123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /*
- * Copyright (c) 2006-2024 RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2024-10-28 zhujiale The first version
- */
- #include <sdhci.h>
- #include <rtdevice.h>
- #include "drv_sd.h"
- #define DBG_TAG "SDHCI"
- #ifdef DRV_DEBUG
- #define DBG_LVL DBG_LOG
- #else
- #define DBG_LVL DBG_INFO
- #endif /* DRV_DEBUG */
- #include <rtdbg.h>
- #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
- struct sdhci_iproc_data {
- const struct sdhci_pltfm_data *pdata;
- rt_uint32_t caps;
- rt_uint32_t caps1;
- rt_uint32_t mmc_caps;
- rt_bool_t missing_caps;
- };
- struct sdhci_iproc_host {
- const struct sdhci_iproc_data *data;
- rt_uint32_t shadow_cmd;
- rt_uint32_t shadow_blk;
- rt_bool_t is_cmd_shadowed;
- rt_bool_t is_blk_shadowed;
- };
- static inline rt_uint32_t sdhci_iproc_readl(struct sdhci_host *host, int reg)
- {
- rt_uint32_t val = readl(host->ioaddr + reg);
- return val;
- }
- static rt_uint16_t sdhci_iproc_readw(struct sdhci_host *host, int reg)
- {
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
- rt_uint32_t val;
- rt_uint16_t word;
- if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed)
- {
- /* Get the saved transfer mode */
- val = iproc_host->shadow_cmd;
- } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
- iproc_host->is_blk_shadowed)
- {
- /* Get the saved block info */
- val = iproc_host->shadow_blk;
- } else {
- val = sdhci_iproc_readl(host, (reg & ~3));
- }
- word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
- return word;
- }
- static rt_uint8_t sdhci_iproc_readb(struct sdhci_host *host, int reg)
- {
- rt_uint32_t val = sdhci_iproc_readl(host, (reg & ~3));
- rt_uint8_t byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff;
- return byte;
- }
- static inline void sdhci_iproc_writel(struct sdhci_host *host, rt_uint32_t val, int reg)
- {
- LOG_D("%s: writel [0x%02x] 0x%08x\n",
- mmc_hostname(host->mmc), reg, val);
- writel(val, host->ioaddr + reg);
- if (host->clock <= 400000)
- {
- /* Round up to micro-second four SD clock delay */
- if (host->clock)
- rt_hw_us_delay((4 * 1000000 + host->clock - 1) / host->clock);
- else
- rt_hw_us_delay(10);
- }
- }
- static void sdhci_iproc_writew(struct sdhci_host *host, rt_uint16_t val, int reg)
- {
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
- rt_uint32_t word_shift = REG_OFFSET_IN_BITS(reg);
- rt_uint32_t mask = 0xffff << word_shift;
- rt_uint32_t oldval, newval;
- if (reg == SDHCI_COMMAND)
- {
- /* Write the block now as we are issuing a command */
- if (iproc_host->is_blk_shadowed)
- {
- sdhci_iproc_writel(host, iproc_host->shadow_blk,
- SDHCI_BLOCK_SIZE);
- iproc_host->is_blk_shadowed = false;
- }
- oldval = iproc_host->shadow_cmd;
- iproc_host->is_cmd_shadowed = false;
- } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
- iproc_host->is_blk_shadowed)
- {
- /* Block size and count are stored in shadow reg */
- oldval = iproc_host->shadow_blk;
- } else {
- /* Read reg, all other registers are not shadowed */
- oldval = sdhci_iproc_readl(host, (reg & ~3));
- }
- newval = (oldval & ~mask) | (val << word_shift);
- if (reg == SDHCI_TRANSFER_MODE)
- {
- /* Save the transfer mode until the command is issued */
- iproc_host->shadow_cmd = newval;
- iproc_host->is_cmd_shadowed = true;
- } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT)
- {
- /* Save the block info until the command is issued */
- iproc_host->shadow_blk = newval;
- iproc_host->is_blk_shadowed = true;
- } else {
- /* Command or other regular 32-bit write */
- sdhci_iproc_writel(host, newval, reg & ~3);
- }
- }
- static void sdhci_iproc_writeb(struct sdhci_host *host, rt_uint8_t val, int reg)
- {
- rt_uint32_t oldval = sdhci_iproc_readl(host, (reg & ~3));
- rt_uint32_t byte_shift = REG_OFFSET_IN_BITS(reg);
- rt_uint32_t mask = 0xff << byte_shift;
- rt_uint32_t newval = (oldval & ~mask) | (val << byte_shift);
- sdhci_iproc_writel(host, newval, reg & ~3);
- }
- static const struct sdhci_ops sdhci_iproc_bcm2711_ops = {
- .read_l = sdhci_iproc_readl,
- .read_w = sdhci_iproc_readw,
- .read_b = sdhci_iproc_readb,
- .write_l = sdhci_iproc_writel,
- .write_w = sdhci_iproc_writew,
- .write_b = sdhci_iproc_writeb,
- .set_clock = sdhci_set_clock,
- .set_bus_width = sdhci_set_bus_width,
- .reset = sdhci_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
- static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = {
- .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
- .ops = &sdhci_iproc_bcm2711_ops,
- };
- static const struct sdhci_iproc_data bcm2711_data = {
- .pdata = &sdhci_bcm2711_pltfm_data,
- .mmc_caps = MMC_CAP_3_3V_DDR,
- };
- rt_err_t bcm2835_probe(struct rt_platform_device *pdev)
- {
- struct sdhci_iproc_host *iproc_host;
- const struct sdhci_iproc_data *iproc_data = NULL;
- struct sdhci_host *host;
- struct sdhci_pltfm_host *pltfm_host;
- int ret;
- iproc_data = &bcm2711_data;
- host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host));
- pltfm_host = sdhci_priv(host);
- iproc_host = sdhci_pltfm_priv(pltfm_host);
- iproc_host->data = iproc_data;
- ret = mmc_of_parse(host->mmc);
- if (ret)
- goto err;
- sdhci_get_property(pdev);
- host->mmc->caps |= iproc_host->data->mmc_caps;
- ret = sdhci_add_host(host);
- if (ret)
- goto err;
- return 0;
- err:
- return ret;
- }
- static const struct rt_ofw_node_id bcm2835_ofw_ids[] =
- {
- /* { .compatible = "brcm,bcm2711-emmc2"},*/
- { .compatible = "brcm,bcm2835-mmc"},
- { /* sentinel */ }
- };
- static struct rt_platform_driver bcm2835_driver =
- {
- .name = "bcm2835",
- .ids = bcm2835_ofw_ids,
- .probe = bcm2835_probe,
- /* .remove = pl011_remove,*/
- };
- RT_PLATFORM_DRIVER_EXPORT(bcm2835_driver);
|