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