123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * bcm2835 sdhost driver.
- *
- * The 2835 has two SD controllers: The Arasan sdhci controller
- * (supported by the iproc driver) and a custom sdhost controller
- * (supported by this driver).
- *
- * The sdhci controller supports both sdcard and sdio. The sdhost
- * controller supports the sdcard only, but has better performance.
- * Also note that the rpi3 has sdio wifi, so driving the sdcard with
- * the sdhost controller allows to use the sdhci controller for wifi
- * support.
- *
- * The configuration is done by devicetree via pin muxing. Both
- * SD controller are available on the same pins (2 pin groups = pin 22
- * to 27 + pin 48 to 53). So it's possible to use both SD controllers
- * at the same time with different pin groups.
- *
- * This code was ported to U-Boot by
- * Alexander Graf <agraf@suse.de>
- * and is based on drivers/mmc/host/bcm2835.c in Linux which is written by
- * Phil Elwell <phil@raspberrypi.org>
- * Copyright (C) 2015-2016 Raspberry Pi (Trading) Ltd.
- * which is based on
- * mmc-bcm2835.c by Gellert Weisz
- * which is, in turn, based on
- * sdhci-bcm2708.c by Broadcom
- * sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
- * sdhci.c and sdhci-pci.c by Pierre Ossman
- */
- #include <clk.h>
- #include <common.h>
- #include <dm.h>
- #include <mmc.h>
- #include <asm/arch/msg.h>
- #include <asm/arch/mbox.h>
- #include <asm/unaligned.h>
- #include <linux/compat.h>
- #include <linux/io.h>
- #include <linux/iopoll.h>
- #include <linux/sizes.h>
- #include <mach/gpio.h>
- #include <power/regulator.h>
- #define msleep(a) udelay(a * 1000)
- #define SDCMD 0x00 /* Command to SD card - 16 R/W */
- #define SDARG 0x04 /* Argument to SD card - 32 R/W */
- #define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */
- #define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */
- #define SDRSP0 0x10 /* SD card response (31:0) - 32 R */
- #define SDRSP1 0x14 /* SD card response (63:32) - 32 R */
- #define SDRSP2 0x18 /* SD card response (95:64) - 32 R */
- #define SDRSP3 0x1c /* SD card response (127:96) - 32 R */
- #define SDHSTS 0x20 /* SD host status - 11 R/W */
- #define SDVDD 0x30 /* SD card power control - 1 R/W */
- #define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */
- #define SDHCFG 0x38 /* Host configuration - 2 R/W */
- #define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */
- #define SDDATA 0x40 /* Data to/from SD card - 32 R/W */
- #define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */
- #define SDCMD_NEW_FLAG 0x8000
- #define SDCMD_FAIL_FLAG 0x4000
- #define SDCMD_BUSYWAIT 0x800
- #define SDCMD_NO_RESPONSE 0x400
- #define SDCMD_LONG_RESPONSE 0x200
- #define SDCMD_WRITE_CMD 0x80
- #define SDCMD_READ_CMD 0x40
- #define SDCMD_CMD_MASK 0x3f
- #define SDCDIV_MAX_CDIV 0x7ff
- #define SDHSTS_BUSY_IRPT 0x400
- #define SDHSTS_BLOCK_IRPT 0x200
- #define SDHSTS_SDIO_IRPT 0x100
- #define SDHSTS_REW_TIME_OUT 0x80
- #define SDHSTS_CMD_TIME_OUT 0x40
- #define SDHSTS_CRC16_ERROR 0x20
- #define SDHSTS_CRC7_ERROR 0x10
- #define SDHSTS_FIFO_ERROR 0x08
- #define SDHSTS_DATA_FLAG 0x01
- #define SDHSTS_CLEAR_MASK (SDHSTS_BUSY_IRPT | \
- SDHSTS_BLOCK_IRPT | \
- SDHSTS_SDIO_IRPT | \
- SDHSTS_REW_TIME_OUT | \
- SDHSTS_CMD_TIME_OUT | \
- SDHSTS_CRC16_ERROR | \
- SDHSTS_CRC7_ERROR | \
- SDHSTS_FIFO_ERROR)
- #define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR | \
- SDHSTS_CRC16_ERROR | \
- SDHSTS_REW_TIME_OUT | \
- SDHSTS_FIFO_ERROR)
- #define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT | \
- SDHSTS_TRANSFER_ERROR_MASK)
- #define SDHCFG_BUSY_IRPT_EN BIT(10)
- #define SDHCFG_BLOCK_IRPT_EN BIT(8)
- #define SDHCFG_SDIO_IRPT_EN BIT(5)
- #define SDHCFG_DATA_IRPT_EN BIT(4)
- #define SDHCFG_SLOW_CARD BIT(3)
- #define SDHCFG_WIDE_EXT_BUS BIT(2)
- #define SDHCFG_WIDE_INT_BUS BIT(1)
- #define SDHCFG_REL_CMD_LINE BIT(0)
- #define SDVDD_POWER_OFF 0
- #define SDVDD_POWER_ON 1
- #define SDEDM_FORCE_DATA_MODE BIT(19)
- #define SDEDM_CLOCK_PULSE BIT(20)
- #define SDEDM_BYPASS BIT(21)
- #define SDEDM_FIFO_FILL_SHIFT 4
- #define SDEDM_FIFO_FILL_MASK 0x1f
- static u32 edm_fifo_fill(u32 edm)
- {
- return (edm >> SDEDM_FIFO_FILL_SHIFT) & SDEDM_FIFO_FILL_MASK;
- }
- #define SDEDM_WRITE_THRESHOLD_SHIFT 9
- #define SDEDM_READ_THRESHOLD_SHIFT 14
- #define SDEDM_THRESHOLD_MASK 0x1f
- #define SDEDM_FSM_MASK 0xf
- #define SDEDM_FSM_IDENTMODE 0x0
- #define SDEDM_FSM_DATAMODE 0x1
- #define SDEDM_FSM_READDATA 0x2
- #define SDEDM_FSM_WRITEDATA 0x3
- #define SDEDM_FSM_READWAIT 0x4
- #define SDEDM_FSM_READCRC 0x5
- #define SDEDM_FSM_WRITECRC 0x6
- #define SDEDM_FSM_WRITEWAIT1 0x7
- #define SDEDM_FSM_POWERDOWN 0x8
- #define SDEDM_FSM_POWERUP 0x9
- #define SDEDM_FSM_WRITESTART1 0xa
- #define SDEDM_FSM_WRITESTART2 0xb
- #define SDEDM_FSM_GENPULSES 0xc
- #define SDEDM_FSM_WRITEWAIT2 0xd
- #define SDEDM_FSM_STARTPOWDOWN 0xf
- #define SDDATA_FIFO_WORDS 16
- #define FIFO_READ_THRESHOLD 4
- #define FIFO_WRITE_THRESHOLD 4
- #define SDDATA_FIFO_PIO_BURST 8
- #define SDHST_TIMEOUT_MAX_USEC 100000
- struct bcm2835_plat {
- struct mmc_config cfg;
- struct mmc mmc;
- };
- struct bcm2835_host {
- void __iomem *ioaddr;
- u32 phys_addr;
- int clock; /* Current clock speed */
- unsigned int max_clk; /* Max possible freq */
- unsigned int blocks; /* remaining PIO blocks */
- u32 ns_per_fifo_word;
- /* cached registers */
- u32 hcfg;
- u32 cdiv;
- struct mmc_cmd *cmd; /* Current command */
- struct mmc_data *data; /* Current data request */
- bool use_busy:1; /* Wait for busy interrupt */
- struct udevice *dev;
- struct mmc *mmc;
- struct bcm2835_plat *plat;
- };
- static void bcm2835_dumpregs(struct bcm2835_host *host)
- {
- dev_dbg(dev, "=========== REGISTER DUMP ===========\n");
- dev_dbg(dev, "SDCMD 0x%08x\n", readl(host->ioaddr + SDCMD));
- dev_dbg(dev, "SDARG 0x%08x\n", readl(host->ioaddr + SDARG));
- dev_dbg(dev, "SDTOUT 0x%08x\n", readl(host->ioaddr + SDTOUT));
- dev_dbg(dev, "SDCDIV 0x%08x\n", readl(host->ioaddr + SDCDIV));
- dev_dbg(dev, "SDRSP0 0x%08x\n", readl(host->ioaddr + SDRSP0));
- dev_dbg(dev, "SDRSP1 0x%08x\n", readl(host->ioaddr + SDRSP1));
- dev_dbg(dev, "SDRSP2 0x%08x\n", readl(host->ioaddr + SDRSP2));
- dev_dbg(dev, "SDRSP3 0x%08x\n", readl(host->ioaddr + SDRSP3));
- dev_dbg(dev, "SDHSTS 0x%08x\n", readl(host->ioaddr + SDHSTS));
- dev_dbg(dev, "SDVDD 0x%08x\n", readl(host->ioaddr + SDVDD));
- dev_dbg(dev, "SDEDM 0x%08x\n", readl(host->ioaddr + SDEDM));
- dev_dbg(dev, "SDHCFG 0x%08x\n", readl(host->ioaddr + SDHCFG));
- dev_dbg(dev, "SDHBCT 0x%08x\n", readl(host->ioaddr + SDHBCT));
- dev_dbg(dev, "SDHBLC 0x%08x\n", readl(host->ioaddr + SDHBLC));
- dev_dbg(dev, "===========================================\n");
- }
- static void bcm2835_reset_internal(struct bcm2835_host *host)
- {
- u32 temp;
- writel(SDVDD_POWER_OFF, host->ioaddr + SDVDD);
- writel(0, host->ioaddr + SDCMD);
- writel(0, host->ioaddr + SDARG);
- /* Set timeout to a big enough value so we don't hit it */
- writel(0xf00000, host->ioaddr + SDTOUT);
- writel(0, host->ioaddr + SDCDIV);
- /* Clear status register */
- writel(SDHSTS_CLEAR_MASK, host->ioaddr + SDHSTS);
- writel(0, host->ioaddr + SDHCFG);
- writel(0, host->ioaddr + SDHBCT);
- writel(0, host->ioaddr + SDHBLC);
- /* Limit fifo usage due to silicon bug */
- temp = readl(host->ioaddr + SDEDM);
- temp &= ~((SDEDM_THRESHOLD_MASK << SDEDM_READ_THRESHOLD_SHIFT) |
- (SDEDM_THRESHOLD_MASK << SDEDM_WRITE_THRESHOLD_SHIFT));
- temp |= (FIFO_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
- (FIFO_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
- writel(temp, host->ioaddr + SDEDM);
- /* Wait for FIFO threshold to populate */
- msleep(20);
- writel(SDVDD_POWER_ON, host->ioaddr + SDVDD);
- /* Wait for all components to go through power on cycle */
- msleep(20);
- host->clock = 0;
- writel(host->hcfg, host->ioaddr + SDHCFG);
- writel(host->cdiv, host->ioaddr + SDCDIV);
- }
- static int bcm2835_wait_transfer_complete(struct bcm2835_host *host)
- {
- int timediff = 0;
- while (1) {
- u32 edm, fsm;
- edm = readl(host->ioaddr + SDEDM);
- fsm = edm & SDEDM_FSM_MASK;
- if ((fsm == SDEDM_FSM_IDENTMODE) ||
- (fsm == SDEDM_FSM_DATAMODE))
- break;
- if ((fsm == SDEDM_FSM_READWAIT) ||
- (fsm == SDEDM_FSM_WRITESTART1) ||
- (fsm == SDEDM_FSM_READDATA)) {
- writel(edm | SDEDM_FORCE_DATA_MODE,
- host->ioaddr + SDEDM);
- break;
- }
- /* Error out after 100000 register reads (~1s) */
- if (timediff++ == 100000) {
- dev_err(host->dev,
- "wait_transfer_complete - still waiting after %d retries\n",
- timediff);
- bcm2835_dumpregs(host);
- return -ETIMEDOUT;
- }
- }
- return 0;
- }
- static int bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
- {
- struct mmc_data *data = host->data;
- size_t blksize = data->blocksize;
- int copy_words;
- u32 hsts = 0;
- u32 *buf;
- if (blksize % sizeof(u32))
- return -EINVAL;
- buf = is_read ? (u32 *)data->dest : (u32 *)data->src;
- if (is_read)
- data->dest += blksize;
- else
- data->src += blksize;
- copy_words = blksize / sizeof(u32);
- /*
- * Copy all contents from/to the FIFO as far as it reaches,
- * then wait for it to fill/empty again and rewind.
- */
- while (copy_words) {
- int burst_words, words;
- u32 edm;
- burst_words = min(SDDATA_FIFO_PIO_BURST, copy_words);
- edm = readl(host->ioaddr + SDEDM);
- if (is_read)
- words = edm_fifo_fill(edm);
- else
- words = SDDATA_FIFO_WORDS - edm_fifo_fill(edm);
- if (words < burst_words) {
- int fsm_state = (edm & SDEDM_FSM_MASK);
- if ((is_read &&
- (fsm_state != SDEDM_FSM_READDATA &&
- fsm_state != SDEDM_FSM_READWAIT &&
- fsm_state != SDEDM_FSM_READCRC)) ||
- (!is_read &&
- (fsm_state != SDEDM_FSM_WRITEDATA &&
- fsm_state != SDEDM_FSM_WRITEWAIT1 &&
- fsm_state != SDEDM_FSM_WRITEWAIT2 &&
- fsm_state != SDEDM_FSM_WRITECRC &&
- fsm_state != SDEDM_FSM_WRITESTART1 &&
- fsm_state != SDEDM_FSM_WRITESTART2))) {
- hsts = readl(host->ioaddr + SDHSTS);
- printf("fsm %x, hsts %08x\n", fsm_state, hsts);
- if (hsts & SDHSTS_ERROR_MASK)
- break;
- }
- continue;
- } else if (words > copy_words) {
- words = copy_words;
- }
- copy_words -= words;
- /* Copy current chunk to/from the FIFO */
- while (words) {
- if (is_read)
- *(buf++) = readl(host->ioaddr + SDDATA);
- else
- writel(*(buf++), host->ioaddr + SDDATA);
- words--;
- }
- }
- return 0;
- }
- static int bcm2835_transfer_pio(struct bcm2835_host *host)
- {
- u32 sdhsts;
- bool is_read;
- int ret = 0;
- is_read = (host->data->flags & MMC_DATA_READ) != 0;
- ret = bcm2835_transfer_block_pio(host, is_read);
- if (ret)
- return ret;
- sdhsts = readl(host->ioaddr + SDHSTS);
- if (sdhsts & (SDHSTS_CRC16_ERROR |
- SDHSTS_CRC7_ERROR |
- SDHSTS_FIFO_ERROR)) {
- printf("%s transfer error - HSTS %08x\n",
- is_read ? "read" : "write", sdhsts);
- ret = -EILSEQ;
- } else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
- SDHSTS_REW_TIME_OUT))) {
- printf("%s timeout error - HSTS %08x\n",
- is_read ? "read" : "write", sdhsts);
- ret = -ETIMEDOUT;
- }
- return ret;
- }
- static void bcm2835_prepare_data(struct bcm2835_host *host, struct mmc_cmd *cmd,
- struct mmc_data *data)
- {
- WARN_ON(host->data);
- host->data = data;
- if (!data)
- return;
- /* Use PIO */
- host->blocks = data->blocks;
- writel(data->blocksize, host->ioaddr + SDHBCT);
- writel(data->blocks, host->ioaddr + SDHBLC);
- }
- static u32 bcm2835_read_wait_sdcmd(struct bcm2835_host *host)
- {
- u32 value;
- int ret;
- int timeout_us = SDHST_TIMEOUT_MAX_USEC;
- ret = readl_poll_timeout(host->ioaddr + SDCMD, value,
- !(value & SDCMD_NEW_FLAG), timeout_us);
- if (ret == -ETIMEDOUT)
- printf("%s: timeout (%d us)\n", __func__, timeout_us);
- return value;
- }
- static int bcm2835_send_command(struct bcm2835_host *host, struct mmc_cmd *cmd,
- struct mmc_data *data)
- {
- u32 sdcmd, sdhsts;
- WARN_ON(host->cmd);
- if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) {
- printf("unsupported response type!\n");
- return -EINVAL;
- }
- sdcmd = bcm2835_read_wait_sdcmd(host);
- if (sdcmd & SDCMD_NEW_FLAG) {
- printf("previous command never completed.\n");
- bcm2835_dumpregs(host);
- return -EBUSY;
- }
- host->cmd = cmd;
- /* Clear any error flags */
- sdhsts = readl(host->ioaddr + SDHSTS);
- if (sdhsts & SDHSTS_ERROR_MASK)
- writel(sdhsts, host->ioaddr + SDHSTS);
- bcm2835_prepare_data(host, cmd, data);
- writel(cmd->cmdarg, host->ioaddr + SDARG);
- sdcmd = cmd->cmdidx & SDCMD_CMD_MASK;
- host->use_busy = false;
- if (!(cmd->resp_type & MMC_RSP_PRESENT)) {
- sdcmd |= SDCMD_NO_RESPONSE;
- } else {
- if (cmd->resp_type & MMC_RSP_136)
- sdcmd |= SDCMD_LONG_RESPONSE;
- if (cmd->resp_type & MMC_RSP_BUSY) {
- sdcmd |= SDCMD_BUSYWAIT;
- host->use_busy = true;
- }
- }
- if (data) {
- if (data->flags & MMC_DATA_WRITE)
- sdcmd |= SDCMD_WRITE_CMD;
- if (data->flags & MMC_DATA_READ)
- sdcmd |= SDCMD_READ_CMD;
- }
- writel(sdcmd | SDCMD_NEW_FLAG, host->ioaddr + SDCMD);
- return 0;
- }
- static int bcm2835_finish_command(struct bcm2835_host *host)
- {
- struct mmc_cmd *cmd = host->cmd;
- u32 sdcmd;
- int ret = 0;
- sdcmd = bcm2835_read_wait_sdcmd(host);
- /* Check for errors */
- if (sdcmd & SDCMD_NEW_FLAG) {
- printf("command never completed.\n");
- bcm2835_dumpregs(host);
- return -EIO;
- } else if (sdcmd & SDCMD_FAIL_FLAG) {
- u32 sdhsts = readl(host->ioaddr + SDHSTS);
- /* Clear the errors */
- writel(SDHSTS_ERROR_MASK, host->ioaddr + SDHSTS);
- if (!(sdhsts & SDHSTS_CRC7_ERROR) ||
- (host->cmd->cmdidx != MMC_CMD_SEND_OP_COND)) {
- if (sdhsts & SDHSTS_CMD_TIME_OUT) {
- ret = -ETIMEDOUT;
- } else {
- printf("unexpected command %d error\n",
- host->cmd->cmdidx);
- bcm2835_dumpregs(host);
- ret = -EILSEQ;
- }
- return ret;
- }
- }
- if (cmd->resp_type & MMC_RSP_PRESENT) {
- if (cmd->resp_type & MMC_RSP_136) {
- int i;
- for (i = 0; i < 4; i++) {
- cmd->response[3 - i] =
- readl(host->ioaddr + SDRSP0 + i * 4);
- }
- } else {
- cmd->response[0] = readl(host->ioaddr + SDRSP0);
- }
- }
- /* Processed actual command. */
- host->cmd = NULL;
- return ret;
- }
- static int bcm2835_check_cmd_error(struct bcm2835_host *host, u32 intmask)
- {
- int ret = -EINVAL;
- if (!(intmask & SDHSTS_ERROR_MASK))
- return 0;
- if (!host->cmd)
- return -EINVAL;
- printf("sdhost_busy_irq: intmask %08x\n", intmask);
- if (intmask & SDHSTS_CRC7_ERROR) {
- ret = -EILSEQ;
- } else if (intmask & (SDHSTS_CRC16_ERROR |
- SDHSTS_FIFO_ERROR)) {
- ret = -EILSEQ;
- } else if (intmask & (SDHSTS_REW_TIME_OUT | SDHSTS_CMD_TIME_OUT)) {
- ret = -ETIMEDOUT;
- }
- bcm2835_dumpregs(host);
- return ret;
- }
- static int bcm2835_check_data_error(struct bcm2835_host *host, u32 intmask)
- {
- int ret = 0;
- if (!host->data)
- return 0;
- if (intmask & (SDHSTS_CRC16_ERROR | SDHSTS_FIFO_ERROR))
- ret = -EILSEQ;
- if (intmask & SDHSTS_REW_TIME_OUT)
- ret = -ETIMEDOUT;
- if (ret)
- printf("%s:%d %d\n", __func__, __LINE__, ret);
- return ret;
- }
- static int bcm2835_transmit(struct bcm2835_host *host)
- {
- u32 intmask = readl(host->ioaddr + SDHSTS);
- int ret;
- /* Check for errors */
- ret = bcm2835_check_data_error(host, intmask);
- if (ret)
- return ret;
- ret = bcm2835_check_cmd_error(host, intmask);
- if (ret)
- return ret;
- /* Handle wait for busy end */
- if (host->use_busy && (intmask & SDHSTS_BUSY_IRPT)) {
- writel(SDHSTS_BUSY_IRPT, host->ioaddr + SDHSTS);
- host->use_busy = false;
- bcm2835_finish_command(host);
- }
- /* Handle PIO data transfer */
- if (host->data) {
- ret = bcm2835_transfer_pio(host);
- if (ret)
- return ret;
- host->blocks--;
- if (host->blocks == 0) {
- /* Wait for command to complete for real */
- ret = bcm2835_wait_transfer_complete(host);
- if (ret)
- return ret;
- /* Transfer complete */
- host->data = NULL;
- }
- }
- return 0;
- }
- static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
- {
- int div;
- /* The SDCDIV register has 11 bits, and holds (div - 2). But
- * in data mode the max is 50MHz wihout a minimum, and only
- * the bottom 3 bits are used. Since the switch over is
- * automatic (unless we have marked the card as slow...),
- * chosen values have to make sense in both modes. Ident mode
- * must be 100-400KHz, so can range check the requested
- * clock. CMD15 must be used to return to data mode, so this
- * can be monitored.
- *
- * clock 250MHz -> 0->125MHz, 1->83.3MHz, 2->62.5MHz, 3->50.0MHz
- * 4->41.7MHz, 5->35.7MHz, 6->31.3MHz, 7->27.8MHz
- *
- * 623->400KHz/27.8MHz
- * reset value (507)->491159/50MHz
- *
- * BUT, the 3-bit clock divisor in data mode is too small if
- * the core clock is higher than 250MHz, so instead use the
- * SLOW_CARD configuration bit to force the use of the ident
- * clock divisor at all times.
- */
- if (clock < 100000) {
- /* Can't stop the clock, but make it as slow as possible
- * to show willing
- */
- host->cdiv = SDCDIV_MAX_CDIV;
- writel(host->cdiv, host->ioaddr + SDCDIV);
- return;
- }
- div = host->max_clk / clock;
- if (div < 2)
- div = 2;
- if ((host->max_clk / div) > clock)
- div++;
- div -= 2;
- if (div > SDCDIV_MAX_CDIV)
- div = SDCDIV_MAX_CDIV;
- clock = host->max_clk / (div + 2);
- host->mmc->clock = clock;
- /* Calibrate some delays */
- host->ns_per_fifo_word = (1000000000 / clock) *
- ((host->mmc->card_caps & MMC_MODE_4BIT) ? 8 : 32);
- host->cdiv = div;
- writel(host->cdiv, host->ioaddr + SDCDIV);
- /* Set the timeout to 500ms */
- writel(host->mmc->clock / 2, host->ioaddr + SDTOUT);
- }
- static inline int is_power_of_2(u64 x)
- {
- return !(x & (x - 1));
- }
- static int bcm2835_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data)
- {
- struct bcm2835_host *host = dev_get_priv(dev);
- u32 edm, fsm;
- int ret = 0;
- if (data && !is_power_of_2(data->blocksize)) {
- printf("unsupported block size (%d bytes)\n", data->blocksize);
- if (cmd)
- return -EINVAL;
- }
- edm = readl(host->ioaddr + SDEDM);
- fsm = edm & SDEDM_FSM_MASK;
- if ((fsm != SDEDM_FSM_IDENTMODE) &&
- (fsm != SDEDM_FSM_DATAMODE) &&
- (cmd && cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)) {
- printf("previous command (%d) not complete (EDM %08x)\n",
- readl(host->ioaddr + SDCMD) & SDCMD_CMD_MASK, edm);
- bcm2835_dumpregs(host);
- if (cmd)
- return -EILSEQ;
- return 0;
- }
- if (cmd) {
- ret = bcm2835_send_command(host, cmd, data);
- if (!ret && !host->use_busy)
- ret = bcm2835_finish_command(host);
- }
- /* Wait for completion of busy signal or data transfer */
- while (host->use_busy || host->data) {
- ret = bcm2835_transmit(host);
- if (ret)
- break;
- }
- return ret;
- }
- static int bcm2835_set_ios(struct udevice *dev)
- {
- struct bcm2835_host *host = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- if (!mmc->clock || mmc->clock != host->clock) {
- bcm2835_set_clock(host, mmc->clock);
- host->clock = mmc->clock;
- }
- /* set bus width */
- host->hcfg &= ~SDHCFG_WIDE_EXT_BUS;
- if (mmc->bus_width == 4)
- host->hcfg |= SDHCFG_WIDE_EXT_BUS;
- host->hcfg |= SDHCFG_WIDE_INT_BUS;
- /* Disable clever clock switching, to cope with fast core clocks */
- host->hcfg |= SDHCFG_SLOW_CARD;
- writel(host->hcfg, host->ioaddr + SDHCFG);
- return 0;
- }
- static void bcm2835_add_host(struct bcm2835_host *host)
- {
- struct mmc_config *cfg = &host->plat->cfg;
- cfg->f_max = host->max_clk;
- cfg->f_min = host->max_clk / SDCDIV_MAX_CDIV;
- cfg->b_max = 65535;
- dev_dbg(dev, "f_max %d, f_min %d\n",
- cfg->f_max, cfg->f_min);
- /* host controller capabilities */
- cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz;
- /* report supported voltage ranges */
- cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- /* Set interrupt enables */
- host->hcfg = SDHCFG_BUSY_IRPT_EN;
- bcm2835_reset_internal(host);
- }
- static int bcm2835_probe(struct udevice *dev)
- {
- struct bcm2835_plat *plat = dev_get_platdata(dev);
- struct bcm2835_host *host = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- host->dev = dev;
- host->mmc = mmc;
- host->plat = plat;
- upriv->mmc = &plat->mmc;
- plat->cfg.name = dev->name;
- host->phys_addr = devfdt_get_addr(dev);
- if (host->phys_addr == FDT_ADDR_T_NONE)
- return -EINVAL;
- host->ioaddr = devm_ioremap(dev, host->phys_addr, SZ_256);
- if (!host->ioaddr)
- return -ENOMEM;
- host->max_clk = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_CORE);
- bcm2835_add_host(host);
- dev_dbg(dev, "%s -> OK\n", __func__);
- return 0;
- }
- static const struct udevice_id bcm2835_match[] = {
- { .compatible = "brcm,bcm2835-sdhost" },
- { }
- };
- static const struct dm_mmc_ops bcm2835_ops = {
- .send_cmd = bcm2835_send_cmd,
- .set_ios = bcm2835_set_ios,
- };
- static int bcm2835_bind(struct udevice *dev)
- {
- struct bcm2835_plat *plat = dev_get_platdata(dev);
- return mmc_bind(dev, &plat->mmc, &plat->cfg);
- }
- U_BOOT_DRIVER(bcm2835_sdhost) = {
- .name = "bcm2835-sdhost",
- .id = UCLASS_MMC,
- .of_match = bcm2835_match,
- .bind = bcm2835_bind,
- .probe = bcm2835_probe,
- .priv_auto_alloc_size = sizeof(struct bcm2835_host),
- .platdata_auto_alloc_size = sizeof(struct bcm2835_plat),
- .ops = &bcm2835_ops,
- };
|