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