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 <linux/pm.h>
26 #include <linux/pm_runtime.h>
27 #include "../core/block.h"
28 #include "../core/card.h"
29 #include "../core/core.h"
30 #include "../core/mmc_ops.h"
31 #include "rk_sdmmc_ops.h"
32
33 #define BLKSZ 512
34
35 enum emmc_area_type {
36 MMC_DATA_AREA_MAIN,
37 MMC_DATA_AREA_BOOT1,
38 MMC_DATA_AREA_BOOT2,
39 MMC_DATA_AREA_RPMB,
40 };
41
rk_emmc_set_areatype(enum emmc_area_type areatype)42 static int rk_emmc_set_areatype(enum emmc_area_type areatype)
43 {
44 int err;
45 u8 part_config;
46
47 part_config = this_card->ext_csd.part_config;
48 part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
49 part_config |= (u8)areatype;
50 err = mmc_switch(this_card, EXT_CSD_CMD_SET_NORMAL,
51 EXT_CSD_PART_CONFIG, part_config,
52 this_card->ext_csd.part_time);
53
54 return err;
55 }
56
57 /*
58 * Fill in the mmc_request structure given a set of transfer parameters.
59 */
rk_emmc_prepare_mrq(struct mmc_request * mrq,struct scatterlist * sg,unsigned sg_len,unsigned dev_addr,unsigned blocks,unsigned blksz,int write)60 static void rk_emmc_prepare_mrq(struct mmc_request *mrq, struct scatterlist *sg,
61 unsigned sg_len, unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
62 {
63 BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
64
65 if (blocks > 1) {
66 mrq->cmd->opcode = write ?
67 MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
68 } else {
69 mrq->cmd->opcode = write ?
70 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
71 }
72
73 mrq->cmd->arg = dev_addr;
74 if (!mmc_card_blockaddr(this_card))
75 mrq->cmd->arg <<= 9;
76
77 mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
78
79 if (blocks == 1)
80 mrq->stop = NULL;
81 else {
82 mrq->stop->opcode = MMC_STOP_TRANSMISSION;
83 mrq->stop->arg = 0;
84 mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
85 }
86
87 mrq->data->blksz = blksz;
88 mrq->data->blocks = blocks;
89 mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
90 mrq->data->sg = sg;
91 mrq->data->sg_len = sg_len;
92 mmc_set_data_timeout(mrq->data, this_card);
93 }
94
rk_emmc_busy(struct mmc_command * cmd)95 static int rk_emmc_busy(struct mmc_command *cmd)
96 {
97 return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
98 (R1_CURRENT_STATE(cmd->resp[0]) == 7);
99 }
100
101 /*
102 * Wait for the card to finish the busy state
103 */
rk_emmc_wait_busy(void)104 static int rk_emmc_wait_busy(void)
105 {
106 int ret, busy;
107 struct mmc_command cmd = {0};
108
109 busy = 0;
110 do {
111 memset(&cmd, 0, sizeof(struct mmc_command));
112
113 cmd.opcode = MMC_SEND_STATUS;
114 cmd.arg = this_card->rca << 16;
115 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
116
117 ret = mmc_wait_for_cmd(this_card->host, &cmd, 0);
118 if (ret)
119 break;
120
121 if (!busy && rk_emmc_busy(&cmd)) {
122 busy = 1;
123 if (this_card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
124 pr_info("%s: Warning: Host did not "
125 "wait for busy state to end.\n",
126 mmc_hostname(this_card->host));
127 }
128 } while (rk_emmc_busy(&cmd));
129
130 return ret;
131 }
132
133 /*
134 * Transfer a single sector of kernel addressable data
135 */
rk_emmc_transfer(u8 * buffer,unsigned int addr,unsigned int datasz,int write)136 int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int datasz, int write)
137 {
138 int ret = 0;
139 enum emmc_area_type areatype;
140
141 struct mmc_request mrq = {0};
142 struct mmc_command cmd = {0};
143 struct mmc_command stop = {0};
144 struct mmc_data data = {0};
145
146 struct scatterlist sg;
147
148 if(!this_card)
149 return -EIO;
150
151 mrq.cmd = &cmd;
152 mrq.data = &data;
153 mrq.stop = &stop;
154
155 sg_init_one(&sg, buffer, datasz);
156
157 rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, datasz / BLKSZ, BLKSZ, write);
158
159 pm_runtime_get_sync(&this_card->dev);
160 mmc_claim_host(this_card->host);
161
162 if (this_card->ext_csd.cmdq_en) {
163 ret = mmc_cmdq_disable(this_card);
164 if (ret)
165 goto exit;
166 }
167
168 areatype = (enum emmc_area_type)this_card->ext_csd.part_config
169 & EXT_CSD_PART_CONFIG_ACC_MASK;
170 if (areatype != MMC_DATA_AREA_MAIN) {
171 ret = rk_emmc_set_areatype(MMC_DATA_AREA_MAIN);
172 if (ret) {
173 pr_err("rk_emmc_set_areatype error!.\n");
174 goto exit;
175 }
176 }
177
178 mmc_wait_for_req(this_card->host, &mrq);
179
180 if (cmd.error){
181 ret = cmd.error;
182 goto exit;
183 }
184 if (data.error){
185 ret = data.error;
186 goto exit;
187 }
188
189 ret = rk_emmc_wait_busy();
190
191 if (areatype != MMC_DATA_AREA_MAIN) {
192 ret = rk_emmc_set_areatype(areatype);
193 if (ret)
194 pr_err("rk_emmc_set_areatype error!.\n");
195 }
196
197 exit:
198 if (this_card->reenable_cmdq && !this_card->ext_csd.cmdq_en)
199 mmc_cmdq_enable(this_card);
200
201 mmc_release_host(this_card->host);
202 pm_runtime_put(&this_card->dev);
203
204 return ret;
205 }
206 EXPORT_SYMBOL(rk_emmc_transfer);
207
208 MODULE_LICENSE("GPL");
209