1 /*
2 * linux/drivers/mmchost/rkemmc_ops.c
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
8 */
9
10 #include <linux/mmc/core.h>
11 #include <linux/mmc/card.h>
12 #include <linux/mmc/host.h>
13 #include <linux/mmc/mmc.h>
14 #include <linux/slab.h>
15
16 #include <linux/scatterlist.h>
17 #include <linux/swap.h> /* For nr_free_buffer_pages() */
18 #include <linux/list.h>
19
20 #include <linux/debugfs.h>
21 #include <linux/uaccess.h>
22 #include <linux/seq_file.h>
23 #include <linux/mutex.h>
24 #include <linux/miscdevice.h>
25 #include "core/block.h"
26 #include "core/card.h"
27 #include "core/core.h"
28 #include "core/mmc_ops.h"
29 #include "rk_sdmmc_ops.h"
30
31 #define BLKSZ 512
32
33 enum emmc_area_type {
34 MMC_DATA_AREA_MAIN,
35 MMC_DATA_AREA_BOOT1,
36 MMC_DATA_AREA_BOOT2,
37 MMC_DATA_AREA_RPMB,
38 };
39
rk_emmc_set_areatype(enum emmc_area_type areatype)40 static int rk_emmc_set_areatype(enum emmc_area_type areatype)
41 {
42 int err;
43 u8 part_config;
44
45 part_config = this_card->ext_csd.part_config;
46 part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
47 part_config |= (u8)areatype;
48 err = mmc_switch(this_card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, part_config, this_card->ext_csd.part_time);
49
50 return err;
51 }
52
53 /*
54 * Fill in the mmc_request structure given a set of transfer parameters.
55 */
rk_emmc_prepare_mrq(struct mmc_request * mrq,struct scatterlist * sg,unsigned sg_len,unsigned dev_addr,unsigned blocks,unsigned blksz,int write)56 static void rk_emmc_prepare_mrq(struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
57 unsigned blocks, unsigned blksz, int write)
58 {
59 BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
60
61 if (blocks > 1) {
62 mrq->cmd->opcode = write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
63 } else {
64 mrq->cmd->opcode = write ? MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
65 }
66
67 mrq->cmd->arg = dev_addr;
68 if (!mmc_card_blockaddr(this_card)) {
69 mrq->cmd->arg <<= 0x09;
70 }
71
72 mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
73
74 if (blocks == 1) {
75 mrq->stop = NULL;
76 } else {
77 mrq->stop->opcode = MMC_STOP_TRANSMISSION;
78 mrq->stop->arg = 0;
79 mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
80 }
81
82 mrq->data->blksz = blksz;
83 mrq->data->blocks = blocks;
84 mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
85 mrq->data->sg = sg;
86 mrq->data->sg_len = sg_len;
87 mmc_set_data_timeout(mrq->data, this_card);
88 }
89
rk_emmc_busy(struct mmc_command * cmd)90 static int rk_emmc_busy(struct mmc_command *cmd)
91 {
92 return !(cmd->resp[0] & R1_READY_FOR_DATA) || (R1_CURRENT_STATE(cmd->resp[0]) == 0x07);
93 }
94
95 /*
96 * Wait for the card to finish the busy state
97 */
rk_emmc_wait_busy(void)98 static int rk_emmc_wait_busy(void)
99 {
100 int ret, busy;
101 struct mmc_command cmd = {0};
102
103 busy = 0;
104 do {
105 memset(&cmd, 0, sizeof(struct mmc_command));
106
107 cmd.opcode = MMC_SEND_STATUS;
108 cmd.arg = this_card->rca << 0x10;
109 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
110
111 ret = mmc_wait_for_cmd(this_card->host, &cmd, 0);
112 if (ret) {
113 break;
114 }
115
116 if (!busy && rk_emmc_busy(&cmd)) {
117 busy = 1;
118 if (this_card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) {
119 pr_info("%s: Warning: Host did not "
120 "wait for busy state to end.\n",
121 mmc_hostname(this_card->host));
122 }
123 }
124 } while (rk_emmc_busy(&cmd));
125
126 return ret;
127 }
128
129 /*
130 * Transfer a single sector of kernel addressable data
131 */
rk_emmc_transfer(u8 * buffer,unsigned addr,unsigned blksz,int write)132 int rk_emmc_transfer(u8 *buffer, unsigned addr, unsigned blksz, int write)
133 {
134 int ret = 0;
135 enum emmc_area_type areatype;
136
137 struct mmc_request mrq = {0};
138 struct mmc_command cmd = {0};
139 struct mmc_command stop = {0};
140 struct mmc_data data = {0};
141
142 struct scatterlist sg;
143
144 if (!this_card) {
145 return -EIO;
146 }
147
148 mrq.cmd = &cmd;
149 mrq.data = &data;
150 mrq.stop = &stop;
151
152 sg_init_one(&sg, buffer, blksz);
153
154 rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, 1, blksz, write);
155
156 mmc_claim_host(this_card->host);
157
158 areatype = (enum emmc_area_type)this_card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK;
159 if (areatype != MMC_DATA_AREA_MAIN) {
160 ret = rk_emmc_set_areatype(MMC_DATA_AREA_MAIN);
161 if (ret) {
162 pr_err("rk_emmc_set_areatype error!.\n");
163 goto exit;
164 }
165 }
166
167 mmc_wait_for_req(this_card->host, &mrq);
168
169 if (cmd.error) {
170 ret = cmd.error;
171 goto exit;
172 }
173 if (data.error) {
174 ret = data.error;
175 goto exit;
176 }
177
178 ret = rk_emmc_wait_busy();
179
180 if (areatype != MMC_DATA_AREA_MAIN) {
181 ret = rk_emmc_set_areatype(areatype);
182 if (ret) {
183 pr_err("rk_emmc_set_areatype error!.\n");
184 }
185 }
186
187 exit:
188 mmc_release_host(this_card->host);
189 return ret;
190 }
191 EXPORT_SYMBOL(rk_emmc_transfer);
192
193 MODULE_LICENSE("GPL");
194