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