xref: /rk3399_rockchip-uboot/drivers/mmc/arm_pl180_mmci.c (revision 07b0b9c00cc8f8e981df35ac4720057469a8d3c8)
123b93e1dSMatt Waddel /*
223b93e1dSMatt Waddel  * ARM PrimeCell MultiMedia Card Interface - PL180
323b93e1dSMatt Waddel  *
423b93e1dSMatt Waddel  * Copyright (C) ST-Ericsson SA 2010
523b93e1dSMatt Waddel  *
623b93e1dSMatt Waddel  * Author: Ulf Hansson <ulf.hansson@stericsson.com>
723b93e1dSMatt Waddel  * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
823b93e1dSMatt Waddel  * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
923b93e1dSMatt Waddel  *
101a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
1123b93e1dSMatt Waddel  */
1223b93e1dSMatt Waddel 
1323b93e1dSMatt Waddel /* #define DEBUG */
1423b93e1dSMatt Waddel 
1523b93e1dSMatt Waddel #include <asm/io.h>
1623b93e1dSMatt Waddel #include "common.h"
1723b93e1dSMatt Waddel #include <errno.h>
1823b93e1dSMatt Waddel #include <mmc.h>
1923b93e1dSMatt Waddel #include "arm_pl180_mmci.h"
2023b93e1dSMatt Waddel #include <malloc.h>
2123b93e1dSMatt Waddel 
wait_for_command_end(struct mmc * dev,struct mmc_cmd * cmd)2223b93e1dSMatt Waddel static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
2323b93e1dSMatt Waddel {
2423b93e1dSMatt Waddel 	u32 hoststatus, statusmask;
2510ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
2623b93e1dSMatt Waddel 
2723b93e1dSMatt Waddel 	statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
2823b93e1dSMatt Waddel 	if ((cmd->resp_type & MMC_RSP_PRESENT))
2923b93e1dSMatt Waddel 		statusmask |= SDI_STA_CMDREND;
3023b93e1dSMatt Waddel 	else
3123b93e1dSMatt Waddel 		statusmask |= SDI_STA_CMDSENT;
3223b93e1dSMatt Waddel 
3323b93e1dSMatt Waddel 	do
3423b93e1dSMatt Waddel 		hoststatus = readl(&host->base->status) & statusmask;
3523b93e1dSMatt Waddel 	while (!hoststatus);
3623b93e1dSMatt Waddel 
3723b93e1dSMatt Waddel 	writel(statusmask, &host->base->status_clear);
3823b93e1dSMatt Waddel 	if (hoststatus & SDI_STA_CTIMEOUT) {
3910ed93dcSJohn Rigby 		debug("CMD%d time out\n", cmd->cmdidx);
40915ffa52SJaehoon Chung 		return -ETIMEDOUT;
4123b93e1dSMatt Waddel 	} else if ((hoststatus & SDI_STA_CCRCFAIL) &&
4295b01c47SAndy Fleming 		   (cmd->resp_type & MMC_RSP_CRC)) {
4323b93e1dSMatt Waddel 		printf("CMD%d CRC error\n", cmd->cmdidx);
4423b93e1dSMatt Waddel 		return -EILSEQ;
4523b93e1dSMatt Waddel 	}
4623b93e1dSMatt Waddel 
4723b93e1dSMatt Waddel 	if (cmd->resp_type & MMC_RSP_PRESENT) {
4823b93e1dSMatt Waddel 		cmd->response[0] = readl(&host->base->response0);
4923b93e1dSMatt Waddel 		cmd->response[1] = readl(&host->base->response1);
5023b93e1dSMatt Waddel 		cmd->response[2] = readl(&host->base->response2);
5123b93e1dSMatt Waddel 		cmd->response[3] = readl(&host->base->response3);
5223b93e1dSMatt Waddel 		debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, "
5323b93e1dSMatt Waddel 			"response[2]:0x%08X, response[3]:0x%08X\n",
5423b93e1dSMatt Waddel 			cmd->cmdidx, cmd->response[0], cmd->response[1],
5523b93e1dSMatt Waddel 			cmd->response[2], cmd->response[3]);
5623b93e1dSMatt Waddel 	}
5723b93e1dSMatt Waddel 
5823b93e1dSMatt Waddel 	return 0;
5923b93e1dSMatt Waddel }
6023b93e1dSMatt Waddel 
6123b93e1dSMatt Waddel /* send command to the mmc card and wait for results */
do_command(struct mmc * dev,struct mmc_cmd * cmd)6223b93e1dSMatt Waddel static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
6323b93e1dSMatt Waddel {
6423b93e1dSMatt Waddel 	int result;
6523b93e1dSMatt Waddel 	u32 sdi_cmd = 0;
6610ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
6723b93e1dSMatt Waddel 
6823b93e1dSMatt Waddel 	sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
6923b93e1dSMatt Waddel 
7023b93e1dSMatt Waddel 	if (cmd->resp_type) {
7123b93e1dSMatt Waddel 		sdi_cmd |= SDI_CMD_WAITRESP;
7223b93e1dSMatt Waddel 		if (cmd->resp_type & MMC_RSP_136)
7323b93e1dSMatt Waddel 			sdi_cmd |= SDI_CMD_LONGRESP;
7423b93e1dSMatt Waddel 	}
7523b93e1dSMatt Waddel 
7623b93e1dSMatt Waddel 	writel((u32)cmd->cmdarg, &host->base->argument);
7723b93e1dSMatt Waddel 	udelay(COMMAND_REG_DELAY);
7823b93e1dSMatt Waddel 	writel(sdi_cmd, &host->base->command);
7923b93e1dSMatt Waddel 	result = wait_for_command_end(dev, cmd);
8023b93e1dSMatt Waddel 
8123b93e1dSMatt Waddel 	/* After CMD2 set RCA to a none zero value. */
8223b93e1dSMatt Waddel 	if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID))
8323b93e1dSMatt Waddel 		dev->rca = 10;
8423b93e1dSMatt Waddel 
8523b93e1dSMatt Waddel 	/* After CMD3 open drain is switched off and push pull is used. */
8623b93e1dSMatt Waddel 	if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) {
8723b93e1dSMatt Waddel 		u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD;
8823b93e1dSMatt Waddel 		writel(sdi_pwr, &host->base->power);
8923b93e1dSMatt Waddel 	}
9023b93e1dSMatt Waddel 
9123b93e1dSMatt Waddel 	return result;
9223b93e1dSMatt Waddel }
9323b93e1dSMatt Waddel 
read_bytes(struct mmc * dev,u32 * dest,u32 blkcount,u32 blksize)9423b93e1dSMatt Waddel static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
9523b93e1dSMatt Waddel {
9623b93e1dSMatt Waddel 	u32 *tempbuff = dest;
9723b93e1dSMatt Waddel 	u64 xfercount = blkcount * blksize;
9810ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
9923b93e1dSMatt Waddel 	u32 status, status_err;
10023b93e1dSMatt Waddel 
10123b93e1dSMatt Waddel 	debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
10223b93e1dSMatt Waddel 
10323b93e1dSMatt Waddel 	status = readl(&host->base->status);
10423b93e1dSMatt Waddel 	status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
10523b93e1dSMatt Waddel 			       SDI_STA_RXOVERR);
10623b93e1dSMatt Waddel 	while ((!status_err) && (xfercount >= sizeof(u32))) {
10723b93e1dSMatt Waddel 		if (status & SDI_STA_RXDAVL) {
10823b93e1dSMatt Waddel 			*(tempbuff) = readl(&host->base->fifo);
10923b93e1dSMatt Waddel 			tempbuff++;
11023b93e1dSMatt Waddel 			xfercount -= sizeof(u32);
11123b93e1dSMatt Waddel 		}
11223b93e1dSMatt Waddel 		status = readl(&host->base->status);
11323b93e1dSMatt Waddel 		status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
11423b93e1dSMatt Waddel 				       SDI_STA_RXOVERR);
11523b93e1dSMatt Waddel 	}
11623b93e1dSMatt Waddel 
11723b93e1dSMatt Waddel 	status_err = status &
11823b93e1dSMatt Waddel 		(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
11923b93e1dSMatt Waddel 		 SDI_STA_RXOVERR);
12023b93e1dSMatt Waddel 	while (!status_err) {
12123b93e1dSMatt Waddel 		status = readl(&host->base->status);
12223b93e1dSMatt Waddel 		status_err = status &
12323b93e1dSMatt Waddel 			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
12423b93e1dSMatt Waddel 			 SDI_STA_RXOVERR);
12523b93e1dSMatt Waddel 	}
12623b93e1dSMatt Waddel 
12723b93e1dSMatt Waddel 	if (status & SDI_STA_DTIMEOUT) {
12823b93e1dSMatt Waddel 		printf("Read data timed out, xfercount: %llu, status: 0x%08X\n",
12923b93e1dSMatt Waddel 			xfercount, status);
13023b93e1dSMatt Waddel 		return -ETIMEDOUT;
13123b93e1dSMatt Waddel 	} else if (status & SDI_STA_DCRCFAIL) {
13223b93e1dSMatt Waddel 		printf("Read data bytes CRC error: 0x%x\n", status);
13323b93e1dSMatt Waddel 		return -EILSEQ;
13423b93e1dSMatt Waddel 	} else if (status & SDI_STA_RXOVERR) {
13523b93e1dSMatt Waddel 		printf("Read data RX overflow error\n");
13623b93e1dSMatt Waddel 		return -EIO;
13723b93e1dSMatt Waddel 	}
13823b93e1dSMatt Waddel 
13923b93e1dSMatt Waddel 	writel(SDI_ICR_MASK, &host->base->status_clear);
14023b93e1dSMatt Waddel 
14123b93e1dSMatt Waddel 	if (xfercount) {
14223b93e1dSMatt Waddel 		printf("Read data error, xfercount: %llu\n", xfercount);
14323b93e1dSMatt Waddel 		return -ENOBUFS;
14423b93e1dSMatt Waddel 	}
14523b93e1dSMatt Waddel 
14623b93e1dSMatt Waddel 	return 0;
14723b93e1dSMatt Waddel }
14823b93e1dSMatt Waddel 
write_bytes(struct mmc * dev,u32 * src,u32 blkcount,u32 blksize)14923b93e1dSMatt Waddel static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
15023b93e1dSMatt Waddel {
15123b93e1dSMatt Waddel 	u32 *tempbuff = src;
15223b93e1dSMatt Waddel 	int i;
15323b93e1dSMatt Waddel 	u64 xfercount = blkcount * blksize;
15410ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
15523b93e1dSMatt Waddel 	u32 status, status_err;
15623b93e1dSMatt Waddel 
15723b93e1dSMatt Waddel 	debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
15823b93e1dSMatt Waddel 
15923b93e1dSMatt Waddel 	status = readl(&host->base->status);
16023b93e1dSMatt Waddel 	status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
16123b93e1dSMatt Waddel 	while (!status_err && xfercount) {
16223b93e1dSMatt Waddel 		if (status & SDI_STA_TXFIFOBW) {
16323b93e1dSMatt Waddel 			if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
16423b93e1dSMatt Waddel 				for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
16523b93e1dSMatt Waddel 					writel(*(tempbuff + i),
16623b93e1dSMatt Waddel 						&host->base->fifo);
16723b93e1dSMatt Waddel 				tempbuff += SDI_FIFO_BURST_SIZE;
16823b93e1dSMatt Waddel 				xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
16923b93e1dSMatt Waddel 			} else {
17023b93e1dSMatt Waddel 				while (xfercount >= sizeof(u32)) {
17123b93e1dSMatt Waddel 					writel(*(tempbuff), &host->base->fifo);
17223b93e1dSMatt Waddel 					tempbuff++;
17323b93e1dSMatt Waddel 					xfercount -= sizeof(u32);
17423b93e1dSMatt Waddel 				}
17523b93e1dSMatt Waddel 			}
17623b93e1dSMatt Waddel 		}
17723b93e1dSMatt Waddel 		status = readl(&host->base->status);
17823b93e1dSMatt Waddel 		status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
17923b93e1dSMatt Waddel 	}
18023b93e1dSMatt Waddel 
18123b93e1dSMatt Waddel 	status_err = status &
18223b93e1dSMatt Waddel 		(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
18323b93e1dSMatt Waddel 	while (!status_err) {
18423b93e1dSMatt Waddel 		status = readl(&host->base->status);
18523b93e1dSMatt Waddel 		status_err = status &
18623b93e1dSMatt Waddel 			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
18723b93e1dSMatt Waddel 	}
18823b93e1dSMatt Waddel 
18923b93e1dSMatt Waddel 	if (status & SDI_STA_DTIMEOUT) {
19023b93e1dSMatt Waddel 		printf("Write data timed out, xfercount:%llu,status:0x%08X\n",
19123b93e1dSMatt Waddel 		       xfercount, status);
19223b93e1dSMatt Waddel 		return -ETIMEDOUT;
19323b93e1dSMatt Waddel 	} else if (status & SDI_STA_DCRCFAIL) {
19423b93e1dSMatt Waddel 		printf("Write data CRC error\n");
19523b93e1dSMatt Waddel 		return -EILSEQ;
19623b93e1dSMatt Waddel 	}
19723b93e1dSMatt Waddel 
19823b93e1dSMatt Waddel 	writel(SDI_ICR_MASK, &host->base->status_clear);
19923b93e1dSMatt Waddel 
20023b93e1dSMatt Waddel 	if (xfercount) {
20123b93e1dSMatt Waddel 		printf("Write data error, xfercount:%llu", xfercount);
20223b93e1dSMatt Waddel 		return -ENOBUFS;
20323b93e1dSMatt Waddel 	}
20423b93e1dSMatt Waddel 
20523b93e1dSMatt Waddel 	return 0;
20623b93e1dSMatt Waddel }
20723b93e1dSMatt Waddel 
do_data_transfer(struct mmc * dev,struct mmc_cmd * cmd,struct mmc_data * data)20823b93e1dSMatt Waddel static int do_data_transfer(struct mmc *dev,
20923b93e1dSMatt Waddel 			    struct mmc_cmd *cmd,
21023b93e1dSMatt Waddel 			    struct mmc_data *data)
21123b93e1dSMatt Waddel {
21223b93e1dSMatt Waddel 	int error = -ETIMEDOUT;
21310ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
21423b93e1dSMatt Waddel 	u32 blksz = 0;
21523b93e1dSMatt Waddel 	u32 data_ctrl = 0;
21623b93e1dSMatt Waddel 	u32 data_len = (u32) (data->blocks * data->blocksize);
21723b93e1dSMatt Waddel 
21810ed93dcSJohn Rigby 	if (!host->version2) {
21923b93e1dSMatt Waddel 		blksz = (ffs(data->blocksize) - 1);
22023b93e1dSMatt Waddel 		data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
22110ed93dcSJohn Rigby 	} else {
22210ed93dcSJohn Rigby 		blksz = data->blocksize;
22310ed93dcSJohn Rigby 		data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT);
22410ed93dcSJohn Rigby 	}
22510ed93dcSJohn Rigby 	data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
22623b93e1dSMatt Waddel 
22723b93e1dSMatt Waddel 	writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
22823b93e1dSMatt Waddel 	writel(data_len, &host->base->datalength);
22923b93e1dSMatt Waddel 	udelay(DATA_REG_DELAY);
23023b93e1dSMatt Waddel 
23123b93e1dSMatt Waddel 	if (data->flags & MMC_DATA_READ) {
23223b93e1dSMatt Waddel 		data_ctrl |= SDI_DCTRL_DTDIR_IN;
23323b93e1dSMatt Waddel 		writel(data_ctrl, &host->base->datactrl);
23423b93e1dSMatt Waddel 
23523b93e1dSMatt Waddel 		error = do_command(dev, cmd);
23623b93e1dSMatt Waddel 		if (error)
23723b93e1dSMatt Waddel 			return error;
23823b93e1dSMatt Waddel 
23923b93e1dSMatt Waddel 		error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks,
24023b93e1dSMatt Waddel 				   (u32)data->blocksize);
24123b93e1dSMatt Waddel 	} else if (data->flags & MMC_DATA_WRITE) {
24223b93e1dSMatt Waddel 		error = do_command(dev, cmd);
24323b93e1dSMatt Waddel 		if (error)
24423b93e1dSMatt Waddel 			return error;
24523b93e1dSMatt Waddel 
24623b93e1dSMatt Waddel 		writel(data_ctrl, &host->base->datactrl);
24723b93e1dSMatt Waddel 		error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
24823b93e1dSMatt Waddel 							(u32)data->blocksize);
24923b93e1dSMatt Waddel 	}
25023b93e1dSMatt Waddel 
25123b93e1dSMatt Waddel 	return error;
25223b93e1dSMatt Waddel }
25323b93e1dSMatt Waddel 
host_request(struct mmc * dev,struct mmc_cmd * cmd,struct mmc_data * data)25423b93e1dSMatt Waddel static int host_request(struct mmc *dev,
25523b93e1dSMatt Waddel 			struct mmc_cmd *cmd,
25623b93e1dSMatt Waddel 			struct mmc_data *data)
25723b93e1dSMatt Waddel {
25823b93e1dSMatt Waddel 	int result;
25923b93e1dSMatt Waddel 
26023b93e1dSMatt Waddel 	if (data)
26123b93e1dSMatt Waddel 		result = do_data_transfer(dev, cmd, data);
26223b93e1dSMatt Waddel 	else
26323b93e1dSMatt Waddel 		result = do_command(dev, cmd);
26423b93e1dSMatt Waddel 
26523b93e1dSMatt Waddel 	return result;
26623b93e1dSMatt Waddel }
26723b93e1dSMatt Waddel 
26823b93e1dSMatt Waddel /* MMC uses open drain drivers in the enumeration phase */
mmc_host_reset(struct mmc * dev)26923b93e1dSMatt Waddel static int mmc_host_reset(struct mmc *dev)
27023b93e1dSMatt Waddel {
27110ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
27223b93e1dSMatt Waddel 
27310ed93dcSJohn Rigby 	writel(host->pwr_init, &host->base->power);
27423b93e1dSMatt Waddel 
27523b93e1dSMatt Waddel 	return 0;
27623b93e1dSMatt Waddel }
27723b93e1dSMatt Waddel 
host_set_ios(struct mmc * dev)278*07b0b9c0SJaehoon Chung static int  host_set_ios(struct mmc *dev)
27923b93e1dSMatt Waddel {
28010ed93dcSJohn Rigby 	struct pl180_mmc_host *host = dev->priv;
28123b93e1dSMatt Waddel 	u32 sdi_clkcr;
28223b93e1dSMatt Waddel 
28323b93e1dSMatt Waddel 	sdi_clkcr = readl(&host->base->clock);
28423b93e1dSMatt Waddel 
28523b93e1dSMatt Waddel 	/* Ramp up the clock rate */
28623b93e1dSMatt Waddel 	if (dev->clock) {
28723b93e1dSMatt Waddel 		u32 clkdiv = 0;
28810ed93dcSJohn Rigby 		u32 tmp_clock;
28923b93e1dSMatt Waddel 
29093bfd616SPantelis Antoniou 		if (dev->clock >= dev->cfg->f_max) {
29110ed93dcSJohn Rigby 			clkdiv = 0;
29293bfd616SPantelis Antoniou 			dev->clock = dev->cfg->f_max;
29310ed93dcSJohn Rigby 		} else {
29410ed93dcSJohn Rigby 			clkdiv = (host->clock_in / dev->clock) - 2;
29510ed93dcSJohn Rigby 		}
29623b93e1dSMatt Waddel 
29710ed93dcSJohn Rigby 		tmp_clock = host->clock_in / (clkdiv + 2);
29810ed93dcSJohn Rigby 		while (tmp_clock > dev->clock) {
29910ed93dcSJohn Rigby 			clkdiv++;
30010ed93dcSJohn Rigby 			tmp_clock = host->clock_in / (clkdiv + 2);
30110ed93dcSJohn Rigby 		}
30223b93e1dSMatt Waddel 
30323b93e1dSMatt Waddel 		if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
30423b93e1dSMatt Waddel 			clkdiv = SDI_CLKCR_CLKDIV_MASK;
30523b93e1dSMatt Waddel 
30610ed93dcSJohn Rigby 		tmp_clock = host->clock_in / (clkdiv + 2);
30710ed93dcSJohn Rigby 		dev->clock = tmp_clock;
30823b93e1dSMatt Waddel 		sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
30923b93e1dSMatt Waddel 		sdi_clkcr |= clkdiv;
31023b93e1dSMatt Waddel 	}
31123b93e1dSMatt Waddel 
31223b93e1dSMatt Waddel 	/* Set the bus width */
31323b93e1dSMatt Waddel 	if (dev->bus_width) {
31423b93e1dSMatt Waddel 		u32 buswidth = 0;
31523b93e1dSMatt Waddel 
31623b93e1dSMatt Waddel 		switch (dev->bus_width) {
31723b93e1dSMatt Waddel 		case 1:
31823b93e1dSMatt Waddel 			buswidth |= SDI_CLKCR_WIDBUS_1;
31923b93e1dSMatt Waddel 			break;
32023b93e1dSMatt Waddel 		case 4:
32123b93e1dSMatt Waddel 			buswidth |= SDI_CLKCR_WIDBUS_4;
32223b93e1dSMatt Waddel 			break;
32310ed93dcSJohn Rigby 		case 8:
32410ed93dcSJohn Rigby 			buswidth |= SDI_CLKCR_WIDBUS_8;
32510ed93dcSJohn Rigby 			break;
32623b93e1dSMatt Waddel 		default:
32710ed93dcSJohn Rigby 			printf("Invalid bus width: %d\n", dev->bus_width);
32823b93e1dSMatt Waddel 			break;
32923b93e1dSMatt Waddel 		}
33023b93e1dSMatt Waddel 		sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
33123b93e1dSMatt Waddel 		sdi_clkcr |= buswidth;
33223b93e1dSMatt Waddel 	}
33323b93e1dSMatt Waddel 
33423b93e1dSMatt Waddel 	writel(sdi_clkcr, &host->base->clock);
33523b93e1dSMatt Waddel 	udelay(CLK_CHANGE_DELAY);
336*07b0b9c0SJaehoon Chung 
337*07b0b9c0SJaehoon Chung 	return 0;
33823b93e1dSMatt Waddel }
33923b93e1dSMatt Waddel 
340ab769f22SPantelis Antoniou static const struct mmc_ops arm_pl180_mmci_ops = {
341ab769f22SPantelis Antoniou 	.send_cmd = host_request,
342ab769f22SPantelis Antoniou 	.set_ios = host_set_ios,
343ab769f22SPantelis Antoniou 	.init = mmc_host_reset,
344ab769f22SPantelis Antoniou };
345ab769f22SPantelis Antoniou 
34623b93e1dSMatt Waddel /*
34723b93e1dSMatt Waddel  * mmc_host_init - initialize the mmc controller.
34823b93e1dSMatt Waddel  * Set initial clock and power for mmc slot.
34923b93e1dSMatt Waddel  * Initialize mmc struct and register with mmc framework.
35023b93e1dSMatt Waddel  */
arm_pl180_mmci_init(struct pl180_mmc_host * host)35110ed93dcSJohn Rigby int arm_pl180_mmci_init(struct pl180_mmc_host *host)
35223b93e1dSMatt Waddel {
35393bfd616SPantelis Antoniou 	struct mmc *mmc;
35423b93e1dSMatt Waddel 	u32 sdi_u32;
35523b93e1dSMatt Waddel 
35610ed93dcSJohn Rigby 	writel(host->pwr_init, &host->base->power);
35710ed93dcSJohn Rigby 	writel(host->clkdiv_init, &host->base->clock);
35823b93e1dSMatt Waddel 	udelay(CLK_CHANGE_DELAY);
35923b93e1dSMatt Waddel 
36023b93e1dSMatt Waddel 	/* Disable mmc interrupts */
36123b93e1dSMatt Waddel 	sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
36223b93e1dSMatt Waddel 	writel(sdi_u32, &host->base->mask0);
36393bfd616SPantelis Antoniou 
36493bfd616SPantelis Antoniou 	host->cfg.name = host->name;
36593bfd616SPantelis Antoniou 	host->cfg.ops = &arm_pl180_mmci_ops;
36693bfd616SPantelis Antoniou 	/* TODO remove the duplicates */
36793bfd616SPantelis Antoniou 	host->cfg.host_caps = host->caps;
36893bfd616SPantelis Antoniou 	host->cfg.voltages = host->voltages;
36993bfd616SPantelis Antoniou 	host->cfg.f_min = host->clock_min;
37093bfd616SPantelis Antoniou 	host->cfg.f_max = host->clock_max;
37193bfd616SPantelis Antoniou 	if (host->b_max != 0)
37293bfd616SPantelis Antoniou 		host->cfg.b_max = host->b_max;
37393bfd616SPantelis Antoniou 	else
37493bfd616SPantelis Antoniou 		host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
37593bfd616SPantelis Antoniou 
37693bfd616SPantelis Antoniou 	mmc = mmc_create(&host->cfg, host);
37793bfd616SPantelis Antoniou 	if (mmc == NULL)
37893bfd616SPantelis Antoniou 		return -1;
37993bfd616SPantelis Antoniou 
380bcce53d0SSimon Glass 	debug("registered mmc interface number is:%d\n", mmc->block_dev.devnum);
38123b93e1dSMatt Waddel 
38223b93e1dSMatt Waddel 	return 0;
38323b93e1dSMatt Waddel }
384