xref: /OK3568_Linux_fs/kernel/drivers/mmc/host/rk_sdmmc_ops.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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