diff options
Diffstat (limited to 'drivers/mci')
35 files changed, 3350 insertions, 1403 deletions
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig index 21d53c0c3f..1e8c85643b 100644 --- a/drivers/mci/Kconfig +++ b/drivers/mci/Kconfig @@ -12,6 +12,13 @@ if MCI comment "--- Feature list ---" +config MCI_TUNING + bool "EXPERIMENTAL - support MMC tuning for higher speeds" + help + Say 'y' here if supporting drivers should do tuning to support + higher clock speeds than 52 MHz SDR. MMC only; SD-Card max + frequency is 50MHz SDR at present. + config MCI_STARTUP bool "Force probe on system start" help @@ -58,6 +65,14 @@ config MCI_MMC_GPP_PARTITIONS comment "--- MCI host drivers ---" +config MCI_DWC_MSHC + bool "Synopsys DesignWare Cores MSHC" + depends on HAS_DMA + select MCI_SDHCI + help + This selects support for the Synopsys DesignWare Mobile Storage Host Controller + block (DWC_mshc), this provides host support for SD/eMMC interfaces, in SDMA mode. + config MCI_DW bool "Synopsys DesignWare Memory Card Interface" depends on HAS_DMA @@ -87,13 +102,6 @@ config MCI_ROCKCHIP_DWCMSHC Enable this entry to add support for a Rockchip derivation of the DWCMSHC controller found on some Rockchip SoCs like the RK3568. -config MCI_S3C - bool "S3C" - depends on ARCH_S3C24xx - help - Enable this entry to add support to read and write SD cards on a - Samsung S3C24xx based system. - config MCI_BCM283X bool "MCI support for BCM283X" depends on ARCH_BCM283X || COMPILE_TEST @@ -184,6 +192,14 @@ config MCI_ARASAN Enable this to support SD and MMC card read/write on systems with the Arasan SD3.0 / SDIO3.0 / eMMC4.51 host controller. +config MCI_AM654 + bool "Support for the SDHCI Controller in TI's AM654 SOCs" + select MCI_SDHCI + help + This selects the Secure Digital Host Controller Interface (SDHCI) + support present in TI's AM654 SOCs. The controller supports + SD/MMC/SDIO devices. + config MCI_SPI bool "MMC/SD over SPI" select CRC7 diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile index 55ec97b3fe..d8d7818a48 100644 --- a/drivers/mci/Makefile +++ b/drivers/mci/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MCI) += mci-core.o +obj-$(CONFIG_MCI_AM654) += am654-sdhci.o obj-$(CONFIG_MCI_ARASAN) += arasan-sdhci.o obj-$(CONFIG_MCI_ATMEL) += atmel_mci.o atmel_mci_common.o obj-$(CONFIG_MCI_ATMEL_SDHCI) += atmel-sdhci.o atmel-sdhci-common.o @@ -14,11 +15,11 @@ pbl-$(CONFIG_MCI_IMX_ESDHC_PBL) += imx-esdhc-pbl.o imx-esdhc-common.o obj-$(CONFIG_MCI_MXS) += mxs.o obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o obj-$(CONFIG_MCI_PXA) += pxamci.o -obj-$(CONFIG_MCI_S3C) += s3c.o obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC) += rockchip-dwcmshc-sdhci.o obj-$(CONFIG_MCI_TEGRA) += tegra-sdmmc.o obj-$(CONFIG_MCI_SPI) += mci_spi.o obj-$(CONFIG_MCI_DW) += dw_mmc.o +obj-$(CONFIG_MCI_DWC_MSHC) += dwcmshc-sdhci.o obj-$(CONFIG_MCI_MMCI) += mmci.o obj-$(CONFIG_MCI_STM32_SDMMC2) += stm32_sdmmc2.o obj-pbl-$(CONFIG_MCI_SDHCI) += sdhci.o diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c new file mode 100644 index 0000000000..391b65591c --- /dev/null +++ b/drivers/mci/am654-sdhci.c @@ -0,0 +1,680 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * Texas Instruments' K3 SD Host Controller Interface + */ +#include <common.h> +#include <init.h> +#include <driver.h> +#include <mci.h> +#include <clock.h> +#include <errno.h> +#include <io.h> +#include <regmap.h> +#include <linux/err.h> +#include <linux/clk.h> +#include "sdhci.h" + +/* CTL_CFG Registers */ +#define CTL_CFG_2 0x14 + +#define SLOTTYPE_MASK GENMASK(31, 30) +#define SLOTTYPE_EMBEDDED BIT(30) + +/* PHY Registers */ +#define PHY_CTRL1 0x100 +#define PHY_CTRL2 0x104 +#define PHY_CTRL3 0x108 +#define PHY_CTRL4 0x10C +#define PHY_CTRL5 0x110 +#define PHY_CTRL6 0x114 +#define PHY_STAT1 0x130 +#define PHY_STAT2 0x134 + +#define IOMUX_ENABLE_SHIFT 31 +#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT) +#define OTAPDLYENA_SHIFT 20 +#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT) +#define OTAPDLYSEL_SHIFT 12 +#define OTAPDLYSEL_MASK GENMASK(15, 12) +#define STRBSEL_SHIFT 24 +#define STRBSEL_4BIT_MASK GENMASK(27, 24) +#define STRBSEL_8BIT_MASK GENMASK(31, 24) +#define SEL50_SHIFT 8 +#define SEL50_MASK BIT(SEL50_SHIFT) +#define SEL100_SHIFT 9 +#define SEL100_MASK BIT(SEL100_SHIFT) +#define FREQSEL_SHIFT 8 +#define FREQSEL_MASK GENMASK(10, 8) +#define CLKBUFSEL_SHIFT 0 +#define CLKBUFSEL_MASK GENMASK(2, 0) +#define DLL_TRIM_ICP_SHIFT 4 +#define DLL_TRIM_ICP_MASK GENMASK(7, 4) +#define DR_TY_SHIFT 20 +#define DR_TY_MASK GENMASK(22, 20) +#define ENDLL_SHIFT 1 +#define ENDLL_MASK BIT(ENDLL_SHIFT) +#define DLLRDY_SHIFT 0 +#define DLLRDY_MASK BIT(DLLRDY_SHIFT) +#define PDB_SHIFT 0 +#define PDB_MASK BIT(PDB_SHIFT) +#define CALDONE_SHIFT 1 +#define CALDONE_MASK BIT(CALDONE_SHIFT) +#define RETRIM_SHIFT 17 +#define RETRIM_MASK BIT(RETRIM_SHIFT) +#define SELDLYTXCLK_SHIFT 17 +#define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT) +#define SELDLYRXCLK_SHIFT 16 +#define SELDLYRXCLK_MASK BIT(SELDLYRXCLK_SHIFT) +#define ITAPDLYSEL_SHIFT 0 +#define ITAPDLYSEL_MASK GENMASK(4, 0) +#define ITAPDLYENA_SHIFT 8 +#define ITAPDLYENA_MASK BIT(ITAPDLYENA_SHIFT) +#define ITAPCHGWIN_SHIFT 9 +#define ITAPCHGWIN_MASK BIT(ITAPCHGWIN_SHIFT) + +#define DRIVER_STRENGTH_50_OHM 0x0 +#define DRIVER_STRENGTH_33_OHM 0x1 +#define DRIVER_STRENGTH_66_OHM 0x2 +#define DRIVER_STRENGTH_100_OHM 0x3 +#define DRIVER_STRENGTH_40_OHM 0x4 + +#define AM654_SDHCI_MIN_FREQ 400000 +#define CLOCK_TOO_SLOW_HZ 50000000 + +#define MMC_CAP2_HS200 0 +#define MMC_CAP2_HS400 0 +#define MMC_CAP_UHS_SDR104 0 +#define MMC_CAP_UHS_SDR12 0 +#define MMC_CAP_UHS_DDR50 0 +#define MMC_CAP_UHS_SDR25 0 +#define MMC_CAP_UHS_SDR50 0 + +struct timing_data { + const char *otap_binding; + const char *itap_binding; + u32 capability; +}; + +static const struct timing_data td[] = { + [MMC_TIMING_LEGACY] = { + "ti,otap-del-sel-legacy", + "ti,itap-del-sel-legacy", + 0 + }, + [MMC_TIMING_MMC_HS] = { + "ti,otap-del-sel-mmc-hs", + "ti,itap-del-sel-mms-hs", + MMC_CAP_MMC_HIGHSPEED + }, + [MMC_TIMING_SD_HS] = { + "ti,otap-del-sel-sd-hs", + "ti,itap-del-sel-sd-hs", + MMC_CAP_SD_HIGHSPEED + }, + [MMC_TIMING_UHS_SDR12] = { + "ti,otap-del-sel-sdr12", + "ti,itap-del-sel-sdr12", + MMC_CAP_UHS_SDR12 + }, + [MMC_TIMING_UHS_SDR25] = { + "ti,otap-del-sel-sdr25", + "ti,itap-del-sel-sdr25", + MMC_CAP_UHS_SDR25 + }, + [MMC_TIMING_UHS_SDR50] = { + "ti,otap-del-sel-sdr50", + NULL, + MMC_CAP_UHS_SDR50 + }, + [MMC_TIMING_UHS_SDR104] = { + "ti,otap-del-sel-sdr104", + NULL, + MMC_CAP_UHS_SDR104 + }, + [MMC_TIMING_UHS_DDR50] = { + "ti,otap-del-sel-ddr50", + NULL, + MMC_CAP_UHS_DDR50 + }, + [MMC_TIMING_MMC_DDR52] = { + "ti,otap-del-sel-ddr52", + "ti,itap-del-sel-ddr52", + MMC_CAP_DDR + }, + [MMC_TIMING_MMC_HS200] = { + "ti,otap-del-sel-hs200", + NULL, + MMC_CAP2_HS200 + }, + [MMC_TIMING_MMC_HS400] = { + "ti,otap-del-sel-hs400", + NULL, + MMC_CAP2_HS400 + }, +}; + +struct am654_sdhci_plat { + struct sdhci sdhci; + struct mci_host mci; + struct clk *clk; + struct clk *clk_ahb; + const struct am654_driver_data *soc_data; + bool fails_without_test_cd; + + struct regmap *base; + bool non_removable; + u32 otap_del_sel[ARRAY_SIZE(td)]; + u32 itap_del_sel[ARRAY_SIZE(td)]; + u32 trm_icp; + u32 drv_strength; + u32 strb_sel; + u32 clkbuf_sel; +#define DLL_PRESENT BIT(0) +#define IOMUX_PRESENT BIT(1) +#define FREQSEL_2_BIT BIT(2) +#define STRBSEL_4_BIT BIT(3) +#define DLL_CALIB BIT(4) +}; + +struct am654_driver_data { + int (*set_ios_post)(struct am654_sdhci_plat *plat, struct mci_ios *ios); + u32 flags; +}; + +static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat, + unsigned int speed) +{ + int sel50, sel100, freqsel; + u32 mask, val; + int ret; + + /* Disable delay chain mode */ + regmap_update_bits(plat->base, PHY_CTRL5, + SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0); + + if (plat->soc_data->flags & FREQSEL_2_BIT) { + switch (speed) { + case 200000000: + sel50 = 0; + sel100 = 0; + break; + case 100000000: + sel50 = 0; + sel100 = 1; + break; + default: + sel50 = 1; + sel100 = 0; + } + + /* Configure PHY DLL frequency */ + mask = SEL50_MASK | SEL100_MASK; + val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL5, mask, val); + } else { + switch (speed) { + case 200000000: + freqsel = 0x0; + break; + default: + freqsel = 0x4; + } + regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK, + freqsel << FREQSEL_SHIFT); + } + + /* Configure DLL TRIM */ + mask = DLL_TRIM_ICP_MASK; + val = plat->trm_icp << DLL_TRIM_ICP_SHIFT; + + /* Configure DLL driver strength */ + mask |= DR_TY_MASK; + val |= plat->drv_strength << DR_TY_SHIFT; + regmap_update_bits(plat->base, PHY_CTRL1, mask, val); + + /* Enable DLL */ + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, + 0x1 << ENDLL_SHIFT); + /* + * Poll for DLL ready. Use a one second timeout. + * Works in all experiments done so far + */ + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val, + val & DLLRDY_MASK, 1000000); + + return ret; +} + +static void am654_sdhci_write_itapdly(struct am654_sdhci_plat *plat, + u32 itapdly) +{ + /* Set ITAPCHGWIN before writing to ITAPDLY */ + regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, + 1 << ITAPCHGWIN_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYSEL_MASK, + itapdly << ITAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0); +} + +static void am654_sdhci_setup_delay_chain(struct am654_sdhci_plat *plat, + int mode) +{ + u32 mask, val; + + val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT; + mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK; + regmap_update_bits(plat->base, PHY_CTRL5, mask, val); + + am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode]); +} + +static int am654_sdhci_set_ios_post(struct am654_sdhci_plat *plat, struct mci_ios *ios) +{ + unsigned int speed = ios->clock; + int mode = ios->timing; + u32 otap_del_sel; + u32 mask, val; + int ret; + + /* Reset SD Clock Enable */ + val = sdhci_read16(&plat->sdhci, SDHCI_CLOCK_CONTROL); + val &= ~SDHCI_CLOCK_CARD_EN; + sdhci_write16(&plat->sdhci, SDHCI_CLOCK_CONTROL, val); + + regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0); + + /* restart clock */ + sdhci_set_clock(&plat->sdhci, speed, clk_get_rate(plat->clk)); + + /* switch phy back on */ + otap_del_sel = plat->otap_del_sel[mode]; + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | + (otap_del_sel << OTAPDLYSEL_SHIFT); + + /* Write to STRBSEL for HS400 speed mode */ + if (mode == MMC_TIMING_MMC_HS400) { + if (plat->soc_data->flags & STRBSEL_4_BIT) + mask |= STRBSEL_4BIT_MASK; + else + mask |= STRBSEL_8BIT_MASK; + + val |= plat->strb_sel << STRBSEL_SHIFT; + } + + regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + + if (mode > MMC_TIMING_UHS_SDR25 && speed >= CLOCK_TOO_SLOW_HZ) { + ret = am654_sdhci_setup_dll(plat, speed); + if (ret) + return ret; + } else { + am654_sdhci_setup_delay_chain(plat, mode); + } + + regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK, + plat->clkbuf_sel); + + return 0; +} + +static int am654_sdhci_init(struct mci_host *mci, struct device *dev) +{ + struct am654_sdhci_plat *plat = container_of(mci, struct am654_sdhci_plat, mci); + u32 ctl_cfg_2 = 0; + u32 mask, val; + int ret; + + ret = sdhci_reset(&plat->sdhci, SDHCI_RESET_ALL); + if (ret) + return ret; + + if (plat->fails_without_test_cd) { + val = sdhci_read8(&plat->sdhci, SDHCI_HOST_CONTROL); + val |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN; + sdhci_write8(&plat->sdhci, SDHCI_HOST_CONTROL, val); + } + + sdhci_write8(&plat->sdhci, SDHCI_POWER_CONTROL, + SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN); + udelay(400); + + sdhci_write32(&plat->sdhci, SDHCI_INT_ENABLE, ~0); + sdhci_write32(&plat->sdhci, SDHCI_SIGNAL_ENABLE, 0x00); + + /* Reset OTAP to default value */ + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0); + + if (plat->soc_data->flags & DLL_CALIB) { + regmap_read(plat->base, PHY_STAT1, &val); + if (~val & CALDONE_MASK) { + /* Calibrate IO lines */ + regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK, + PDB_MASK); + ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, + val, val & CALDONE_MASK, + 20); + if (ret) + return ret; + } + } + + /* Enable pins by setting IO mux to 0 */ + if (plat->soc_data->flags & IOMUX_PRESENT) + regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0); + + /* Set slot type based on SD or eMMC */ + if (plat->non_removable) + ctl_cfg_2 = SLOTTYPE_EMBEDDED; + + regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2); + + return 0; +} + +const struct am654_driver_data am654_drv_data = { + .flags = DLL_PRESENT | IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT, +}; + +const struct am654_driver_data am654_sr1_drv_data = { + .flags = IOMUX_PRESENT | FREQSEL_2_BIT | DLL_PRESENT | DLL_CALIB | + STRBSEL_4_BIT, +}; + +const struct am654_driver_data j721e_8bit_drv_data = { + .flags = DLL_PRESENT | DLL_CALIB, +}; + +static int j721e_4bit_sdhci_set_ios_post(struct am654_sdhci_plat *plat, struct mci_ios *ios) +{ + u32 otap_del_sel, mask, val; + + otap_del_sel = plat->otap_del_sel[ios->timing]; + mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; + val = (1 << OTAPDLYENA_SHIFT) | (otap_del_sel << OTAPDLYSEL_SHIFT); + regmap_update_bits(plat->base, PHY_CTRL4, mask, val); + + regmap_update_bits(plat->base, PHY_CTRL5, CLKBUFSEL_MASK, + plat->clkbuf_sel); + + return 0; +} + +const struct am654_driver_data j721e_4bit_drv_data = { + .set_ios_post = &j721e_4bit_sdhci_set_ios_post, + .flags = IOMUX_PRESENT, +}; + +static const struct am654_driver_data sdhci_am64_8bit_drvdata = { + .set_ios_post = &am654_sdhci_set_ios_post, + .flags = DLL_PRESENT | DLL_CALIB, +}; + +static const struct am654_driver_data sdhci_am64_4bit_drvdata = { + .set_ios_post = &j721e_4bit_sdhci_set_ios_post, + .flags = IOMUX_PRESENT, +}; + +static int sdhci_am654_get_otap_delay(struct am654_sdhci_plat *plat) +{ + struct device *dev = plat->mci.hw_dev; + struct device_node *np = dev->of_node; + int ret; + int i; + + /* ti,otap-del-sel-legacy is mandatory */ + ret = of_property_read_u32(np, "ti,otap-del-sel-legacy", + &plat->otap_del_sel[0]); + if (ret) + return ret; + /* + * Remove the corresponding capability if an otap-del-sel + * value is not found + */ + for (i = MMC_TIMING_MMC_HS; i <= MMC_TIMING_MMC_HS400; i++) { + ret = of_property_read_u32(np, td[i].otap_binding, + &plat->otap_del_sel[i]); + if (ret) { + dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding); + /* + * Remove the corresponding capability + * if an otap-del-sel value is not found + */ + plat->mci.host_caps &= ~td[i].capability; + } + + if (td[i].itap_binding) + of_property_read_u32(np, td[i].itap_binding, + &plat->itap_del_sel[i]); + } + + return 0; +} + +static void print_error(struct am654_sdhci_plat *host, int cmdidx) +{ + dev_dbg(host->mci.hw_dev, + "error while transfering data for command %d\n", cmdidx); + dev_dbg(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n", + sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE), + sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS)); +} + +static int am654_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, + struct mci_data *data) +{ + struct am654_sdhci_plat *host = container_of(mci, struct am654_sdhci_plat, mci); + u32 command, xfer; + int ret; + dma_addr_t dma; + + ret = sdhci_wait_idle_data(&host->sdhci, cmd); + if (ret) + return ret; + + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); + + sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe); + + sdhci_setup_data_dma(&host->sdhci, data, &dma); + + sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, + dma == SDHCI_NO_DMA ? false : true, + &command, &xfer); + + sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer); + sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); + sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); + + ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE); + if (ret) + goto error; + + sdhci_read_response(&host->sdhci, cmd); + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE); + + ret = sdhci_transfer_data_dma(&host->sdhci, data, dma); + +error: + if (ret) { + print_error(host, cmd->cmdidx); + sdhci_reset(&host->sdhci, SDHCI_RESET_CMD); + sdhci_reset(&host->sdhci, SDHCI_RESET_DATA); + } + + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); + + return ret; +} + +static void am654_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios) +{ + struct am654_sdhci_plat *plat = container_of(mci, struct am654_sdhci_plat, mci); + u32 val; + + if (ios->clock) + sdhci_set_clock(&plat->sdhci, ios->clock, plat->sdhci.max_clk); + + sdhci_set_bus_width(&plat->sdhci, ios->bus_width); + + val = sdhci_read8(&plat->sdhci, SDHCI_HOST_CONTROL); + + if (ios->clock > 26000000) + val |= SDHCI_CTRL_HISPD; + else + val &= ~SDHCI_CTRL_HISPD; + + sdhci_write8(&plat->sdhci, SDHCI_HOST_CONTROL, val); + + plat->soc_data->set_ios_post(plat, ios); +} + +static const struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x400, +}; + +static int am654_sdhci_probe(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct am654_sdhci_plat *plat; + struct mci_host *mci; + struct resource *iores; + u32 drv_strength; + int ret; + + plat = xzalloc(sizeof(*plat)); + + ret = dev_get_drvdata(dev, (const void **)&plat->soc_data); + if (ret) + return ret; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + + plat->sdhci.base = IOMEM(iores->start); + + iores = dev_request_mem_resource(dev, 1); + if (IS_ERR(iores)) + return PTR_ERR(iores); + + plat->base = regmap_init_mmio(dev, IOMEM(iores->start), ®map_config); + if (IS_ERR(plat->base)) { + dev_err(dev, "failed to init regmap: %ld\n", + PTR_ERR(plat->base)); + return PTR_ERR(plat->base); + } + + plat->clk = clk_get(dev, "clk_xin"); + if (IS_ERR(plat->clk)) { + dev_err(dev, "failed to get clock\n"); + return ret; + } + + clk_enable(plat->clk); + + plat->clk_ahb = clk_get(dev, "clk_ahb"); + if (IS_ERR(plat->clk_ahb)) { + dev_err(dev, "failed to get ahb clock\n"); + return ret; + } + + clk_enable(plat->clk_ahb); + + mci = &plat->mci; + mci->f_max = clk_get_rate(plat->clk); + mci->f_min = 50000000 / 256; + + if (plat->soc_data->flags & DLL_PRESENT) { + ret = of_property_read_u32(np, "ti,trm-icp", &plat->trm_icp); + if (ret) + return ret; + + ret = of_property_read_u32(np, "ti,driver-strength-ohm", + &drv_strength); + if (ret) + return ret; + + switch (drv_strength) { + case 50: + plat->drv_strength = DRIVER_STRENGTH_50_OHM; + break; + case 33: + plat->drv_strength = DRIVER_STRENGTH_33_OHM; + break; + case 66: + plat->drv_strength = DRIVER_STRENGTH_66_OHM; + break; + case 100: + plat->drv_strength = DRIVER_STRENGTH_100_OHM; + break; + case 40: + plat->drv_strength = DRIVER_STRENGTH_40_OHM; + break; + default: + dev_err(dev, "Invalid driver strength\n"); + return -EINVAL; + } + } + + mci->send_cmd = am654_sdhci_send_cmd; + mci->set_ios = am654_sdhci_set_ios; + mci->init = am654_sdhci_init; + mci->hw_dev = dev; + + of_property_read_u32(np, "ti,strobe-sel", &plat->strb_sel); + of_property_read_u32(np, "ti,clkbuf-sel", &plat->clkbuf_sel); + + plat->fails_without_test_cd = of_property_read_bool(np, "ti,fails-without-test-cd"); + + mci_of_parse(&plat->mci); + + ret = sdhci_am654_get_otap_delay(plat); + if (ret) + return ret; + + plat->sdhci.mci = mci; + sdhci_setup_host(&plat->sdhci); + + dev->priv = plat; + + return mci_register(&plat->mci); +} + +static const struct of_device_id am654_sdhci_ids[] = { + { + .compatible = "ti,am654-sdhci-5.1", + .data = &am654_drv_data, + }, { + .compatible = "ti,j721e-sdhci-8bit", + .data = &j721e_8bit_drv_data, + }, { + .compatible = "ti,j721e-sdhci-4bit", + .data = &j721e_4bit_drv_data, + }, { + .compatible = "ti,am64-sdhci-8bit", + .data = &sdhci_am64_8bit_drvdata, + }, { + .compatible = "ti,am64-sdhci-4bit", + .data = &sdhci_am64_4bit_drvdata, + }, { + .compatible = "ti,am62-sdhci", + .data = &sdhci_am64_4bit_drvdata, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, am654_sdhci_ids); + +static struct driver am654_sdhc_driver = { + .name = "am654-sdhci", + .probe = am654_sdhci_probe, + .of_compatible = DRV_OF_COMPAT(am654_sdhci_ids), +}; +device_platform_driver(am654_sdhc_driver); diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c index d45f9184cd..be13954541 100644 --- a/drivers/mci/arasan-sdhci.c +++ b/drivers/mci/arasan-sdhci.c @@ -6,6 +6,7 @@ #include <init.h> #include <linux/clk.h> #include <mci.h> +#include <mach/zynqmp/firmware-zynqmp.h> #include "sdhci.h" @@ -30,13 +31,52 @@ #define SDHCI_ARASAN_BUS_WIDTH 4 #define TIMEOUT_VAL 0xE +#define ZYNQMP_CLK_PHASES 10 +#define ZYNQMP_CLK_PHASE_UHS_SDR104 6 +#define ZYNQMP_CLK_PHASE_HS200 9 +/* Default settings for ZynqMP Clock Phases */ +#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} +#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} + +/** + * struct sdhci_arasan_clk_data - Arasan Controller Clock Data. + * + * @sdcardclk_hw: Struct for the clock we might provide to a PHY. + * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. + * @sampleclk_hw: Struct for the clock we might provide to a PHY. + * @sampleclk: Pointer to normal 'struct clock' for sampleclk_hw. + * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes + * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes + * @set_clk_delays: Function pointer for setting Clock Delays + * @clk_of_data: Platform specific runtime clock data storage pointer + */ +struct sdhci_arasan_clk_data { + struct clk_hw sdcardclk_hw; + struct clk *sdcardclk; + struct clk_hw sampleclk_hw; + struct clk *sampleclk; + int clk_phase_in[ZYNQMP_CLK_PHASES + 1]; + int clk_phase_out[ZYNQMP_CLK_PHASES + 1]; + void (*set_clk_delays)(struct sdhci *host); + void *clk_of_data; +}; + struct arasan_sdhci_host { struct mci_host mci; struct sdhci sdhci; unsigned int quirks; /* Arasan deviations from spec */ + const struct clk_ops *sdcardclk_ops; + const struct clk_ops *sampleclk_ops; + struct sdhci_arasan_clk_data clk_data; /* Controller does not have CD wired and will not function normally without */ #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0) #define SDHCI_ARASAN_QUIRK_NO_1_8_V BIT(1) +/* + * Some of the Arasan variations might not have timing requirements + * met at 25MHz for Default Speed mode, those controllers work at + * 19MHz instead + */ +#define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2) }; static inline @@ -73,27 +113,64 @@ static int arasan_sdhci_card_write_protected(struct mci_host *mci) static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask) { - sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask); + int ret; - /* wait for reset completion */ - if (wait_on_timeout(100 * MSECOND, - !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))) { - dev_err(host->mci.hw_dev, "SDHCI reset timeout\n"); - return -ETIMEDOUT; - } + ret = sdhci_reset(&host->sdhci, mask); + if (ret) + return ret; if (host->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) { u8 ctrl; ctrl = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL); ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_INS; - sdhci_write8(&host->sdhci, ctrl, SDHCI_HOST_CONTROL); + sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, ctrl); } return 0; } -static int arasan_sdhci_init(struct mci_host *mci, struct device_d *dev) +static void arasan_zynqmp_dll_reset(struct arasan_sdhci_host *host, u32 deviceid) +{ + u16 clk; + + clk = sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL); + clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, clk); + + /* Issue DLL Reset */ + zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE); + + clk = sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL); + + sdhci_enable_clk(&host->sdhci, clk); +} + +static int arasan_zynqmp_execute_tuning(struct mci_host *mci, u32 opcode) +{ + struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci); + struct clk_hw *hw = &host->clk_data.sdcardclk_hw; + const char *clk_name = clk_hw_get_name(hw); + u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : + NODE_SD_1; + int err; + + /* ZynqMP SD controller does not perform auto tuning in DDR50 mode */ + if (mci->timing == MMC_TIMING_UHS_DDR50) + return 0; + + arasan_zynqmp_dll_reset(host, device_id); + + err = sdhci_execute_tuning(&host->sdhci, opcode); + if (err) + return err; + + arasan_zynqmp_dll_reset(host, device_id); + + return 0; +} + +static int arasan_sdhci_init(struct mci_host *mci, struct device *dev) { struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci); int ret; @@ -113,13 +190,36 @@ static int arasan_sdhci_init(struct mci_host *mci, struct device_d *dev) return 0; } +static void arasan_sdhci_set_clock(struct mci_host *mci, unsigned int clock) +{ + struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci); + struct sdhci_arasan_clk_data *clk_data = &host->clk_data; + + if (host->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) { + /* + * Some of the Arasan variations might not have timing + * requirements met at 25MHz for Default Speed mode, + * those controllers work at 19MHz instead. + */ + if (clock == 25000000) + clock = (25000000 * 19) / 25; + } + + clk_set_phase(clk_data->sampleclk, + clk_data->clk_phase_in[mci->mci->host->timing]); + clk_set_phase(clk_data->sdcardclk, + clk_data->clk_phase_out[mci->mci->host->timing]); + + sdhci_set_clock(&host->sdhci, clock, host->sdhci.max_clk); +} + static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios) { struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci); u16 val; if (ios->clock) - sdhci_set_clock(&host->sdhci, ios->clock, host->sdhci.max_clk); + arasan_sdhci_set_clock(mci, ios->clock); sdhci_set_bus_width(&host->sdhci, ios->bus_width); @@ -133,34 +233,11 @@ static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios) sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val); } -static int arasan_sdhci_wait_for_done(struct arasan_sdhci_host *host, u32 mask) +static void print_error(struct arasan_sdhci_host *host, int cmdidx, int ret) { - u64 start = get_time_ns(); - u16 stat; - u16 error; - - do { - stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS); - if (stat & SDHCI_INT_ERROR) { - error = sdhci_read16(&host->sdhci, - SDHCI_INT_ERROR_STATUS); - dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n", - error); - return -EPERM; - } + if (ret == -ETIMEDOUT) + return; - if (is_timeout(start, 1000 * MSECOND)) { - dev_err(host->mci.hw_dev, - "SDHCI timeout while waiting for done\n"); - return -ETIMEDOUT; - } - } while ((stat & mask) != mask); - - return 0; -} - -static void print_error(struct arasan_sdhci_host *host, int cmdidx) -{ dev_err(host->mci.hw_dev, "error while transferring data for command %d\n", cmdidx); dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n", @@ -173,35 +250,29 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, { struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci); u32 mask, command, xfer; + dma_addr_t dma; int ret; - /* Wait for idle before next command */ - mask = SDHCI_CMD_INHIBIT_CMD; - if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION) - mask |= SDHCI_CMD_INHIBIT_DATA; - - ret = wait_on_timeout(10 * MSECOND, - !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask)); - if (ret) { - dev_err(host->mci.hw_dev, - "SDHCI timeout while waiting for idle\n"); + ret = sdhci_wait_idle(&host->sdhci, cmd, data); + if (ret) return ret; - } sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); mask = SDHCI_INT_CMD_COMPLETE; - if (data && data->flags == MMC_DATA_READ) - mask |= SDHCI_INT_DATA_AVAIL; if (cmd->resp_type & MMC_RSP_BUSY) mask |= SDHCI_INT_XFER_COMPLETE; - sdhci_set_cmd_xfer_mode(&host->sdhci, - cmd, data, false, &command, &xfer); + sdhci_setup_data_dma(&host->sdhci, data, &dma); + + sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, + dma == SDHCI_NO_DMA ? false : true, + &command, &xfer); sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, TIMEOUT_VAL); - if (data) { + if (xfer) sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer); + if (data) { sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K | SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize)); sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks); @@ -209,23 +280,25 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); - ret = arasan_sdhci_wait_for_done(host, mask); - if (ret == -EPERM) + /* CMD19/21 generate _only_ Buffer Read Ready interrupt */ + if (cmd->cmdidx == MMC_SEND_TUNING_BLOCK || cmd->cmdidx == MMC_SEND_TUNING_BLOCK_HS200) + mask = SDHCI_INT_DATA_AVAIL; + + ret = sdhci_wait_for_done(&host->sdhci, mask); + if (ret) goto error; - else if (ret) - return ret; sdhci_read_response(&host->sdhci, cmd); - sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, mask); + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE); if (data) - ret = sdhci_transfer_data_pio(&host->sdhci, data); + ret = sdhci_transfer_data_dma(&host->sdhci, data, dma); error: if (ret) { - print_error(host, cmd->cmdidx); - arasan_sdhci_reset(host, BIT(1)); // SDHCI_RESET_CMD - arasan_sdhci_reset(host, BIT(2)); // SDHCI_RESET_DATA + print_error(host, cmd->cmdidx, ret); + arasan_sdhci_reset(host, SDHCI_RESET_CMD); + arasan_sdhci_reset(host, SDHCI_RESET_DATA); } sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); @@ -233,9 +306,414 @@ error: return ret; } -static int arasan_sdhci_probe(struct device_d *dev) +static void sdhci_arasan_set_clk_delays(struct sdhci *host) +{ + struct arasan_sdhci_host *arasan_sdhci = sdhci_to_arasan(host); + struct mci_host *mci = &arasan_sdhci->mci; + struct sdhci_arasan_clk_data *clk_data = &arasan_sdhci->clk_data; + + clk_set_phase(clk_data->sampleclk, + clk_data->clk_phase_in[mci->timing]); + clk_set_phase(clk_data->sdcardclk, + clk_data->clk_phase_out[mci->timing]); +} + +static void arasan_dt_read_clk_phase(struct device *dev, + struct sdhci_arasan_clk_data *clk_data, + unsigned int timing, const char *prop) +{ + struct device_node *np = dev->of_node; + + u32 clk_phase[2] = {0}; + int ret; + + /* + * Read Tap Delay values from DT, if the DT does not contain the + * Tap Values then use the pre-defined values. + */ + ret = of_property_read_u32_array(np, prop, &clk_phase[0], 2); + if (ret < 0) { + dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", + prop, clk_data->clk_phase_in[timing], + clk_data->clk_phase_out[timing]); + return; + } + + /* The values read are Input and Output Clock Delays in order */ + clk_data->clk_phase_in[timing] = clk_phase[0]; + clk_data->clk_phase_out[timing] = clk_phase[1]; +} + +/** + * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays + * + * @hw: Pointer to the hardware clock structure. + * @degrees: The clock phase shift between 0 - 359. + * + * Set the SD Input Clock Tap Delays for Input path + * + * Return: 0 on success and error value on error + */ +static int arasan_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); + struct arasan_sdhci_host *sdhci_arasan = + container_of(clk_data, struct arasan_sdhci_host, clk_data); + struct mci_host *host = &sdhci_arasan->mci; + const char *clk_name = clk_hw_get_name(hw); + u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1; + u8 tap_delay, tap_max = 0; + int ret; + + /* This is applicable for SDHCI_SPEC_300 and above */ + if (sdhci_arasan->sdhci.version < SDHCI_SPEC_300) + return 0; + + /* Assert DLL Reset */ + zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT); + + switch (host->timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 120 Taps are available */ + tap_max = 120; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 60 Taps are available */ + tap_max = 60; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 30 Taps are available */ + tap_max = 30; + break; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay); + if (ret) + pr_err("Error setting Input Tap Delay\n"); + + return ret; +} + +static unsigned long arasan_sampleclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); + struct arasan_sdhci_host *sdhci_arasan = + container_of(clk_data, struct arasan_sdhci_host, clk_data); + struct mci_host *host = &sdhci_arasan->mci; + + return host->actual_clock; +}; + +/** + * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays + * + * @hw: Pointer to the hardware clock structure. + * @degrees: The clock phase shift between 0 - 359. + * + * Set the SD Output Clock Tap Delays for Output path + * + * Return: 0 on success and error value on error + */ +static int arasan_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); + struct arasan_sdhci_host *sdhci_arasan = + container_of(clk_data, struct arasan_sdhci_host, clk_data); + struct mci_host *host = &sdhci_arasan->mci; + const char *clk_name = clk_hw_get_name(hw); + u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1; + u8 tap_delay, tap_max = 0; + int ret; + + /* This is applicable for SDHCI_SPEC_300 and above */ + if (sdhci_arasan->sdhci.version < SDHCI_SPEC_300) + return 0; + + switch (host->timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 30 Taps are available */ + tap_max = 30; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 15 Taps are available */ + tap_max = 15; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 8 Taps are available */ + tap_max = 8; + break; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay); + if (ret) + pr_err("Error setting Output Tap Delay\n"); + + /* Release DLL Reset */ + zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE); + + return ret; +} + +static unsigned long arasan_sdcardclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); + struct arasan_sdhci_host *sdhci_arasan = + container_of(clk_data, struct arasan_sdhci_host, clk_data); + struct mci_host *host = &sdhci_arasan->mci; + + return host->actual_clock; +}; + +static const struct clk_ops arasan_sampleclk_ops = { + .recalc_rate = arasan_sampleclk_recalc_rate, +}; + +static const struct clk_ops arasan_sdcardclk_ops = { + .recalc_rate = arasan_sdcardclk_recalc_rate, +}; + +static const struct clk_ops zynqmp_sampleclk_ops = { + .recalc_rate = arasan_sampleclk_recalc_rate, + .set_phase = arasan_zynqmp_sampleclk_set_phase, +}; + +static const struct clk_ops zynqmp_sdcardclk_ops = { + .recalc_rate = arasan_sdcardclk_recalc_rate, + .set_phase = arasan_zynqmp_sdcardclk_set_phase, +}; + +/** + * arasan_sdhci_register_sampleclk - Register the sampleclk for a PHY to use + * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * + * Some PHY devices need to know what the actual card clock is. In order for + * them to find out, we'll provide a clock through the common clock framework + * for them to query. + * + * Return: 0 on success and error value on error + */ +static int +arasan_sdhci_register_sampleclk(struct arasan_sdhci_host *sdhci_arasan, + struct clk *clk_xin, + struct device *dev) +{ + struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; + struct device_node *np = dev->of_node; + struct clk_init_data sampleclk_init = {}; + const char *clk_name; + int ret; + + ret = of_property_read_string_index(np, "clock-output-names", 1, + &sampleclk_init.name); + if (ret) { + dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); + return ret; + } + + clk_name = __clk_get_name(clk_xin); + sampleclk_init.parent_names = &clk_name; + sampleclk_init.num_parents = 1; + sampleclk_init.ops = sdhci_arasan->sampleclk_ops; + + clk_data->sampleclk_hw.init = &sampleclk_init; + clk_data->sampleclk = clk_register(dev, &clk_data->sampleclk_hw); + if (IS_ERR(clk_data->sampleclk)) + return PTR_ERR(clk_data->sampleclk); + clk_data->sampleclk_hw.init = NULL; + + ret = of_clk_add_provider(np, of_clk_src_simple_get, + clk_data->sampleclk); + if (ret) + dev_err(dev, "Failed to add sample clock provider\n"); + + return ret; +} + +/** + * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use + * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * + * Some PHY devices need to know what the actual card clock is. In order for + * them to find out, we'll provide a clock through the common clock framework + * for them to query. + * + * Return: 0 on success and error value on error + */ +static int +arasan_sdhci_register_sdcardclk(struct arasan_sdhci_host *sdhci_arasan, + struct clk *clk_xin, + struct device *dev) +{ + struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; + struct device_node *np = dev->of_node; + struct clk_init_data sdcardclk_init = {}; + const char *clk_name; + int ret; + + ret = of_property_read_string_index(np, "clock-output-names", 0, + &sdcardclk_init.name); + if (ret) { + dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); + return ret; + } + + clk_name = __clk_get_name(clk_xin); + sdcardclk_init.parent_names = &clk_name; + sdcardclk_init.ops = sdhci_arasan->sdcardclk_ops; + sdcardclk_init.num_parents = 1; + + clk_data->sdcardclk_hw.init = &sdcardclk_init; + clk_data->sdcardclk = clk_register(dev, &clk_data->sdcardclk_hw); + if (IS_ERR(clk_data->sdcardclk)) + return PTR_ERR(clk_data->sdcardclk); + clk_data->sdcardclk_hw.init = NULL; + + ret = of_clk_add_provider(np, of_clk_src_simple_get, + clk_data->sdcardclk); + if (ret) + dev_err(dev, "Failed to add sdcard clock provider\n"); + + return ret; +} + +/** + * arasan_sdhci_register_sdclk - Register the sdcardclk for a PHY to use + * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * + * Some PHY devices need to know what the actual card clock is. In order for + * them to find out, we'll provide a clock through the common clock framework + * for them to query. + * + * Note: without seriously re-architecting SDHCI's clock code and testing on + * all platforms, there's no way to create a totally beautiful clock here + * with all clock ops implemented. Instead, we'll just create a clock that can + * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock + * framework that we're doing things behind its back. This should be sufficient + * to create nice clean device tree bindings and later (if needed) we can try + * re-architecting SDHCI if we see some benefit to it. + * + * Return: 0 on success and error value on error + */ +static int arasan_sdhci_register_sdclk(struct arasan_sdhci_host *sdhci_arasan, + struct clk *clk_xin, + struct device *dev) +{ + struct device_node *np = dev->of_node; + u32 num_clks = 0; + int ret; + + /* Providing a clock to the PHY is optional; no error if missing */ + if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0) + return 0; + + ret = arasan_sdhci_register_sdcardclk(sdhci_arasan, clk_xin, dev); + if (ret) + return ret; + + if (num_clks) + return arasan_sdhci_register_sampleclk(sdhci_arasan, clk_xin, + dev); + + return 0; +} + +/** + * arasan_dt_parse_clk_phases - Read Clock Delay values from DT + * + * @dev: Pointer to our struct device. + * @clk_data: Pointer to the Clock Data structure + * + * Called at initialization to parse the values of Clock Delays. + */ +static void arasan_dt_parse_clk_phases(struct device *dev, + struct sdhci_arasan_clk_data *clk_data) { - struct device_node *np = dev->device_node; + u32 mio_bank = 0; + int i; + + /* + * This has been kept as a pointer and is assigned a function here. + * So that different controller variants can assign their own handling + * function. + */ + clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; + + if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { + u32 zynqmp_iclk_phase[ZYNQMP_CLK_PHASES + 1] = ZYNQMP_ICLK_PHASE; + u32 zynqmp_oclk_phase[ZYNQMP_CLK_PHASES + 1] = ZYNQMP_OCLK_PHASE; + + of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank); + if (mio_bank == 2) { + zynqmp_oclk_phase[ZYNQMP_CLK_PHASE_UHS_SDR104] = 90; + zynqmp_oclk_phase[ZYNQMP_CLK_PHASE_HS200] = 90; + } + + for (i = 0; i <= ZYNQMP_CLK_PHASES; i++) { + clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i]; + clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i]; + } + } + + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, + "clk-phase-legacy"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, + "clk-phase-mmc-hs"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, + "clk-phase-sd-hs"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, + "clk-phase-uhs-sdr12"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, + "clk-phase-uhs-sdr25"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, + "clk-phase-uhs-sdr50"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, + "clk-phase-uhs-sdr104"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, + "clk-phase-uhs-ddr50"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, + "clk-phase-mmc-ddr52"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, + "clk-phase-mmc-hs200"); + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, + "clk-phase-mmc-hs400"); +} + +static int arasan_sdhci_probe(struct device *dev) +{ + struct device_node *np = dev->of_node; struct arasan_sdhci_host *arasan_sdhci; struct clk *clk_xin, *clk_ahb; struct resource *iores; @@ -280,6 +758,12 @@ static int arasan_sdhci_probe(struct device_d *dev) if (of_property_read_bool(np, "no-1-8-v")) arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_NO_1_8_V; + if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { + if (IS_ENABLED(CONFIG_MCI_TUNING)) + mci->execute_tuning = arasan_zynqmp_execute_tuning; + arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN; + } + arasan_sdhci->sdhci.base = IOMEM(iores->start); arasan_sdhci->sdhci.mci = mci; mci->send_cmd = arasan_sdhci_send_cmd; @@ -289,9 +773,29 @@ static int arasan_sdhci_probe(struct device_d *dev) mci->card_write_protected = arasan_sdhci_card_write_protected; mci->hw_dev = dev; - mci->f_max = clk_get_rate(clk_xin); + /* + * clk_rates on ZynqMP are rounded wrong. For HS200 clk_get_rate retunrs + * 199999998 instead of 200000000 + */ + if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) + mci->f_max = 200000000; + else + mci->f_max = clk_get_rate(clk_xin); + mci->f_min = 50000000 / 256; + if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { + arasan_sdhci->sdcardclk_ops = &zynqmp_sdcardclk_ops; + arasan_sdhci->sampleclk_ops = &zynqmp_sampleclk_ops; + } else { + arasan_sdhci->sdcardclk_ops = &arasan_sdcardclk_ops; + arasan_sdhci->sampleclk_ops = &arasan_sampleclk_ops; + } + + arasan_sdhci_register_sdclk(arasan_sdhci, clk_xin, dev); + + arasan_dt_parse_clk_phases(dev, &arasan_sdhci->clk_data); + /* parse board supported bus width capabilities */ mci_of_parse(&arasan_sdhci->mci); @@ -306,8 +810,9 @@ static __maybe_unused struct of_device_id arasan_sdhci_compatible[] = { { .compatible = "arasan,sdhci-8.9a" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, arasan_sdhci_compatible); -static struct driver_d arasan_sdhci_driver = { +static struct driver arasan_sdhci_driver = { .name = "arasan-sdhci", .probe = arasan_sdhci_probe, .of_compatible = DRV_OF_COMPAT(arasan_sdhci_compatible), diff --git a/drivers/mci/atmel-mci-regs.h b/drivers/mci/atmel-mci-regs.h index 045c1a9f38..44db8a9dff 100644 --- a/drivers/mci/atmel-mci-regs.h +++ b/drivers/mci/atmel-mci-regs.h @@ -155,7 +155,7 @@ struct atmel_mci_caps { struct atmel_mci { struct mci_host mci; void __iomem *regs; - struct device_d *hw_dev; + struct device *hw_dev; struct clk *clk; u32 datasize; @@ -190,7 +190,7 @@ static inline unsigned int atmci_convert_chksize(unsigned int maxburst) } void atmci_common_set_ios(struct atmel_mci *host, struct mci_ios *ios); -int atmci_reset(struct mci_host *mci, struct device_d *mci_dev); +int atmci_reset(struct mci_host *mci, struct device *mci_dev); int atmci_common_request(struct atmel_mci *host, struct mci_cmd *cmd, struct mci_data *data); void atmci_get_cap(struct atmel_mci *host); diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c index 129480aa55..082ce842f7 100644 --- a/drivers/mci/atmel-sdhci-common.c +++ b/drivers/mci/atmel-sdhci-common.c @@ -13,7 +13,7 @@ #include <mci.h> #include <linux/bitfield.h> -#include <mach/early_udelay.h> +#include <mach/at91/early_udelay.h> #ifdef __PBL__ #define udelay early_udelay @@ -39,7 +39,7 @@ static inline struct at91_sdhci *to_priv(struct sdhci *sdhci) void at91_sdhci_host_capability(struct at91_sdhci *host, unsigned *voltages) { - u16 caps; + u32 caps; caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES); @@ -89,52 +89,18 @@ exit: return is_inserted; } -static int at91_sdhci_wait_for_done(struct at91_sdhci *host, u32 mask) -{ - struct sdhci *sdhci = &host->sdhci; - u32 status; - int ret; - - ret = sdhci_read32_poll_timeout(sdhci, SDHCI_INT_STATUS, status, - (status & mask) == mask || (status & SDHCI_INT_ERROR), - USEC_PER_SEC); - - if (ret < 0) { - dev_err(host->dev, "SDHCI timeout while waiting for done\n"); - return ret; - } - - if (status & SDHCI_INT_TIMEOUT) - return -ETIMEDOUT; - - if (status & SDHCI_INT_ERROR) { - dev_err(host->dev, "SDHCI_INT_STATUS: 0x%08x\n", status); - return -EPERM; - } - - return status & 0xFFFF; -} - int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd, struct mci_data *data) { unsigned command, xfer; struct sdhci *sdhci = &host->sdhci; - u32 mask, state; + u32 mask; int status; int ret; - /* Wait for idle before next command */ - mask = SDHCI_CMD_INHIBIT_CMD; - if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION) - mask |= SDHCI_CMD_INHIBIT_DATA; - - ret = sdhci_read32_poll_timeout(sdhci, SDHCI_PRESENT_STATE, state, - !(state & mask), 100 * USEC_PER_MSEC); - if (ret) { - dev_err(host->dev, "timeout while waiting for idle\n"); + ret = sdhci_wait_idle_data(&host->sdhci, cmd); + if (ret) return ret; - } sdhci_write32(sdhci, SDHCI_INT_STATUS, ~0U); @@ -158,7 +124,7 @@ int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd, sdhci_write32(sdhci, SDHCI_ARGUMENT, cmd->cmdarg); sdhci_write16(sdhci, SDHCI_COMMAND, command); - status = at91_sdhci_wait_for_done(host, mask); + status = sdhci_wait_for_done(&host->sdhci, mask); if (status < 0) goto error; @@ -219,17 +185,12 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock) struct sdhci *sdhci = &host->sdhci; unsigned clk = 0, clk_div; unsigned reg; - u32 present_mask, caps, caps_clk_mult; + u32 caps, caps_clk_mult; int ret; - present_mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA; - ret = sdhci_read32_poll_timeout(sdhci, SDHCI_PRESENT_STATE, reg, - !(reg & present_mask), - 100 * USEC_PER_MSEC); - if (ret) { - dev_warn(host->dev, "Timeout waiting for CMD and DAT Inhibit bits\n"); + ret = sdhci_wait_idle_data(&host->sdhci, NULL); + if (ret) return ret; - } sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, 0); diff --git a/drivers/mci/atmel-sdhci-pbl.c b/drivers/mci/atmel-sdhci-pbl.c index 2c5f107abd..f5a7279bff 100644 --- a/drivers/mci/atmel-sdhci-pbl.c +++ b/drivers/mci/atmel-sdhci-pbl.c @@ -11,10 +11,10 @@ #include <pbl/bio.h> #include <mci.h> #include <debug_ll.h> -#include <mach/xload.h> +#include <mach/at91/xload.h> #include "atmel-sdhci.h" -#include <mach/early_udelay.h> +#include <mach/at91/early_udelay.h> #ifdef __PBL__ #define udelay early_udelay diff --git a/drivers/mci/atmel-sdhci.c b/drivers/mci/atmel-sdhci.c index 380a79d33e..c124e736bb 100644 --- a/drivers/mci/atmel-sdhci.c +++ b/drivers/mci/atmel-sdhci.c @@ -40,7 +40,7 @@ static void at91_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) at91_sdhci_set_ios(&to_priv(mci)->host, ios); } -static int at91_sdhci_mci_init(struct mci_host *mci, struct device_d *dev) +static int at91_sdhci_mci_init(struct mci_host *mci, struct device *dev) { struct at91_sdhci_priv *priv = to_priv(mci); struct sdhci *sdhci = &priv->host.sdhci; @@ -99,7 +99,7 @@ static int at91_sdhci_card_present(struct mci_host *mci) return at91_sdhci_is_card_inserted(&to_priv(mci)->host); } -static int at91_sdhci_probe(struct device_d *dev) +static int at91_sdhci_probe(struct device *dev) { struct at91_sdhci_priv *priv; struct resource *iores; @@ -135,7 +135,7 @@ static int at91_sdhci_probe(struct device_d *dev) * if SDCAL pin is wrongly connected, we must enable * the analog calibration cell permanently. */ - priv->cal_always_on = of_property_read_bool(dev->device_node, + priv->cal_always_on = of_property_read_bool(dev->of_node, "microchip,sdcal-inverted"); at91_sdhci_mmio_init(&priv->host, IOMEM(iores->start)); @@ -162,8 +162,9 @@ static const struct of_device_id at91_sdhci_dt_match[] = { { .compatible = "microchip,sam9x60-sdhci" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, at91_sdhci_dt_match); -static struct driver_d at91_sdhci_driver = { +static struct driver at91_sdhci_driver = { .name = "sdhci-at91", .of_compatible = DRV_OF_COMPAT(at91_sdhci_dt_match), .probe = at91_sdhci_probe, diff --git a/drivers/mci/atmel-sdhci.h b/drivers/mci/atmel-sdhci.h index 7032294647..8f07de340d 100644 --- a/drivers/mci/atmel-sdhci.h +++ b/drivers/mci/atmel-sdhci.h @@ -11,7 +11,7 @@ struct at91_sdhci { struct sdhci sdhci; - struct device_d *dev; + struct device *dev; void __iomem *base; u32 caps_max_clock; }; diff --git a/drivers/mci/atmel_mci.c b/drivers/mci/atmel_mci.c index e676c1bd5c..9021dba0f8 100644 --- a/drivers/mci/atmel_mci.c +++ b/drivers/mci/atmel_mci.c @@ -31,7 +31,7 @@ static int atmci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, return atmci_common_request(host, cmd, data); } -static void atmci_info(struct device_d *mci_dev) +static void atmci_info(struct device *mci_dev) { struct atmel_mci *host = mci_dev->priv; @@ -67,11 +67,11 @@ static int atmci_card_present(struct mci_host *mci) return ret == 0 ? 1 : 0; } -static int atmci_probe(struct device_d *hw_dev) +static int atmci_probe(struct device *hw_dev) { struct resource *iores; struct atmel_mci *host; - struct device_node *np = hw_dev->device_node; + struct device_node *np = hw_dev->of_node; struct atmel_mci_platform_data *pd = hw_dev->platform_data; int ret; @@ -105,8 +105,8 @@ static int atmci_probe(struct device_d *hw_dev) for_each_child_of_node(np, cnp) { if (of_property_read_u32(cnp, "reg", &slot_id)) { - dev_warn(hw_dev, "reg property is missing for %s\n", - cnp->full_name); + dev_warn(hw_dev, "reg property is missing for %pOF\n", + cnp); continue; } @@ -151,6 +151,7 @@ static int atmci_probe(struct device_d *hw_dev) clk_enable(host->clk); atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_PWSDIS); atmci_writel(host, ATMCI_IDR, ~0UL); host->bus_hz = clk_get_rate(host->clk); clk_disable(host->clk); @@ -193,8 +194,9 @@ static __maybe_unused struct of_device_id atmci_compatible[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, atmci_compatible); -static struct driver_d atmci_driver = { +static struct driver atmci_driver = { .name = "atmel_mci", .probe = atmci_probe, .of_compatible = DRV_OF_COMPAT(atmci_compatible), diff --git a/drivers/mci/atmel_mci_common.c b/drivers/mci/atmel_mci_common.c index 5c9e6f9c4d..7b11e9134e 100644 --- a/drivers/mci/atmel_mci_common.c +++ b/drivers/mci/atmel_mci_common.c @@ -68,7 +68,17 @@ static void atmci_set_clk_rate(struct atmel_mci *host, clock_min, host->bus_hz / (2 * 256)); clkdiv = 255; } - host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); + + /* + * Older Atmels without CLKODD have the block length + * in the upper 16 bits of both MCI_MR and MCI_BLKR + * + * To avoid intermittent zeroing of the block length, + * just hardcode 512 here and have atmci_setup_data() + * change it as necessary. + */ + + host->mode_reg = ATMCI_MR_CLKDIV(clkdiv) | ATMCI_BLKLEN(512); } dev_dbg(host->hw_dev, "atmel_set_clk_rate: clkIn=%ld clkIos=%d divider=%d\n", @@ -90,8 +100,8 @@ static int atmci_poll_status(struct atmel_mci *host, u32 mask) u32 stat; int ret; - ret = read_poll_timeout(atmci_readl, stat, (stat & mask), SECOND, host, - ATMCI_SR); + ret = read_poll_timeout(atmci_readl, stat, (stat & mask), USEC_PER_SEC, + host, ATMCI_SR); if (ret < 0) { dev_err(host->hw_dev, "timeout\n"); host->need_reset = true; @@ -220,7 +230,7 @@ static void atmci_setup_data(struct atmel_mci *host, struct mci_data *data) host->data = data; - dev_dbg(host->hw_dev, "atmel_setup_data: nob=%d blksz=%d\n", + dev_vdbg(host->hw_dev, "atmel_setup_data: nob=%d blksz=%d\n", nob, blksz); atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(nob) @@ -315,7 +325,7 @@ static int atmci_start_cmd(struct atmel_mci *host, struct mci_cmd *cmd, flags |= ATMCI_CMDR_RSPTYP_NONE; break; default: - dev_err(host->hw_dev, "unhandled response type 0x%x\n", + dev_dbg(host->hw_dev, "unhandled response type 0x%x\n", cmd->resp_type); return -EINVAL; } @@ -329,7 +339,7 @@ static int atmci_start_cmd(struct atmel_mci *host, struct mci_cmd *cmd, } /** init the host interface */ -int atmci_reset(struct mci_host *mci, struct device_d *mci_dev) +int atmci_reset(struct mci_host *mci, struct device *mci_dev) { struct atmel_mci *host = to_mci_host(mci); @@ -437,7 +447,7 @@ void atmci_get_cap(struct atmel_mci *host) version = atmci_readl(host, ATMCI_VERSION) & 0x00000fff; host->version = version; - dev_info(host->hw_dev, "version: 0x%x\n", version); + dev_dbg(host->hw_dev, "version: 0x%x\n", version); host->caps.has_cfg_reg = 0; host->caps.has_highspeed = 0; diff --git a/drivers/mci/atmel_mci_pbl.c b/drivers/mci/atmel_mci_pbl.c index 65d8b3632a..bd4faa4de5 100644 --- a/drivers/mci/atmel_mci_pbl.c +++ b/drivers/mci/atmel_mci_pbl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include <common.h> -#include <mach/xload.h> +#include <mach/at91/xload.h> #include <mci.h> #include "atmel-mci-regs.h" @@ -106,6 +106,7 @@ int at91_mci_bio_init(struct pbl_bio *bio, void __iomem *base, else host->sdc_reg = ATMCI_SDCSEL_SLOT_A; + atmci_writel(host, ATMCI_CR, ATMCI_CR_PWSDIS); atmci_writel(host, ATMCI_DTOR, 0x7f); atmci_common_set_ios(host, &ios); diff --git a/drivers/mci/bcm2835-sdhost.c b/drivers/mci/bcm2835-sdhost.c index 7e19c6eb1e..2b1336a7d3 100644 --- a/drivers/mci/bcm2835-sdhost.c +++ b/drivers/mci/bcm2835-sdhost.c @@ -135,7 +135,7 @@ static inline struct bcm2835_host *to_bcm2835_host(struct mci_host *mci) return container_of(mci, struct bcm2835_host, mci); } -static int bcm2835_sdhost_init(struct mci_host *mci, struct device_d *dev) +static int bcm2835_sdhost_init(struct mci_host *mci, struct device *dev) { struct bcm2835_host *host = to_bcm2835_host(mci); u32 temp; @@ -579,7 +579,7 @@ static void bcm2835_set_ios(struct mci_host *mci, struct mci_ios *ios) writel(hcfg, host->regs + SDHCFG); } -static int bcm2835_sdhost_probe(struct device_d *dev) +static int bcm2835_sdhost_probe(struct device *dev) { struct bcm2835_host *host; struct resource *iores; @@ -619,8 +619,9 @@ static __maybe_unused struct of_device_id bcm2835_sdhost_compatible[] = { { .compatible = "brcm,bcm2835-sdhost" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, bcm2835_sdhost_compatible); -static struct driver_d bcm2835_sdhost_driver = { +static struct driver bcm2835_sdhost_driver = { .name = "bcm2835-sdhost", .probe = bcm2835_sdhost_probe, .of_compatible = DRV_OF_COMPAT(bcm2835_sdhost_compatible), diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c index 7581511285..d37046ad31 100644 --- a/drivers/mci/dove-sdhci.c +++ b/drivers/mci/dove-sdhci.c @@ -57,39 +57,26 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask) static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) { - u16 val; u32 command, xfer; - u64 start; int ret; unsigned int num_bytes = 0; struct dove_sdhci *host = priv_from_mci_host(mci); - sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); - - /* Do not wait for CMD_INHIBIT_DAT on stop commands */ - if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) - val = SDHCI_CMD_INHIBIT_CMD; - else - val = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA; + ret = sdhci_wait_idle_data(&host->sdhci, cmd); + if (ret) + return ret; - /* Wait for bus idle */ - start = get_time_ns(); - while (1) { - if (!(sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE) & val)) - break; - if (is_timeout(start, 10 * MSECOND)) { - dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n"); - return -ETIMEDOUT; - } - } + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); /* setup transfer data */ if (data) { num_bytes = data->blocks * data->blocksize; if (data->flags & MMC_DATA_READ) - sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->dest); + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, + lower_32_bits(virt_to_phys(data->dest))); else - sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->src); + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, + lower_32_bits(virt_to_phys(data->src))); sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K | SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize)); sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks); @@ -97,10 +84,12 @@ static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_device((unsigned long)data->src, + dma_sync_single_for_device(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->src)), num_bytes, DMA_TO_DEVICE); else - dma_sync_single_for_device((unsigned long)data->dest, + dma_sync_single_for_device(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->dest)), num_bytes, DMA_FROM_DEVICE); } @@ -126,11 +115,13 @@ static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, if (data) { if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_cpu((unsigned long)data->src, + dma_sync_single_for_cpu(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->src)), num_bytes, DMA_TO_DEVICE); else - dma_sync_single_for_cpu((unsigned long)data->dest, - num_bytes, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->dest)), + num_bytes, DMA_FROM_DEVICE); ret = dove_sdhci_wait_for_done(host, SDHCI_INT_XFER_COMPLETE); if (ret) { @@ -189,6 +180,8 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) case MMC_BUS_WIDTH_4: val |= SDHCI_CTRL_4BITBUS; break; + case MMC_BUS_WIDTH_1: + break; } if (ios->clock > 26000000) @@ -218,7 +211,7 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_CLOCK_CARD_EN); } -static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev) +static int dove_sdhci_mci_init(struct mci_host *mci, struct device *dev) { u64 start; struct dove_sdhci *host = priv_from_mci_host(mci); @@ -271,7 +264,7 @@ static void dove_sdhci_set_mci_caps(struct dove_sdhci *host) host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA; } -static int dove_sdhci_probe(struct device_d *dev) +static int dove_sdhci_probe(struct device *dev) { struct dove_sdhci *host; int ret; @@ -298,8 +291,9 @@ static struct of_device_id dove_sdhci_dt_ids[] = { { .compatible = "marvell,dove-sdhci", }, { } }; +MODULE_DEVICE_TABLE(of, dove_sdhci_dt_ids); -static struct driver_d dove_sdhci_driver = { +static struct driver dove_sdhci_driver = { .name = "dove-sdhci", .probe = dove_sdhci_probe, .of_compatible = DRV_OF_COMPAT(dove_sdhci_dt_ids), diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c index 86c4f43e88..c49e839c94 100644 --- a/drivers/mci/dw_mmc.c +++ b/drivers/mci/dw_mmc.c @@ -26,7 +26,7 @@ struct dwmci_host { struct mci_host mci; - struct device_d *dev; + struct device *dev; struct clk *clk_biu, *clk_ciu; void *ioaddr; unsigned int fifo_size_bytes; @@ -496,7 +496,7 @@ static int dwmci_card_present(struct mci_host *mci) return 1; } -static int dwmci_init(struct mci_host *mci, struct device_d *dev) +static int dwmci_init(struct mci_host *mci, struct device *dev) { struct dwmci_host *host = to_dwmci_host(mci); uint32_t fifo_size; @@ -528,8 +528,8 @@ static int dwmci_init(struct mci_host *mci, struct device_d *dev) /* * If fifo-depth property is set, use this value */ - if (!of_property_read_u32(host->mci.hw_dev->device_node, - "fifo-depth", &fifo_size)) { + if (!of_property_read_u32(host->mci.hw_dev->of_node, + "fifo-depth", &fifo_size)) { host->fifo_size_bytes = fifo_size; dev_dbg(host->mci.hw_dev, "Using fifo-depth=%u\n", host->fifo_size_bytes); @@ -547,7 +547,7 @@ static int dwmci_init(struct mci_host *mci, struct device_d *dev) return 0; } -static int dw_mmc_probe(struct device_d *dev) +static int dw_mmc_probe(struct device *dev) { struct reset_control *rst; struct resource *iores; @@ -570,7 +570,7 @@ static int dw_mmc_probe(struct device_d *dev) clk_enable(host->clk_biu); clk_enable(host->clk_ciu); - rst = reset_control_get(dev, "reset"); + rst = reset_control_get_optional(dev, "reset"); if (IS_ERR(rst)) { dev_warn(dev, "error claiming reset: %pe\n", rst); } else if (rst) { @@ -603,22 +603,23 @@ static int dw_mmc_probe(struct device_d *dev) host->ciu_div = pdata->ciu_div; host->mci.host_caps &= ~MMC_CAP_BIT_DATA_MASK; host->mci.host_caps |= pdata->bus_width_caps; - } else if (dev->device_node) { - of_property_read_u32(dev->device_node, "dw-mshc-ciu-div", - &host->ciu_div); + } else if (dev->of_node) { + of_property_read_u32(dev->of_node, "dw-mshc-ciu-div", + &host->ciu_div); } /* divider is 0 based in pdata and 1 based in our private struct */ host->ciu_div++; - if (of_device_is_compatible(dev->device_node, - "rockchip,rk2928-dw-mshc")) + if (of_device_is_compatible(dev->of_node, + "rockchip,rk2928-dw-mshc")) host->pwren_value = 0; else host->pwren_value = 1; - if (of_device_is_compatible(dev->device_node, "starfive,jh7100-dw-mshc")) - of_property_read_u32(dev->device_node, "clock-frequency", &host->clkrate); + if (of_device_is_compatible(dev->of_node, "starfive,jh7100-dw-mshc")) + of_property_read_u32(dev->of_node, "clock-frequency", + &host->clkrate); if (!host->clkrate) host->clkrate = clk_get_rate(host->clk_ciu); @@ -647,8 +648,9 @@ static __maybe_unused struct of_device_id dw_mmc_compatible[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, dw_mmc_compatible); -static struct driver_d dw_mmc_driver = { +static struct driver dw_mmc_driver = { .name = "dw_mmc", .probe = dw_mmc_probe, .of_compatible = DRV_OF_COMPAT(dw_mmc_compatible), diff --git a/drivers/mci/dwcmshc-sdhci.c b/drivers/mci/dwcmshc-sdhci.c new file mode 100644 index 0000000000..7b367e02ee --- /dev/null +++ b/drivers/mci/dwcmshc-sdhci.c @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2019 Yann Sionneau, Kalray Inc. +// SPDX-FileCopyrightText: 2023 Jules Maselbas, Kalray Inc. + +#include <clock.h> +#include <common.h> +#include <init.h> +#include <io.h> +#include <dma.h> +#include <malloc.h> +#include <mci.h> +#include <of_device.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include "sdhci.h" + +#define tx_delay_static_cfg(delay) (delay << 5) +#define tx_tuning_clk_sel(delay) (delay) + +#define DWCMSHC_GPIO_OUT 0x34 /* offset from vendor specific area */ +#define CARD_STATUS_MASK (0x1e00) +#define CARD_STATUS_TRAN (4 << 9) + +static int do_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data); + +struct dwcmshc_host { + struct mci_host mci; + struct sdhci sdhci; + int vendor_specific_area; + const struct dwcmshc_callbacks *cb; +}; + +struct dwcmshc_callbacks { + void (*init)(struct mci_host *mci, struct device *dev); +}; + +static inline struct dwcmshc_host *priv_from_mci_host(struct mci_host *h) +{ + return container_of(h, struct dwcmshc_host, mci); +} + +static void mci_setup_cmd(struct mci_cmd *p, unsigned int cmd, unsigned int arg, + unsigned int response) +{ + p->cmdidx = cmd; + p->cmdarg = arg; + p->resp_type = response; +} + +static int do_abort_sequence(struct mci_host *mci, struct mci_cmd *current_cmd) +{ + int ret = 0; + struct dwcmshc_host *host = priv_from_mci_host(mci); + struct mci_cmd cmd; + u64 start; + + mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, MMC_RSP_R1b); + ret = do_send_cmd(mci, &cmd, NULL); + if (ret) { + dev_err(host->mci.hw_dev, "Abort failed at first cmd12!\n"); + goto out; + } + mci_setup_cmd(&cmd, MMC_CMD_SEND_STATUS, mci->mci->rca << 16, + MMC_RSP_R1); + ret = do_send_cmd(mci, &cmd, NULL); + if (ret) { + dev_err(host->mci.hw_dev, "Abort failed at first cmd13!\n"); + goto out; + } + + if ((cmd.response[0] & CARD_STATUS_MASK) == CARD_STATUS_TRAN) + goto out; /* All is OK! */ + + mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, MMC_RSP_R1b); + ret = do_send_cmd(mci, &cmd, NULL); + if (ret) { + dev_err(host->mci.hw_dev, "Abort failed at second cmd12!\n"); + goto out; + } + + mci_setup_cmd(&cmd, MMC_CMD_SEND_STATUS, mci->mci->rca << 16, + MMC_RSP_R1); + ret = do_send_cmd(mci, &cmd, NULL); + if (ret) { + dev_err(host->mci.hw_dev, "Abort failed at second cmd13!\n"); + goto out; + } + + if ((cmd.response[0] & CARD_STATUS_MASK) != CARD_STATUS_TRAN) { + dev_err(host->mci.hw_dev, + "Abort sequence failed to put card in TRAN state!\n"); + ret = -EIO; + goto out; + } + +out: + /* Perform SW reset if in abort sequence */ + sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, + SDHCI_RESET_DATA | SDHCI_RESET_CMD); + start = get_time_ns(); + while (sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) != 0) { + if (is_timeout(start, 50 * MSECOND)) { + dev_err(host->mci.hw_dev, + "SDHCI data reset timeout\n"); + break; + } + } + + return ret; +} + +static int dwcmshc_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, + struct mci_data *data) +{ + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + return do_abort_sequence(mci, cmd); + return do_send_cmd(mci, cmd, data); +} + +static int do_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, + struct mci_data *data) +{ + struct dwcmshc_host *host = priv_from_mci_host(mci); + dma_addr_t dma = SDHCI_NO_DMA; + u32 mask, command, xfer; + int ret; + + /* Do not wait for CMD_INHIBIT_DAT on stop commands */ + mask = SDHCI_CMD_INHIBIT_CMD; + if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION) + mask |= SDHCI_CMD_INHIBIT_DATA; + + /* Wait for bus idle */ + ret = wait_on_timeout(50 * MSECOND, + !(sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE) & mask)); + if (ret) { + dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n"); + return -ETIMEDOUT; + } + + if (data) + dev_dbg(host->mci.hw_dev, "cmd %d arg %d bcnt %d bsize %d\n", + cmd->cmdidx, cmd->cmdarg, data->blocks, data->blocksize); + else + dev_dbg(host->mci.hw_dev, "cmd %d arg %d\n", cmd->cmdidx, cmd->cmdarg); + + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); + + sdhci_setup_data_dma(&host->sdhci, data, &dma); + + sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe); + + sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, + dma == SDHCI_NO_DMA ? false : true, + &command, &xfer); + + sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer); + + sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); + sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); + + ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE); + if (ret) + goto error; + + sdhci_read_response(&host->sdhci, cmd); + + ret = sdhci_transfer_data(&host->sdhci, data, dma); +error: + if (ret) { + sdhci_reset(&host->sdhci, SDHCI_RESET_CMD); + sdhci_reset(&host->sdhci, SDHCI_RESET_DATA); + } + + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); + return ret; +} + +static u16 dwcmshc_get_clock_divider(struct dwcmshc_host *host, u32 reqclk) +{ + u16 div; + + for (div = 1; div < SDHCI_MAX_DIV_SPEC_300; div += 2) + if ((host->sdhci.max_clk / div) <= reqclk) + break; + div /= 2; + + return div; +} + +static void dwcmshc_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) +{ + struct dwcmshc_host *host = priv_from_mci_host(mci); + u16 val; + + dev_dbg(host->mci.hw_dev, + "%s: clock = %u, bus-width = %d, timing = %02x\n", + __func__, ios->clock, ios->bus_width, ios->timing); + + /* stop clock */ + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0); + + if (!ios->clock) + return; + + /* enable bus power */ + val = SDHCI_BUS_VOLTAGE_330; + sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN); + udelay(400); + + /* set bus width */ + sdhci_set_bus_width(&host->sdhci, ios->bus_width); + + val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL); + if (ios->clock > 26000000) + val |= SDHCI_CTRL_HISPD; + else + val &= ~SDHCI_CTRL_HISPD; + sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val); + + /* set bus clock */ + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0); + val = dwcmshc_get_clock_divider(host, ios->clock); + val = SDHCI_CLOCK_INT_EN | SDHCI_FREQ_SEL(val) | ((val & 0x300) >> 2); + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val); + + /* wait for internal clock stable */ + if (wait_on_timeout(20 * MSECOND, + sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) + & SDHCI_CLOCK_INT_STABLE)) { + dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n"); + return; + } + + /* enable bus clock */ + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_CLOCK_CARD_EN); +} + +static int dwcmshc_mci_init(struct mci_host *mci, struct device *dev) +{ + struct dwcmshc_host *host = priv_from_mci_host(mci); + u16 ctrl2; + + /* reset mshci controller */ + sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL); + + /* wait for reset completion */ + if (wait_on_timeout(100 * MSECOND, + (sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) + & SDHCI_RESET_ALL) == 0)) { + dev_err(dev, "SDHCI reset timeout\n"); + return -ETIMEDOUT; + } + + sdhci_write16(&host->sdhci, SDHCI_INT_ERROR_ENABLE, ~0); + sdhci_write16(&host->sdhci, SDHCI_INT_ENABLE, ~0); + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); + sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, ~0); + + sdhci_enable_v4_mode(&host->sdhci); + + dev_dbg(host->mci.hw_dev, "host version4: %s\n", + ctrl2 & SDHCI_CTRL_V4_MODE ? "enabled" : "disabled"); + + if (host->cb && host->cb->init) + host->cb->init(mci, dev); + + return 0; +} + +static int dwcmshc_detect(struct device *dev) +{ + struct dwcmshc_host *host = dev->priv; + + return mci_detect_card(&host->mci); +} + +static int dwcmshc_mci_card_present(struct mci_host *mci) +{ + struct dwcmshc_host *host = priv_from_mci_host(mci); + u32 pstate; + + pstate = sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE); + return pstate & SDHCI_CARD_PRESENT; +} + +static void dwcmshc_set_dma_mask(struct device *dev) +{ + struct dwcmshc_host *host = dev->priv; + + if (host->sdhci.caps & SDHCI_CAN_64BIT_V4) + dma_set_mask(dev, DMA_BIT_MASK(64)); + else + dma_set_mask(dev, DMA_BIT_MASK(32)); +} + +static int dwcmshc_probe(struct device *dev) +{ + const struct dwcmshc_callbacks *dwcmshc_cb = + of_device_get_match_data(dev); + struct dwcmshc_host *host; + struct resource *iores; + struct mci_host *mci; + struct clk *clk; + int ret; + + host = xzalloc(sizeof(*host)); + mci = &host->mci; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) { + ret = PTR_ERR(iores); + goto err_mem_req; + } + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto err_clk_get; + } + clk_enable(clk); + + host->sdhci.base = IOMEM(iores->start); + host->sdhci.mci = mci; + host->sdhci.max_clk = clk_get_rate(clk); + host->cb = dwcmshc_cb; + + mci->hw_dev = dev; + mci->init = dwcmshc_mci_init; + mci->set_ios = dwcmshc_mci_set_ios; + mci->send_cmd = dwcmshc_mci_send_cmd; + mci->card_present = dwcmshc_mci_card_present; + + sdhci_setup_host(&host->sdhci); + + mci->max_req_size = 0x8000; + /* + * Let's first initialize f_max to the DT clock freq + * Then mci_of_parse can override if with the content + * of the 'max-frequency' DT property if it is present. + * Then we can finish by computing the f_min. + */ + mci->f_max = clk_get_rate(clk); + mci_of_parse(&host->mci); + mci->f_min = mci->f_max / SDHCI_MAX_DIV_SPEC_300; + + dev->priv = host; + dev->detect = dwcmshc_detect; + + dwcmshc_set_dma_mask(dev); + + dev_dbg(host->mci.hw_dev, "host controller version: %u\n", + host->sdhci.version); + + host->vendor_specific_area = sdhci_read32(&host->sdhci, + SDHCI_P_VENDOR_SPEC_AREA); + host->vendor_specific_area &= SDHCI_P_VENDOR_SPEC_AREA_MASK; + + ret = mci_register(&host->mci); + if (ret) + goto err_register; + + return ret; + +err_register: + clk_disable(clk); + clk_put(clk); +err_clk_get: + release_region(iores); +err_mem_req: + free(host); + + return ret; +} + +static void dwcmshc_coolidgev2_init(struct mci_host *mci, struct device *dev) +{ + struct dwcmshc_host *host = priv_from_mci_host(mci); + + /* configure TX delay to set correct setup/hold for Coolidge V2 */ + sdhci_write32(&host->sdhci, + host->vendor_specific_area + DWCMSHC_GPIO_OUT, + tx_delay_static_cfg(0xf) | tx_tuning_clk_sel(4)); +} + +struct dwcmshc_callbacks kalray_coolidgev2_callbacks = { + .init = dwcmshc_coolidgev2_init, +}; + +static struct of_device_id dwcmshc_dt_ids[] = { + { .compatible = "snps,dwcmshc-sdhci", }, + { .compatible = "kalray,coolidge-v2-dwcmshc-sdhci", .data = &kalray_coolidgev2_callbacks }, + { } +}; + +static struct driver dwcmshc_driver = { + .name = "dwcmshc-sdhci", + .probe = dwcmshc_probe, + .of_compatible = DRV_OF_COMPAT(dwcmshc_dt_ids), +}; +device_platform_driver(dwcmshc_driver); diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c index 27293e44b7..3d93889143 100644 --- a/drivers/mci/imx-esdhc-common.c +++ b/drivers/mci/imx-esdhc-common.c @@ -59,19 +59,14 @@ static int esdhc_setup_data(struct fsl_esdhc_host *host, struct mci_data *data, u32 wml_value; wml_value = data->blocksize / 4; + if (wml_value > 0x80) + wml_value = 0x80; - if (data->flags & MMC_DATA_READ) { - if (wml_value > 0x10) - wml_value = 0x10; - + if (data->flags & MMC_DATA_READ) esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value); - } else { - if (wml_value > 0x80) - wml_value = 0x80; - + else esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK, wml_value << 16); - } host->sdhci.sdma_boundary = 0; @@ -160,6 +155,7 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd, mixctrl = xfertyp; /* Keep the bits 22-25 of the register as is */ mixctrl |= (sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL) & (0xF << 22)); + mixctrl |= mci_timing_is_ddr(host->sdhci.timing) ? MIX_CTRL_DDREN : 0; sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl); } diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c index c81eba5b9d..5b1d9a3cf4 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -8,14 +8,20 @@ #include <linux/sizes.h> #include <asm/sections.h> #include <asm/cache.h> -#include <mach/xload.h> +#include <mach/imx/xload.h> +#include <firmware.h> +#include <asm/atf_common.h> #ifdef CONFIG_ARCH_IMX -#include <mach/atf.h> -#include <mach/imx6-regs.h> -#include <mach/imx7-regs.h> -#include <mach/imx8mq-regs.h> -#include <mach/imx8mm-regs.h> -#include <mach/imx-header.h> +#include <mach/imx/atf.h> +#include <mach/imx/imx6-regs.h> +#include <mach/imx/imx7-regs.h> +#include <mach/imx/imx8mq-regs.h> +#include <mach/imx/imx8mm-regs.h> +#include <mach/imx/imx-header.h> +#endif +#ifdef CONFIG_ARCH_LAYERSCAPE +#include <mach/layerscape/xload.h> +#include <mach/layerscape/layerscape.h> #endif #include "sdhci.h" #include "imx-esdhc.h" @@ -101,122 +107,24 @@ static int esdhc_read_blocks(struct fsl_esdhc_host *host, void *dst, size_t len) } #ifdef CONFIG_ARCH_IMX -static int esdhc_search_header(struct fsl_esdhc_host *host, - struct imx_flash_header_v2 **header_pointer, - void *buffer, u32 *offset, u32 ivt_offset) +static int imx_read_blocks(void *dest, size_t len, void *priv) { - int ret; - int i, header_count = 1; - void *buf = buffer; - struct imx_flash_header_v2 *hdr; - - for (i = 0; i < header_count; i++) { - ret = esdhc_read_blocks(host, buf, - *offset + ivt_offset + SECTOR_SIZE); - if (ret) - return ret; - - hdr = buf + *offset + ivt_offset; - - if (!is_imx_flash_header_v2(hdr)) { - pr_debug("IVT header not found on SD card. " - "Found tag: 0x%02x length: 0x%04x " - "version: %02x\n", - hdr->header.tag, hdr->header.length, - hdr->header.version); - return -EINVAL; - } - - if (IS_ENABLED(CONFIG_ARCH_IMX8MQ) && - hdr->boot_data.plugin & PLUGIN_HDMI_IMAGE) { - /* - * In images that include signed HDMI - * firmware, first v2 header would be - * dedicated to that and would not contain any - * useful for us information. In order for us - * to pull the rest of the bootloader image - * in, we need to re-read header from SD/MMC, - * this time skipping anything HDMI firmware - * related. - */ - *offset += hdr->boot_data.size + hdr->header.length; - header_count++; - } - } - *header_pointer = hdr; - return 0; + return esdhc_read_blocks(priv, dest, len); } static int esdhc_load_image(struct fsl_esdhc_host *host, ptrdiff_t address, ptrdiff_t entry, u32 offset, u32 ivt_offset, bool start) { - - void *buf = (void *)address; - struct imx_flash_header_v2 *hdr = NULL; - int ret, len; - void __noreturn (*bb)(void); - unsigned int ofs; - - len = imx_image_size(); - len = ALIGN(len, SECTOR_SIZE); - - ret = esdhc_search_header(host, &hdr, buf, &offset, ivt_offset); - if (ret) - return ret; - - pr_debug("Check ok, loading image\n"); - - ofs = offset + hdr->entry - hdr->boot_data.start; - - if (entry != address) { - /* - * Passing entry different from address is interpreted - * as a request to place the image such that its entry - * point would be exactly at 'entry', that is: - * - * buf + ofs = entry - * - * solving the above for 'buf' gives us the - * adjustment that needs to be made: - * - * buf = entry - ofs - * - */ - if (WARN_ON(entry - ofs < address)) { - /* - * We want to make sure we won't try to place - * the start of the image before the beginning - * of the memory buffer we were given in - * address. - */ - return -EINVAL; - } - - buf = (void *)(entry - ofs); - } - - ret = esdhc_read_blocks(host, buf, offset + len); - if (ret) { - pr_err("Loading image failed with %d\n", ret); - return ret; - } - - pr_debug("Image loaded successfully\n"); - - if (!start) - return 0; - - bb = buf + ofs; - - sync_caches_for_execution(); - - bb(); + return imx_load_image(address, entry, offset, ivt_offset, start, + SECTOR_SIZE, imx_read_blocks, host); } static void imx_esdhc_init(struct fsl_esdhc_host *host, struct esdhc_soc_data *data) { + u32 mixctrl; + data->flags = ESDHC_FLAG_USDHC; host->socdata = data; esdhc_populate_sdhci(host); @@ -226,6 +134,10 @@ static void imx_esdhc_init(struct fsl_esdhc_host *host, FIELD_PREP(WML_WR_WML_MASK, SECTOR_WML) | FIELD_PREP(WML_RD_BRST_LEN, 16) | FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML)); + + mixctrl = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL); + if (mixctrl & MIX_CTRL_DDREN) + host->sdhci.timing = MMC_TIMING_MMC_DDR52; } static int imx8m_esdhc_init(struct fsl_esdhc_host *host, @@ -330,17 +242,17 @@ int imx7_esdhc_start_image(int instance) /** * imx8m_esdhc_load_image - Load and optionally start an image from USDHC controller * @instance: The USDHC controller instance (0..2) - * @start: Whether to directly start the loaded image + * @bl33: Where to load the bl33 barebox image * * This uses esdhc_start_image() to load an image from SD/MMC. It is * assumed that the image is the currently running barebox image (This * information is used to calculate the length of the image). The - * image is started afterwards. + * image is not started afterwards. * - * Return: If successful, this function does not return (if directly started) - * or 0. A negative error code is returned when this function fails. + * Return: If image successfully loaded, returns 0. + * A negative error code is returned when this function fails. */ -int imx8m_esdhc_load_image(int instance, bool start) +int imx8m_esdhc_load_image(int instance, void *bl33) { struct esdhc_soc_data data; struct fsl_esdhc_host host = { 0 }; @@ -351,24 +263,24 @@ int imx8m_esdhc_load_image(int instance, bool start) return ret; return esdhc_load_image(&host, MX8M_DDR_CSD1_BASE_ADDR, - MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K, SZ_1K, - start); + (ptrdiff_t)bl33, SZ_32K, SZ_1K, + false); } /** * imx8mp_esdhc_load_image - Load and optionally start an image from USDHC controller * @instance: The USDHC controller instance (0..2) - * @start: Whether to directly start the loaded image + * @bl33: Where to load the bl33 barebox image * * This uses esdhc_start_image() to load an image from SD/MMC. It is * assumed that the image is the currently running barebox image (This * information is used to calculate the length of the image). The - * image is started afterwards. + * image is not started afterwards. * - * Return: If successful, this function does not return (if directly started) - * or 0. A negative error code is returned when this function fails. + * Return: If image successfully loaded, returns 0. + * A negative error code is returned when this function fails. */ -int imx8mp_esdhc_load_image(int instance, bool start) +int imx8mp_esdhc_load_image(int instance, void *bl33) { struct esdhc_soc_data data; struct fsl_esdhc_host host = { 0 }; @@ -382,14 +294,47 @@ int imx8mp_esdhc_load_image(int instance, bool start) offset = esdhc_bootpart_active(&host)? 0 : SZ_32K; return esdhc_load_image(&host, MX8M_DDR_CSD1_BASE_ADDR, - MX8MQ_ATF_BL33_BASE_ADDR, offset, 0, start); + (ptrdiff_t)bl33, offset, 0, false); } -int imx8mn_esdhc_load_image(int instance, bool start) +int imx8mn_esdhc_load_image(int instance, void *bl33) __alias(imx8mp_esdhc_load_image); #endif -#ifdef CONFIG_ARCH_LS1046 +#ifdef CONFIG_ARCH_LAYERSCAPE + +static int layerscape_esdhc_load_image(struct fsl_esdhc_host *host, void *adr, unsigned long size, + uint32_t div_val) +{ + uint32_t val; + int ret; + + esdhc_populate_sdhci(host); + sdhci_write32(&host->sdhci, IMX_SDHCI_WML, 0); + + /* + * The ROM leaves us here with a clock frequency of around 400kHz. Speed + * this up a bit. FIXME: The resulting frequency has not yet been verified + * to work on all cards. + */ + val = sdhci_read32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET); + val &= ~0x0000fff0; + val |= div_val; + sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val); + + sdhci_write32(&host->sdhci, ESDHC_DMA_SYSCTL, + ESDHC_SYSCTL_DMA_SNOOP | ESDHC_SYSCTL_PERIPHERAL_CLK_SEL); + + ret = esdhc_read_blocks(host, adr, size); + if (ret) { + pr_err("%s: reading blocks failed with: %d\n", __func__, ret); + return ret; + } + + sync_caches_for_execution(); + + return 0; +} /* * The image on the SD card starts at 0x1000. We reserved 128KiB for the PBL, @@ -410,46 +355,76 @@ int imx8mn_esdhc_load_image(int instance, bool start) int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long r2) { int ret; - uint32_t val; struct esdhc_soc_data data = { - .flags = ESDHC_FLAG_BIGENDIAN, + .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_BIGENDIAN, }; struct fsl_esdhc_host host = { .sdhci.base = IOMEM(0x01560000), .socdata = &data, }; - unsigned long sdram = 0x80000000; + void *sdram = (void *)0x80000000; + unsigned long size = ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512); void (*barebox)(unsigned long, unsigned long, unsigned long) = - (void *)(sdram + LS1046A_SD_IMAGE_OFFSET); + (sdram + LS1046A_SD_IMAGE_OFFSET); - esdhc_populate_sdhci(&host); - sdhci_write32(&host.sdhci, IMX_SDHCI_WML, 0); + ret = layerscape_esdhc_load_image(&host, sdram, size, (8 << 8) | (3 << 4)); + if (ret) + return ret; - /* - * The ROM leaves us here with a clock frequency of around 400kHz. Speed - * this up a bit. FIXME: The resulting frequency has not yet been verified - * to work on all cards. - */ - val = sdhci_read32(&host.sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET); - val &= ~0x0000fff0; - val |= (8 << 8) | (3 << 4); - sdhci_write32(&host.sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val); + printf("Starting barebox\n"); - sdhci_write32(&host.sdhci, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP); + barebox(r0, r1, r2); - ret = esdhc_read_blocks(&host, (void *)sdram, - ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512)); - if (ret) { - pr_err("%s: reading blocks failed with: %d\n", __func__, ret); + return -EINVAL; +} + +static int ls1028a_esdhc_start_image(void __iomem *base, struct dram_regions_info *dram_info) +{ + struct esdhc_soc_data data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT, + }; + struct fsl_esdhc_host host = { + .sdhci.base = base, + .socdata = &data, + }; + void *sdram = (void *)0x80000000; + void (*bl31)(void) = (void *)LS1028A_TFA_RESERVED_START; + size_t bl31_size; + void *bl31_image; + struct bl2_to_bl31_params_mem_v2 *params; + unsigned long size = ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512); + void (*barebox)(unsigned long, unsigned long, unsigned long) = + (sdram + LS1046A_SD_IMAGE_OFFSET); + int ret; + + ret = layerscape_esdhc_load_image(&host, sdram, size, 8 << 4); + if (ret) return ret; - } - sync_caches_for_execution(); + get_builtin_firmware_ext(ls1028a_bl31_bin, barebox, &bl31_image, &bl31_size); + memcpy(bl31, bl31_image, bl31_size); - printf("Starting barebox\n"); + /* Setup an initial stack for EL2 */ + asm volatile("msr sp_el2, %0" : : "r" ((unsigned long)barebox - 16) : "cc"); - barebox(r0, r1, r2); + params = bl2_plat_get_bl31_params_v2(0, (uintptr_t)barebox, 0); + params->bl31_ep_info.args.arg3 = (unsigned long)dram_info; + + printf("Starting bl31\n"); + + bl31_entry_v2((uintptr_t)bl31, ¶ms->bl_params, NULL); return -EINVAL; } + +int ls1028a_esdhc1_start_image(struct dram_regions_info *dram_info) +{ + return ls1028a_esdhc_start_image(IOMEM(0x2140000), dram_info); +} + +int ls1028a_esdhc2_start_image(struct dram_regions_info *dram_info) +{ + return ls1028a_esdhc_start_image(IOMEM(0x2150000), dram_info); +} + #endif diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 9dcad3bb5d..fb52c7b893 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -21,6 +21,8 @@ #include <platform_data/mmc-esdhc-imx.h> #include <gpio.h> #include <of_device.h> +#include <mach/imx/generic.h> +#include <mach/imx/imx53-regs.h> #include "sdhci.h" #include "imx-esdhc.h" @@ -43,33 +45,35 @@ esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) return __esdhc_send_cmd(host, cmd, data); } -static void set_sysctl(struct mci_host *mci, u32 clock) +static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr) { - int div, pre_div; + int div, pre_div, ddr_pre_div = 1; struct fsl_esdhc_host *host = to_fsl_esdhc(mci); int sdhc_clk = clk_get_rate(host->clk); u32 clk; unsigned long cur_clock; - /* - * With eMMC and imx53 (sdhc_clk=200MHz) a pre_div of 1 results in - * pre_div=1,div=4 (=50MHz) - * which is valid and should work, but somehow doesn't. - * Starting with pre_div=2 gives - * pre_div=2, div=2 (=50MHz) - * and works fine. - */ - pre_div = 2; + if (esdhc_is_usdhc(host) && ddr) + ddr_pre_div = 2; + + if (esdhc_is_layerscape(host)) + sdhc_clk >>= 1; + + /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ + if (cpu_is_mx53() && host->sdhci.base == (void *)MX53_ESDHC3_BASE_ADDR) + pre_div = 2; + else + pre_div = 1; if (sdhc_clk == clock) pre_div = 1; else if (sdhc_clk / 16 > clock) for (; pre_div < 256; pre_div *= 2) - if ((sdhc_clk / pre_div) <= (clock * 16)) + if ((sdhc_clk / (pre_div * ddr_pre_div)) <= (clock * 16)) break; for (div = 1; div <= 16; div++) - if ((sdhc_clk / (div * pre_div)) <= clock) + if ((sdhc_clk / (div * pre_div * ddr_pre_div)) <= clock) break; cur_clock = sdhc_clk / pre_div / div; @@ -103,12 +107,70 @@ static void set_sysctl(struct mci_host *mci, u32 clock) 10 * MSECOND); } +static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing) +{ + u32 mixctrl; + + mixctrl = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL); + mixctrl &= ~MIX_CTRL_DDREN; + + switch (timing) { + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + mixctrl |= MIX_CTRL_DDREN; + sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl); + break; + default: + sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl); + } + + host->sdhci.timing = timing; +} + +static void layerscape_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing) +{ + esdhc_clrbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + SYSCTL_CKEN); + + switch (timing) { + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + esdhc_clrsetbits32(host, SDHCI_ACMD12_ERR__HOST_CONTROL2, + SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM, + FIELD_PREP(SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM, 4)); + break; + default: + esdhc_clrbits32(host, SDHCI_ACMD12_ERR__HOST_CONTROL2, + SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM); + break; + } + + esdhc_setbits32(host, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, + SYSCTL_CKEN); + + host->sdhci.timing = timing; +} + static void esdhc_set_ios(struct mci_host *mci, struct mci_ios *ios) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); + /* + * call esdhc_set_timing() before update the clock rate, + * This is because current we support DDR and SDR timing, + * Once the DDR_EN bit is set, the card clock will be + * divide by 2 automatically. So need to do this before + * setting clock rate. + */ + if (host->sdhci.timing != ios->timing) { + if (esdhc_is_usdhc(host)) + usdhc_set_timing(host, ios->timing); + else if (esdhc_is_layerscape(host)) + layerscape_set_timing(host, ios->timing); + } + /* Set the clock speed */ - set_sysctl(mci, ios->clock); + set_sysctl(mci, ios->clock, mci_timing_is_ddr(ios->timing)); /* Set the bus width */ esdhc_clrbits32(host, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, @@ -186,7 +248,7 @@ static int esdhc_reset(struct fsl_esdhc_host *host) return 0; } -static int esdhc_init(struct mci_host *mci, struct device_d *dev) +static int esdhc_init(struct mci_host *mci, struct device *dev) { struct fsl_esdhc_host *host = to_fsl_esdhc(mci); int ret; @@ -201,12 +263,13 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev) /* RSTA doesn't reset MMC_BOOT register, so manually reset it */ sdhci_write32(&host->sdhci, SDHCI_MMC_BOOT, 0); - /* Enable cache snooping */ - if (host->socdata->flags & ESDHC_FLAG_CACHE_SNOOPING) - esdhc_setbits32(host, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP); + if (esdhc_is_layerscape(host)) + esdhc_setbits32(host, ESDHC_DMA_SYSCTL, + ESDHC_SYSCTL_DMA_SNOOP | /* Enable cache snooping */ + ESDHC_SYSCTL_PERIPHERAL_CLK_SEL); /* Set the initial clock speed */ - set_sysctl(mci, 400000); + set_sysctl(mci, 400000, false); sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, SDHCI_INT_CMD_COMPLETE | SDHCI_INT_XFER_COMPLETE | SDHCI_INT_CARD_INT | @@ -225,7 +288,7 @@ static int esdhc_init(struct mci_host *mci, struct device_d *dev) return ret; } -static int fsl_esdhc_probe(struct device_d *dev) +static int fsl_esdhc_probe(struct device *dev) { struct resource *iores; struct fsl_esdhc_host *host; @@ -285,6 +348,9 @@ static int fsl_esdhc_probe(struct device_d *dev) if (ret) goto err_clk_disable; + if (esdhc_is_usdhc(host) || esdhc_is_layerscape(host)) + mci->host_caps |= MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR; + rate = clk_get_rate(host->clk); host->mci.f_min = rate >> 12; if (host->mci.f_min < 200000) @@ -342,9 +408,13 @@ static struct esdhc_soc_data usdhc_imx6sx_data = { .clkidx = "per", }; -static struct esdhc_soc_data esdhc_ls_data = { +static struct esdhc_soc_data esdhc_ls_be_data = { .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_BIGENDIAN | - ESDHC_FLAG_CACHE_SNOOPING, + ESDHC_FLAG_LAYERSCAPE, +}; + +static struct esdhc_soc_data esdhc_ls_le_data = { + .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_LAYERSCAPE, }; static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = { @@ -359,9 +429,11 @@ static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = { { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx6sx_data }, { .compatible = "fsl,imx8mn-usdhc", .data = &usdhc_imx6sx_data }, { .compatible = "fsl,imx8mp-usdhc", .data = &usdhc_imx6sx_data }, - { .compatible = "fsl,ls1046a-esdhc",.data = &esdhc_ls_data }, + { .compatible = "fsl,ls1028a-esdhc",.data = &esdhc_ls_le_data }, + { .compatible = "fsl,ls1046a-esdhc",.data = &esdhc_ls_be_data }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, fsl_esdhc_compatible); static struct platform_device_id imx_esdhc_ids[] = { { @@ -375,7 +447,7 @@ static struct platform_device_id imx_esdhc_ids[] = { } }; -static struct driver_d fsl_esdhc_driver = { +static struct driver fsl_esdhc_driver = { .name = "imx-esdhc", .probe = fsl_esdhc_probe, .of_compatible = DRV_OF_COMPAT(fsl_esdhc_compatible), diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h index f1685eac06..eff556f2ff 100644 --- a/drivers/mci/imx-esdhc.h +++ b/drivers/mci/imx-esdhc.h @@ -39,14 +39,30 @@ #define PIO_TIMEOUT 100000 +#define SDHCI_ACMD12_ERR__HOST_CONTROL2_UHSM GENMASK(18, 16) /* Layerscape specific */ + #define IMX_SDHCI_WML 0x44 #define IMX_SDHCI_MIXCTRL 0x48 +/* Imported from Linux Kernel drivers/mmc/host/sdhci-esdhc-imx.c */ +#define MIX_CTRL_DDREN BIT(3) +#define MIX_CTRL_DTDSEL_READ BIT(4) +#define MIX_CTRL_AC23EN BIT(7) +#define MIX_CTRL_EXE_TUNE BIT(22) +#define MIX_CTRL_SMPCLK_SEL BIT(23) +#define MIX_CTRL_AUTO_TUNE_EN BIT(24) +#define MIX_CTRL_FBCLK_SEL BIT(25) +#define MIX_CTRL_HS400_EN BIT(26) +#define MIX_CTRL_HS400_ES BIT(27) +/* Bits 3 and 6 are not SDHCI standard definitions */ +#define MIX_CTRL_SDHCI_MASK 0xb7 +/* Tuning bits */ +#define MIX_CTRL_TUNING_MASK 0x03c00000 #define IMX_SDHCI_DLL_CTRL 0x60 #define IMX_SDHCI_MIX_CTRL_FBCLK_SEL BIT(25) #define ESDHC_DMA_SYSCTL 0x40c /* Layerscape specific */ #define ESDHC_SYSCTL_DMA_SNOOP BIT(6) - +#define ESDHC_SYSCTL_PERIPHERAL_CLK_SEL BIT(19) /* * The CMDTYPE of the CMD register (offset 0xE) should be set to @@ -89,8 +105,8 @@ #define ESDHC_FLAG_HS400 BIT(9) /* Need to access registers in bigendian mode */ #define ESDHC_FLAG_BIGENDIAN BIT(10) -/* Enable cache snooping */ -#define ESDHC_FLAG_CACHE_SNOOPING BIT(11) +/* Layerscape variant ls1046a, ls1028a, ls1088a, revisit for ls1012a */ +#define ESDHC_FLAG_LAYERSCAPE BIT(11) struct esdhc_soc_data { u32 flags; @@ -100,7 +116,7 @@ struct esdhc_soc_data { struct fsl_esdhc_host { struct mci_host mci; struct clk *clk; - struct device_d *dev; + struct device *dev; const struct esdhc_soc_data *socdata; struct sdhci sdhci; }; @@ -110,6 +126,11 @@ static inline int esdhc_is_usdhc(struct fsl_esdhc_host *data) return !!(data->socdata->flags & ESDHC_FLAG_USDHC); } +static inline int esdhc_is_layerscape(struct fsl_esdhc_host *data) +{ + return !!(data->socdata->flags & ESDHC_FLAG_LAYERSCAPE); +} + static inline struct fsl_esdhc_host *sdhci_to_esdhc(struct sdhci *sdhci) { return container_of(sdhci, struct fsl_esdhc_host, sdhci); diff --git a/drivers/mci/imx.c b/drivers/mci/imx.c index 9910b55ed5..48a3378335 100644 --- a/drivers/mci/imx.c +++ b/drivers/mci/imx.c @@ -465,7 +465,7 @@ static void mxcmci_set_ios(struct mci_host *mci, struct mci_ios *ios) host->clock = ios->clock; } -static int mxcmci_init(struct mci_host *mci, struct device_d *dev) +static int mxcmci_init(struct mci_host *mci, struct device *dev) { struct mxcmci_host *host = to_mxcmci(mci); @@ -486,7 +486,7 @@ static int mxcmci_init(struct mci_host *mci, struct device_d *dev) return 0; } -static int mxcmci_probe(struct device_d *dev) +static int mxcmci_probe(struct device *dev) { struct resource *iores; struct mxcmci_host *host; @@ -527,8 +527,9 @@ static __maybe_unused struct of_device_id mxcmci_compatible[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, mxcmci_compatible); -static struct driver_d mxcmci_driver = { +static struct driver mxcmci_driver = { .name = DRIVER_NAME, .probe = mxcmci_probe, .of_compatible = DRV_OF_COMPAT(mxcmci_compatible), diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c index f092156f9a..3546cc3a32 100644 --- a/drivers/mci/mci-bcm2835.c +++ b/drivers/mci/mci-bcm2835.c @@ -30,7 +30,7 @@ static int twoticks_delay; struct bcm2835_mci_host { struct mci_host mci; void __iomem *regs; - struct device_d *hw_dev; + struct device *hw_dev; int bus_width; u32 clock; u32 max_clock; @@ -118,7 +118,6 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) { u32 command, block_data = 0, transfer_mode = 0; int ret; - u32 wait_inhibit_mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA; struct bcm2835_mci_host *host = to_bcm2835_host(mci); sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, false, @@ -129,15 +128,9 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd, block_data |= data->blocksize; } - /* We shouldn't wait for data inihibit for stop commands, even - though they might use busy signaling */ - if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) - wait_inhibit_mask = SDHCI_CMD_INHIBIT_CMD; - - /*Wait for old command*/ - while (sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) - & wait_inhibit_mask) - ; + ret = sdhci_wait_idle_data(&host->sdhci, cmd); + if (ret) + return ret; sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, 0xFFFFFFFF); sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, 0xFFFFFFFF); @@ -148,7 +141,7 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd, command << 16 | transfer_mode); ret = bcm2835_mci_wait_command_done(host); - if (ret) { + if (ret && ret != -ETIMEDOUT) { dev_err(host->hw_dev, "Error while executing command %d\n", cmd->cmdidx); dev_err(host->hw_dev, "Status: 0x%X, Interrupt: 0x%X\n", @@ -232,6 +225,13 @@ static void bcm2835_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL); switch (ios->bus_width) { + case MMC_BUS_WIDTH_8: + sdhci_write32(&host->sdhci, + SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, + (current_val & ~CONTROL0_4DATA) | CONTROL0_8DATA); + host->bus_width = 2; + dev_dbg(host->hw_dev, "Changing bus width to 8\n"); + break; case MMC_BUS_WIDTH_4: sdhci_write32(&host->sdhci, SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL, @@ -301,7 +301,7 @@ static void bcm2835_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) host->bus_width, host->clock); } -static int bcm2835_mci_reset(struct mci_host *mci, struct device_d *mci_dev) +static int bcm2835_mci_reset(struct mci_host *mci, struct device *mci_dev) { struct bcm2835_mci_host *host; u32 ret = 0; @@ -353,7 +353,7 @@ static int bcm2835_mci_reset(struct mci_host *mci, struct device_d *mci_dev) return 0; } -static int bcm2835_mci_probe(struct device_d *hw_dev) +static int bcm2835_mci_probe(struct device *hw_dev) { struct resource *iores; struct bcm2835_mci_host *host; @@ -429,8 +429,9 @@ static __maybe_unused struct of_device_id bcm2835_mci_compatible[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, bcm2835_mci_compatible); -static struct driver_d bcm2835_mci_driver = { +static struct driver bcm2835_mci_driver = { .name = "bcm2835_mci", .probe = bcm2835_mci_probe, .of_compatible = DRV_OF_COMPAT(bcm2835_mci_compatible), diff --git a/drivers/mci/mci-bcm2835.h b/drivers/mci/mci-bcm2835.h index 608764c23d..71448642ad 100644 --- a/drivers/mci/mci-bcm2835.h +++ b/drivers/mci/mci-bcm2835.h @@ -10,6 +10,7 @@ #define CONTROL0_HISPEED (1 << 2) #define CONTROL0_4DATA (1 << 1) +#define CONTROL0_8DATA (1 << 5) #define CONTROL1_DATARST (1 << 26) #define CONTROL1_CMDRST (1 << 25) diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index 8c08a4f61f..f6565b2b64 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -75,6 +75,28 @@ static int mci_send_cmd(struct mci *mci, struct mci_cmd *cmd, struct mci_data *d } /** + * mci_send_cmd_retry() - send a command to the mmc device, retrying on error + * + * @dev: device to receive the command + * @cmd: command to send + * @data: additional data to send/receive + * @retries: how many times to retry; mci_send_cmd is always called at least + * once + * Return: 0 if ok, -ve on error + */ +static int mci_send_cmd_retry(struct mci *mci, struct mci_cmd *cmd, + struct mci_data *data, unsigned retries) +{ + int ret; + + do + ret = mci_send_cmd(mci, cmd, data); + while (ret && retries--); + + return ret; +} + +/** * @param p Command definition to setup * @param cmd Valid SD/MMC command (refer MMC_CMD_* / SD_CMD_*) * @param arg Argument for the command (optional) @@ -113,12 +135,105 @@ static int mci_set_blocklen(struct mci *mci, unsigned len) { struct mci_cmd cmd; + if (mci->host->timing == MMC_TIMING_MMC_DDR52) + return 0; + mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCKLEN, len, MMC_RSP_R1); return mci_send_cmd(mci, &cmd, NULL); } static void *sector_buf; +static int mci_send_status(struct mci *mci, unsigned int *status) +{ + struct mci_host *host = mci->host; + struct mci_cmd cmd; + int ret; + + /* + * While CMD13 is defined for SPI mode, the reported status bits have + * different layout that SD/MMC. We skip supporting this for now. + */ + if (mmc_host_is_spi(host)) + return -ENOSYS; + + cmd.cmdidx = MMC_CMD_SEND_STATUS; + cmd.resp_type = MMC_RSP_R1; + cmd.cmdarg = mci->rca << 16; + + ret = mci_send_cmd_retry(mci, &cmd, NULL, 4); + if (!ret) + *status = cmd.response[0]; + + return ret; +} + +static int mmc_switch_status_error(struct mci_host *host, u32 status) +{ + if (mmc_host_is_spi(host)) { + if (status & R1_SPI_ILLEGAL_COMMAND) + return -EBADMSG; + } else { + if (R1_STATUS(status)) + pr_warn("unexpected status %#x after switch\n", status); + if (status & R1_SWITCH_ERROR) + return -EBADMSG; + } + return 0; +} + +/* Caller must hold re-tuning */ +int mci_switch_status(struct mci *mci, bool crc_err_fatal) +{ + u32 status; + int err; + + err = mci_send_status(mci, &status); + if (!crc_err_fatal && err == -EILSEQ) + return 0; + if (err) + return err; + + return mmc_switch_status_error(mci->host, status); +} + +static int mci_poll_until_ready(struct mci *mci, int timeout_ms) +{ + unsigned int status; + int err, retries = 0; + + while (1) { + err = mci_send_status(mci, &status); + if (err) + return err; + + /* + * Some cards mishandle the status bits, so make sure to + * check both the busy indication and the card state. + */ + if ((status & R1_READY_FOR_DATA) && + R1_CURRENT_STATE(status) != R1_STATE_PRG) + break; + + if (status & R1_STATUS_MASK) { + dev_err(&mci->dev, "Status Error: 0x%08x\n", status); + return -EIO; + } + + if (retries++ == timeout_ms) { + dev_err(&mci->dev, "Timeout awaiting card ready\n"); + return -ETIMEDOUT; + } + + udelay(1000); + } + + dev_dbg(&mci->dev, "Ready polling took %ums\n", retries); + + return 0; +} + + /** * Write one or several blocks of data to the card * @param mci_dev MCI instance @@ -132,28 +247,31 @@ static int mci_block_write(struct mci *mci, const void *src, int blocknum, { struct mci_cmd cmd; struct mci_data data; - const void *buf; unsigned mmccmd; int ret; + /* + * Quoting eMMC Spec v5.1 (JEDEC Standard No. 84-B51): + * Due to legacy reasons, a Device may still treat CMD24/25 during + * prg-state (while busy is active) as a legal or illegal command. + * A host should not send CMD24/25 while the Device is in the prg + * state and busy is active. + */ + ret = mci_poll_until_ready(mci, 1000 /* ms */); + if (ret && ret != -ENOSYS) + return ret; + if (blocks > 1) mmccmd = MMC_CMD_WRITE_MULTIPLE_BLOCK; else mmccmd = MMC_CMD_WRITE_SINGLE_BLOCK; - if ((unsigned long)src & 0x3) { - memcpy(sector_buf, src, SECTOR_SIZE); - buf = sector_buf; - } else { - buf = src; - } - mci_setup_cmd(&cmd, mmccmd, mci->high_capacity != 0 ? blocknum : blocknum * mci->write_bl_len, MMC_RSP_R1); - data.src = buf; + data.src = src; data.blocks = blocks; data.blocksize = mci->write_bl_len; data.flags = MMC_DATA_WRITE; @@ -201,7 +319,8 @@ static int mci_read_block(struct mci *mci, void *dst, int blocknum, ret = mci_send_cmd(mci, &cmd, &data); if (ret || blocks > 1) { - mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, MMC_RSP_R1b); + mci_setup_cmd(&cmd, MMC_CMD_STOP_TRANSMISSION, 0, + IS_SD(mci) ? MMC_RSP_R1b : MMC_RSP_R1); mci_send_cmd(mci, &cmd, NULL); } return ret; @@ -232,6 +351,15 @@ static int mci_go_idle(struct mci *mci) return 0; } +static int sdio_send_op_cond(struct mci *mci) +{ + struct mci_cmd cmd; + + mci_setup_cmd(&cmd, SD_IO_SEND_OP_COND, 0, MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR); + + return mci_send_cmd(mci, &cmd, NULL); +} + /** * FIXME * @param mci MCI instance @@ -344,7 +472,7 @@ static int mmc_send_op_cond(struct mci *mci) mci->ocr = cmd.response[0]; mci->high_capacity = ((mci->ocr & OCR_HCS) == OCR_HCS); - mci->rca = 0; + mci->rca = 2; return 0; } @@ -388,7 +516,9 @@ int mci_send_ext_csd(struct mci *mci, char *ext_csd) */ int mci_switch(struct mci *mci, unsigned index, unsigned value) { + unsigned int status; struct mci_cmd cmd; + int ret; mci_setup_cmd(&cmd, MMC_CMD_SWITCH, (MMC_SWITCH_MODE_WRITE_BYTE << 24) | @@ -396,7 +526,35 @@ int mci_switch(struct mci *mci, unsigned index, unsigned value) (value << 8), MMC_RSP_R1b); - return mci_send_cmd(mci, &cmd, NULL); + ret = mci_send_cmd(mci, &cmd, NULL); + if (ret) + return ret; + + ret = mci_send_status(mci, &status); + if (ret) + return ret; + + if (status & R1_SWITCH_ERROR) + return -EIO; + + return 0; +} + +u8 *mci_get_ext_csd(struct mci *mci) +{ + u8 *ext_csd; + int ret; + + ext_csd = dma_alloc(512); + + ret = mci_send_ext_csd(mci, ext_csd); + if (ret) { + printf("Failure to read EXT_CSD register\n"); + dma_free(ext_csd); + return ERR_PTR(-EIO); + } + + return ext_csd; } static blkcnt_t mci_calc_blk_cnt(blkcnt_t cap, unsigned shift) @@ -428,7 +586,7 @@ static void mci_part_add(struct mci *mci, uint64_t size, part->idx = idx; if (area_type == MMC_BLK_DATA_AREA_MAIN) { - part->blk.cdev.device_node = mci->host->hw_dev->device_node; + cdev_set_of_node(&part->blk.cdev, mci->host->hw_dev->of_node); part->blk.cdev.flags |= DEVFS_IS_MCI_MAIN_PART_DEV; } @@ -508,7 +666,7 @@ static int mmc_change_freq(struct mci *mci) char cardtype; int err; - mci->ext_csd = xmalloc(512); + mci->ext_csd = dma_alloc(512); mci->card_caps = 0; /* Only version 4 supports high-speed */ @@ -525,7 +683,7 @@ static int mmc_change_freq(struct mci *mci) cardtype = mci->ext_csd[EXT_CSD_DEVICE_TYPE] & EXT_CSD_CARD_TYPE_MASK; - err = mci_switch(mci, EXT_CSD_HS_TIMING, 1); + err = mci_switch(mci, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); if (err) { dev_dbg(&mci->dev, "MMC frequency changing failed: %d\n", err); @@ -546,11 +704,15 @@ static int mmc_change_freq(struct mci *mci) return 0; } - /* High Speed is set, there are two types: 52MHz and 26MHz */ - if (cardtype & EXT_CSD_CARD_TYPE_52) - mci->card_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ | MMC_CAP_MMC_HIGHSPEED; - else - mci->card_caps |= MMC_CAP_MMC_HIGHSPEED; + mci->card_caps |= MMC_CAP_MMC_HIGHSPEED; + + /* High Speed is set, there are three types: 26MHz, 52MHz, 52MHz DDR */ + if (cardtype & EXT_CSD_CARD_TYPE_52) { + mci->card_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ; + + if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) + mci->card_caps |= MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR; + } if (IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) && mci->ext_csd[EXT_CSD_REV] >= 3 && mci->ext_csd[EXT_CSD_BOOT_SIZE_MULT]) { @@ -734,6 +896,8 @@ static void mci_set_ios(struct mci *mci) }; host->set_ios(host, &ios); + + host->actual_clock = host->clock; } /** @@ -761,7 +925,7 @@ static void mci_set_clock(struct mci *mci, unsigned clock) * @param mci MCI instance * @param width New interface bit width (1, 4 or 8) */ -static void mci_set_bus_width(struct mci *mci, unsigned width) +static void mci_set_bus_width(struct mci *mci, enum mci_bus_width width) { struct mci_host *host = mci->host; @@ -952,7 +1116,7 @@ static void mci_extract_card_dsr_imp_from_csd(struct mci *mci) mci->dsr_imp = UNSTUFF_BITS(mci->csd, 76, 1); } -static int mmc_compare_ext_csds(struct mci *mci, unsigned bus_width) +static int mmc_compare_ext_csds(struct mci *mci, enum mci_bus_width bus_width) { u8 *bw_ext_csd; int err; @@ -960,7 +1124,7 @@ static int mmc_compare_ext_csds(struct mci *mci, unsigned bus_width) if (bus_width == MMC_BUS_WIDTH_1) return 0; - bw_ext_csd = xmalloc(512); + bw_ext_csd = dma_alloc(512); err = mci_send_ext_csd(mci, bw_ext_csd); if (err) { dev_info(&mci->dev, "mci_send_ext_csd failed with %d\n", err); @@ -1009,7 +1173,7 @@ static int mmc_compare_ext_csds(struct mci *mci, unsigned bus_width) 0 : -EINVAL; out: - free(bw_ext_csd); + dma_free(bw_ext_csd); return err; } @@ -1064,34 +1228,71 @@ static int mci_startup_sd(struct mci *mci) return 0; } -static int mci_startup_mmc(struct mci *mci) +static u32 mci_bus_width_ext_csd_bits(enum mci_bus_width bus_width) { - struct mci_host *host = mci->host; + switch (bus_width) { + case MMC_BUS_WIDTH_8: + return EXT_CSD_BUS_WIDTH_8; + case MMC_BUS_WIDTH_4: + return EXT_CSD_BUS_WIDTH_4; + case MMC_BUS_WIDTH_1: + default: + return EXT_CSD_BUS_WIDTH_1; + } +} + +static int mci_mmc_try_bus_width(struct mci *mci, enum mci_bus_width bus_width, + enum mci_timing timing) +{ + u32 ext_csd_bits; int err; - int idx = 0; - static unsigned ext_csd_bits[] = { - EXT_CSD_BUS_WIDTH_4, - EXT_CSD_BUS_WIDTH_8, - }; - static unsigned bus_widths[] = { - MMC_BUS_WIDTH_4, - MMC_BUS_WIDTH_8, - }; - /* if possible, speed up the transfer */ - if (mci_caps(mci) & MMC_CAP_MMC_HIGHSPEED) { - if (mci->card_caps & MMC_CAP_MMC_HIGHSPEED_52MHZ) - mci->tran_speed = 52000000; - else - mci->tran_speed = 26000000; + ext_csd_bits = mci_bus_width_ext_csd_bits(bus_width); - host->timing = MMC_TIMING_MMC_HS; + if (mci_timing_is_ddr(timing)) + ext_csd_bits |= EXT_CSD_DDR_FLAG; + + err = mci_switch(mci, EXT_CSD_BUS_WIDTH, ext_csd_bits); + if (err < 0) + goto out; + + mci->host->timing = timing; + mci_set_bus_width(mci, bus_width); + + switch (bus_width) { + case MMC_BUS_WIDTH_8: + mci->card_caps |= MMC_CAP_8_BIT_DATA; + break; + case MMC_BUS_WIDTH_4: + mci->card_caps |= MMC_CAP_4_BIT_DATA; + break; + default: + break; } - mci_set_clock(mci, mci->tran_speed); + err = mmc_compare_ext_csds(mci, bus_width); + if (err < 0) + goto out; + +out: + dev_dbg(&mci->dev, "Tried buswidth %u%s: %s\n", 1 << bus_width, + mci_timing_is_ddr(timing) ? " (DDR)" : "", err ? "failed" : "OK"); + + return err ?: bus_width; +} + +static int mci_mmc_select_bus_width(struct mci *mci) +{ + struct mci_host *host = mci->host; + int ret; + int idx = 0; + static enum mci_bus_width bus_widths[] = { + MMC_BUS_WIDTH_4, + MMC_BUS_WIDTH_8, + }; if (!(host->host_caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) - return 0; + return MMC_BUS_WIDTH_1; /* * Unlike SD, MMC cards dont have a configuration register to notify @@ -1103,7 +1304,6 @@ static int mci_startup_mmc(struct mci *mci) idx = 1; for (; idx >= 0; idx--) { - /* * Host is capable of 8bit transfer, then switch * the device to work in 8bit transfer mode. If the @@ -1111,23 +1311,275 @@ static int mci_startup_mmc(struct mci *mci) * 4bit transfer mode. On success set the corresponding * bus width on the host. */ - err = mci_switch(mci, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); - if (err) { - if (idx == 0) - dev_warn(&mci->dev, "Changing MMC bus width failed: %d\n", err); - continue; - } + ret = mci_mmc_try_bus_width(mci, bus_widths[idx], host->timing); + if (ret > 0) + break; + } - mci_set_bus_width(mci, bus_widths[idx]); + return ret; +} - err = mmc_compare_ext_csds(mci, bus_widths[idx]); - if (!err) - break; +static int mci_mmc_select_hs_ddr(struct mci *mci) +{ + struct mci_host *host = mci->host; + int ret; + + /* + * barebox MCI core does not change voltage, so we don't know here + * if we should check for the 1.8v or 3.3v mode. Until we support + * higher speed modes that require voltage switching like HS200/HS400, + * let's just check for either bit. + */ + if (!(mci_caps(mci) & (MMC_CAP_MMC_1_8V_DDR | MMC_CAP_MMC_3_3V_DDR))) + return 0; + + ret = mci_mmc_try_bus_width(mci, host->bus_width, MMC_TIMING_MMC_DDR52); + if (ret < 0) + return mci_mmc_try_bus_width(mci, host->bus_width, MMC_TIMING_MMC_HS); + + /* Block length is fixed to 512 bytes while in DDR mode */ + mci->read_bl_len = SECTOR_SIZE; + mci->write_bl_len = SECTOR_SIZE; + + return 0; +} + +int mci_execute_tuning(struct mci *mci) +{ + struct mci_host *host = mci->host; + u32 opcode; + + if (!host->execute_tuning) { + /* + * For us, implementing ->execute_tuning is mandatory to + * support higher speed modes + */ + dev_warn(&mci->dev, "tuning failed: no host diver support\n"); + return -EOPNOTSUPP; + } + + /* Tuning is only supported for MMC / HS200 */ + if (mmc_card_hs200(mci)) + opcode = MMC_SEND_TUNING_BLOCK_HS200; + else + return 0; + + return host->execute_tuning(host, opcode); +} + +int mci_send_abort_tuning(struct mci *mci, u32 opcode) +{ + struct mci_cmd cmd = {}; + + /* + * eMMC specification specifies that CMD12 can be used to stop a tuning + * command, but SD specification does not, so do nothing unless it is + * eMMC. + */ + if (opcode != MMC_SEND_TUNING_BLOCK_HS200) + return 0; + + cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; + cmd.resp_type = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + return mci_send_cmd(mci, &cmd, NULL); +} +EXPORT_SYMBOL_GPL(mci_send_abort_tuning); + +static void mmc_select_max_dtr(struct mci *mci) +{ + u8 card_type = mci->ext_csd[EXT_CSD_DEVICE_TYPE]; + u32 caps2 = mci->host->caps2; + u32 caps = mci->card_caps; + unsigned int hs_max_dtr = 0; + unsigned int hs200_max_dtr = 0; + + if ((caps & MMC_CAP_MMC_HIGHSPEED) && + (card_type & EXT_CSD_CARD_TYPE_26)) { + hs_max_dtr = MMC_HIGH_26_MAX_DTR; + } + + if ((caps & MMC_CAP_MMC_HIGHSPEED) && + (card_type & EXT_CSD_CARD_TYPE_52)) { + hs_max_dtr = MMC_HIGH_52_MAX_DTR; } + if ((caps2 & MMC_CAP2_HS200_1_8V_SDR) && + (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) { + hs200_max_dtr = MMC_HS200_MAX_DTR; + } + + if ((caps2 & MMC_CAP2_HS200_1_2V_SDR) && + (card_type & EXT_CSD_CARD_TYPE_HS200_1_2V)) { + hs200_max_dtr = MMC_HS200_MAX_DTR; + } + + mci->host->hs200_max_dtr = hs200_max_dtr; + mci->host->hs_max_dtr = hs_max_dtr; +} +/* + * For device supporting HS200 mode, the following sequence + * should be done before executing the tuning process. + * 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported) + * 2. switch to HS200 mode + * 3. set the clock to > 52Mhz and <=200MHz + */ +static int mmc_select_hs200(struct mci *mci) +{ + unsigned int old_timing, old_clock; + int err = -EINVAL; + u8 val; + + /* + * Set the bus width(4 or 8) with host's support and + * switch to HS200 mode if bus width is set successfully. + */ + /* find out maximum bus width and then try DDR if supported */ + err = mci_mmc_select_bus_width(mci); + if (err > 0) { + /* TODO actually set drive strength instead of 0. Currently unsupported. */ + val = EXT_CSD_TIMING_HS200 | 0 << EXT_CSD_DRV_STR_SHIFT; + err = mci_switch(mci, EXT_CSD_HS_TIMING, val); + if (err == -EIO) + return -EBADMSG; + if (err) + goto err; + + /* + * Bump to HS timing and frequency. Some cards don't handle + * SEND_STATUS reliably at the initial frequency. + * NB: We can't move to full (HS200) speeds until after we've + * successfully switched over. + */ + old_timing = mci->host->timing; + old_clock = mci->host->clock; + + mci->host->timing = MMC_TIMING_MMC_HS200; + mci_set_ios(mci); + mci_set_clock(mci, mci->host->hs_max_dtr); + + err = mci_switch_status(mci, true); + + /* + * mmc_select_timing() assumes timing has not changed if + * it is a switch error. + */ + if (err == -EBADMSG) { + mci->host->clock = old_clock; + mci->host->timing = old_timing; + mci_set_ios(mci); + } + } +err: + if (err) { + dev_err(&mci->dev, "%s failed, error %d\n", __func__, err); + } return err; } +/* + * Set the bus speed for the selected speed mode. + */ +static void mmc_set_bus_speed(struct mci *mci) +{ + unsigned int max_dtr = (unsigned int)-1; + + if (mmc_card_hs200(mci) && + max_dtr > mci->host->hs200_max_dtr) + max_dtr = mci->host->hs200_max_dtr; + else if (mmc_card_hs(mci) && max_dtr > mci->host->hs_max_dtr) + max_dtr = mci->host->hs_max_dtr; + else if (max_dtr > mci->tran_speed) + max_dtr = mci->tran_speed; + + mci_set_clock(mci, max_dtr); +} + +/* + * Activate HS200 or HS400ES mode if supported. + */ +int mmc_select_timing(struct mci *mci) +{ + unsigned int mmc_avail_type; + int err = 0; + + mmc_select_max_dtr(mci); + + mmc_avail_type = mci->ext_csd[EXT_CSD_DEVICE_TYPE] & EXT_CSD_CARD_TYPE_MASK; + if (mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) { + err = mmc_select_hs200(mci); + if (err == -EBADMSG) + mmc_avail_type &= ~EXT_CSD_CARD_TYPE_HS200; + else + goto out; + } + +out: + if (err && err != -EBADMSG) + return err; + + /* + * Set the bus speed to the selected bus timing. + * If timing is not selected, backward compatible is the default. + */ + mmc_set_bus_speed(mci); + + return 0; +} + +int mmc_hs200_tuning(struct mci *mci) +{ + return mci_execute_tuning(mci); +} + +static int mci_startup_mmc(struct mci *mci) +{ + struct mci_host *host = mci->host; + int ret = 0; + + /* if possible, speed up the transfer */ + if (mci_caps(mci) & MMC_CAP_MMC_HIGHSPEED) { + if (mci->card_caps & MMC_CAP_MMC_HIGHSPEED_52MHZ) + mci->tran_speed = 52000000; + else + mci->tran_speed = 26000000; + + host->timing = MMC_TIMING_MMC_HS; + } + + if (IS_ENABLED(CONFIG_MCI_TUNING)) { + /* + * Select timing interface + */ + ret = mmc_select_timing(mci); + if (ret) + return ret; + + if (mmc_card_hs200(mci)) + ret = mmc_hs200_tuning(mci); + + if (ret) { + host->timing = MMC_TIMING_MMC_HS; + mci_switch(mci, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); + } + } + + if (ret || !IS_ENABLED(CONFIG_MCI_TUNING)) { + mci_set_clock(mci, mci->tran_speed); + + /* find out maximum bus width and then try DDR if supported */ + ret = mci_mmc_select_bus_width(mci); + if (ret > MMC_BUS_WIDTH_1 && mci->tran_speed == 52000000) + ret = mci_mmc_select_hs_ddr(mci); + + if (ret < 0) { + dev_warn(&mci->dev, "Changing MMC bus width failed: %d\n", ret); + } + } + + return ret >= MMC_BUS_WIDTH_1 ? 0 : ret; +} + /** * Scan the given host interfaces and detect connected MMC/SD cards * @param mci MCI instance @@ -1551,6 +2003,10 @@ static const char *mci_timing_tostr(unsigned timing) return "MMC HS"; case MMC_TIMING_SD_HS: return "SD HS"; + case MMC_TIMING_MMC_DDR52: + return "MMC DDR52"; + case MMC_TIMING_MMC_HS200: + return "HS200"; default: return "unknown"; /* shouldn't happen */ } @@ -1558,19 +2014,22 @@ static const char *mci_timing_tostr(unsigned timing) static void mci_print_caps(unsigned caps) { - printf(" capabilities: %s%s%s%s%s\n", + printf(" capabilities: %s%s%s%s%s%s%s%s\n", caps & MMC_CAP_4_BIT_DATA ? "4bit " : "", caps & MMC_CAP_8_BIT_DATA ? "8bit " : "", caps & MMC_CAP_SD_HIGHSPEED ? "sd-hs " : "", caps & MMC_CAP_MMC_HIGHSPEED ? "mmc-hs " : "", - caps & MMC_CAP_MMC_HIGHSPEED_52MHZ ? "mmc-52MHz " : ""); + caps & MMC_CAP_MMC_HIGHSPEED_52MHZ ? "mmc-52MHz " : "", + caps & MMC_CAP_MMC_3_3V_DDR ? "ddr-3.3v " : "", + caps & MMC_CAP_MMC_1_8V_DDR ? "ddr-1.8v " : "", + caps & MMC_CAP_MMC_1_2V_DDR ? "ddr-1.2v " : ""); } /** * Output some valuable information when the user runs 'devinfo' on an MCI device * @param mci MCI device instance */ -static void mci_info(struct device_d *dev) +static void mci_info(struct device *dev) { struct mci *mci = container_of(dev, struct mci, dev); struct mci_host *host = mci->host; @@ -1596,7 +2055,9 @@ static void mci_info(struct device_d *dev) mci_print_caps(host->host_caps); printf("Card information:\n"); - printf(" Attached is a %s card\n", IS_SD(mci) ? "SD" : "MMC"); + printf(" Card type: %s\n", mci->sdio ? "SDIO" : IS_SD(mci) ? "SD" : "MMC"); + if (mci->sdio) + return; printf(" Version: %s\n", mci_version_string(mci)); printf(" Capacity: %u MiB\n", (unsigned)(mci->capacity >> 20)); @@ -1608,8 +2069,8 @@ static void mci_info(struct device_d *dev) mci->csd[2], mci->csd[3]); printf(" Max. transfer speed: %u Hz\n", mci->tran_speed); mci_print_caps(mci->card_caps); - printf(" Manufacturer ID: %02X\n", extract_mid(mci)); - printf(" OEM/Application ID: %04X\n", extract_oid(mci)); + printf(" Manufacturer ID: 0x%02X\n", extract_mid(mci)); + printf(" OEM/Application ID: 0x%04X\n", extract_oid(mci)); printf(" Product name: '%c%c%c%c%c'\n", mci->cid[0] & 0xff, (mci->cid[1] >> 24), (mci->cid[1] >> 16) & 0xff, (mci->cid[1] >> 8) & 0xff, mci->cid[1] & 0xff); @@ -1691,6 +2152,7 @@ static int mci_register_partition(struct mci_part *part) */ part->blk.dev = &mci->dev; part->blk.ops = &mci_ops; + part->blk.type = IS_SD(mci) ? BLK_TYPE_SD : BLK_TYPE_MMC; rc = blockdevice_register(&part->blk); if (rc != 0) { @@ -1699,7 +2161,7 @@ static int mci_register_partition(struct mci_part *part) } dev_info(&mci->dev, "registered %s\n", part->blk.cdev.name); - np = host->hw_dev->device_node; + np = host->hw_dev->of_node; /* create partitions on demand */ switch (part->area_type) { @@ -1709,7 +2171,7 @@ static int mci_register_partition(struct mci_part *part) else partnodename = "boot1-partitions"; - np = of_get_child_by_name(host->hw_dev->device_node, + np = of_get_child_by_name(host->hw_dev->of_node, partnodename); break; case MMC_BLK_DATA_AREA_MAIN: @@ -1720,12 +2182,6 @@ static int mci_register_partition(struct mci_part *part) return 0; } - rc = parse_partition_table(&part->blk); - if (rc != 0) { - dev_warn(&mci->dev, "No partition table found\n"); - rc = 0; /* it's not a failure */ - } - if (np) { of_parse_partitions(&part->blk.cdev, np); @@ -1739,6 +2195,47 @@ static int mci_register_partition(struct mci_part *part) return 0; } +static int of_broken_cd_fixup(struct device_node *root, void *ctx) +{ + struct mci_host *host = ctx; + struct device *hw_dev = host->hw_dev; + struct device_node *np; + char *name; + + if (!host->broken_cd) + return 0; + + name = of_get_reproducible_name(hw_dev->of_node); + np = of_find_node_by_reproducible_name(root, name); + free(name); + if (!np) { + dev_warn(hw_dev, "Cannot find nodepath %pOF, cannot fixup\n", + hw_dev->of_node); + return -EINVAL; + } + + of_property_write_bool(np, "cd-gpios", false); + of_property_write_bool(np, "broken-cd", true); + + return 0; +} + +static int mci_get_partition_setting_completed(struct mci *mci) +{ + u8 *ext_csd; + int ret; + + ext_csd = mci_get_ext_csd(mci); + if (IS_ERR(ext_csd)) + return PTR_ERR(ext_csd); + + ret = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]; + + dma_free(ext_csd); + + return ret; +} + /** * Probe an MCI card at the given host interface * @param mci MCI device instance @@ -1750,10 +2247,13 @@ static int mci_card_probe(struct mci *mci) int i, rc, disknum, ret; bool has_bootpart = false; - if (host->card_present && !host->card_present(host) && - !host->non_removable) { - dev_err(&mci->dev, "no card inserted\n"); - return -ENODEV; + if (host->card_present && !host->card_present(host) && !host->non_removable) { + if (!host->broken_cd) { + dev_err(&mci->dev, "no card inserted\n"); + return -ENODEV; + } + + dev_info(&mci->dev, "no card inserted (ignoring)\n"); } ret = regulator_enable(host->supply); @@ -1781,12 +2281,22 @@ static int mci_card_probe(struct mci *mci) goto on_error; } + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) { + rc = sdio_send_op_cond(mci); + if (!rc) { + mci->ready_for_use = true; + mci->sdio = true; + dev_info(&mci->dev, "SDIO card detected, ignoring\n"); + return 0; + } + } + /* Check if this card can handle the "SD Card Physical Layer Specification 2.0" */ - if (!host->no_sd) { + if (!(host->caps2 & MMC_CAP2_NO_SD)) { rc = sd_send_if_cond(mci); rc = sd_send_op_cond(mci); } - if (host->no_sd || rc == -ETIMEDOUT) { + if ((host->caps2 & MMC_CAP2_NO_SD) || rc == -ETIMEDOUT) { /* If SD card initialization was skipped or if it timed out, * we check for an MMC card */ dev_dbg(&mci->dev, "Card seems to be a MultiMediaCard\n"); @@ -1837,6 +2347,13 @@ static int mci_card_probe(struct mci *mci) dev_add_param_bool(&mci->dev, "boot_ack", mci_set_boot_ack, NULL, &mci->boot_ack_enable, mci); + + ret = mci_get_partition_setting_completed(mci); + if (ret < 0) + dev_dbg(&mci->dev, + "Failed to determine EXT_CSD_PARTITION_SETTING_COMPLETED\n"); + else + dev_add_param_bool_fixed(&mci->dev, "partitioning_completed", ret); } dev_dbg(&mci->dev, "SD Card successfully added\n"); @@ -1888,14 +2405,14 @@ int mci_detect_card(struct mci_host *host) return mci_card_probe(host->mci); } -static int mci_detect(struct device_d *dev) +static int mci_detect(struct device *dev) { struct mci *mci = container_of(dev, struct mci, dev); return mci_detect_card(mci->host); } -static int mci_hw_detect(struct device_d *dev) +static int mci_hw_detect(struct device *dev) { struct mci *mci; @@ -1915,8 +2432,8 @@ static int mci_hw_detect(struct device_d *dev) int mci_register(struct mci_host *host) { struct mci *mci; - struct device_d *hw_dev; - struct param_d *param_probe; + struct device *hw_dev; + struct param_d *param; int ret; mci = xzalloc(sizeof(*mci)); @@ -1961,15 +2478,24 @@ int mci_register(struct mci_host *host) dev_info(hw_dev, "registered as %s\n", dev_name(&mci->dev)); - param_probe = dev_add_param_bool(&mci->dev, "probe", - mci_set_probe, NULL, &mci->probe, mci); + param = dev_add_param_bool(&mci->dev, "probe", mci_set_probe, NULL, + &mci->probe, mci); - if (IS_ERR(param_probe) && PTR_ERR(param_probe) != -ENOSYS) { - ret = PTR_ERR(param_probe); + if (IS_ERR(param) && PTR_ERR(param) != -ENOSYS) { + ret = PTR_ERR(param); dev_dbg(&mci->dev, "Failed to add 'probe' parameter to the MCI device\n"); goto err_unregister; } + param = dev_add_param_bool(&mci->dev, "broken_cd", NULL, NULL, + &host->broken_cd, mci); + + if (IS_ERR(param) && PTR_ERR(param) != -ENOSYS) { + ret = PTR_ERR(param); + dev_dbg(&mci->dev, "Failed to add 'broken_cd' parameter to the MCI device\n"); + goto err_unregister; + } + if (IS_ENABLED(CONFIG_MCI_INFO)) mci->dev.info = mci_info; @@ -1977,6 +2503,9 @@ int mci_register(struct mci_host *host) if (IS_ENABLED(CONFIG_MCI_STARTUP)) mci_card_probe(mci); + if (!(host->caps2 & MMC_CAP2_NO_SD) && dev_of_node(host->hw_dev)) + of_register_fixup(of_broken_cd_fixup, host); + list_add_tail(&mci->list, &mci_list); return 0; @@ -2043,14 +2572,40 @@ void mci_of_parse_node(struct mci_host *host, } } + host->broken_cd = of_property_read_bool(np, "broken-cd"); host->non_removable = of_property_read_bool(np, "non-removable"); - host->no_sd = of_property_read_bool(np, "no-sd"); host->disable_wp = of_property_read_bool(np, "disable-wp"); + + if (of_property_read_bool(np, "full-pwr-cycle")) + host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; + if (of_property_read_bool(np, "full-pwr-cycle-in-suspend")) + host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND; + if (of_property_read_bool(np, "no-sdio")) + host->caps2 |= MMC_CAP2_NO_SDIO; + if (of_property_read_bool(np, "no-sd")) + host->caps2 |= MMC_CAP2_NO_SD; + if (of_property_read_bool(np, "no-mmc")) + host->caps2 |= MMC_CAP2_NO_MMC; + if (IS_ENABLED(CONFIG_MCI_TUNING)) { + if (of_property_read_bool(np, "mmc-hs200-1_8v")) + host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; + if (of_property_read_bool(np, "mmc-hs200-1_2v")) + host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; + if (of_property_read_bool(np, "mmc-hs400-1_8v")) + host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR; + if (of_property_read_bool(np, "mmc-hs400-1_2v")) + host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR; + if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe")) + host->caps2 |= MMC_CAP2_HS400_ES; + if (of_property_read_bool(np, "no-mmc-hs400")) + host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V | + MMC_CAP2_HS400_ES); + } } void mci_of_parse(struct mci_host *host) { - return mci_of_parse_node(host, host->hw_dev->device_node); + return mci_of_parse_node(host, host->hw_dev->of_node); } struct mci *mci_get_device_by_name(const char *name) diff --git a/drivers/mci/mci_spi.c b/drivers/mci/mci_spi.c index 6ae2824edd..ad743d19d9 100644 --- a/drivers/mci/mci_spi.c +++ b/drivers/mci/mci_spi.c @@ -19,7 +19,7 @@ #include <crc.h> #include <crc7.h> #include <of.h> -#include <gpiod.h> +#include <linux/gpio/consumer.h> #define to_spi_host(mci) container_of(mci, struct mmc_spi_host, mci) #define spi_setup(spi) spi->master->setup(spi) @@ -48,8 +48,8 @@ struct mmc_spi_host { struct mci_host mci; struct spi_device *spi; - struct device_d *dev; - int detect_pin; + struct device *dev; + struct gpio_desc *detect_pin; /* for bulk data transfers */ struct spi_transfer t_tx; @@ -314,7 +314,7 @@ static void mmc_spi_set_ios(struct mci_host *mci, struct mci_ios *ios) } } -static int mmc_spi_init(struct mci_host *mci, struct device_d *mci_dev) +static int mmc_spi_init(struct mci_host *mci, struct device *mci_dev) { struct mmc_spi_host *host = to_spi_host(mci); mmc_spi_readbytes(host, 10, NULL); @@ -360,15 +360,15 @@ static int spi_mci_card_present(struct mci_host *mci) int ret; /* No gpio, assume card is present */ - if (!gpio_is_valid(host->detect_pin)) + if (IS_ERR_OR_NULL(host->detect_pin)) return 1; - ret = gpio_get_value(host->detect_pin); + ret = gpiod_get_value(host->detect_pin); return ret == 0 ? 1 : 0; } -static int spi_mci_probe(struct device_d *dev) +static int spi_mci_probe(struct device *dev) { struct device_node *np = dev_of_node(dev); struct spi_device *spi = (struct spi_device *)dev->type_data; @@ -434,11 +434,12 @@ static int spi_mci_probe(struct device_d *dev) host->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; host->mci.host_caps = MMC_CAP_SPI; - host->detect_pin = -EINVAL; if (np) { host->mci.devname = xstrdup(of_alias_get(np)); - host->detect_pin = gpiod_get(dev, NULL, GPIOD_IN); + host->detect_pin = gpiod_get_optional(dev, NULL, GPIOD_IN); + if (IS_ERR(host->detect_pin)) + dev_warn(dev, "Failed to get 'reset' GPIO (ignored)\n"); } mci_register(&host->mci); @@ -450,8 +451,9 @@ static __maybe_unused struct of_device_id spi_mci_compatible[] = { { .compatible = "mmc-spi-slot" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, spi_mci_compatible); -static struct driver_d spi_mci_driver = { +static struct driver spi_mci_driver = { .name = "spi_mci", .probe = spi_mci_probe, .of_compatible = DRV_OF_COMPAT(spi_mci_compatible), diff --git a/drivers/mci/mmci.c b/drivers/mci/mmci.c index 2edc37c681..a16deba854 100644 --- a/drivers/mci/mmci.c +++ b/drivers/mci/mmci.c @@ -96,7 +96,7 @@ static struct variant_data variant_ux500v2 = { struct mmci_host { struct mci_host mci; void __iomem *base; - struct device_d *hw_dev; + struct device *hw_dev; struct mmci_platform_data *plat; struct clk *clk; unsigned long mclk; @@ -434,7 +434,7 @@ static int mci_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci_dat } /* MMC uses open drain drivers in the enumeration phase */ -static int mci_reset(struct mci_host *mci, struct device_d *mci_dev) +static int mci_reset(struct mci_host *mci, struct device *mci_dev) { struct mmci_host *host = to_mci_host(mci); struct variant_data *variant = host->variant; @@ -551,8 +551,8 @@ static int mmci_of_parse(struct device_node *np, static int mmci_probe(struct amba_device *dev, const struct amba_id *id) { - struct device_d *hw_dev = &dev->dev; - struct device_node *np = hw_dev->device_node; + struct device *hw_dev = &dev->dev; + struct device_node *np = hw_dev->of_node; struct mmci_platform_data *plat = hw_dev->platform_data; struct variant_data *variant = id->data; u32 sdi_u32; diff --git a/drivers/mci/mxs.c b/drivers/mci/mxs.c index 5d6511f958..6883b78d5c 100644 --- a/drivers/mci/mxs.c +++ b/drivers/mci/mxs.c @@ -27,9 +27,8 @@ #include <linux/clk.h> #include <linux/err.h> #include <asm/bitops.h> -#include <mach/mci.h> -#include <mach/clock.h> -#include <mach/ssp.h> +#include <mach/mxs/mci.h> +#include <mach/mxs/ssp.h> #define CLOCKRATE_MIN (1 * 1000 * 1000) #define CLOCKRATE_MAX (480 * 1000 * 1000) @@ -433,7 +432,7 @@ static unsigned mxs_mci_setup_clock_speed(struct mxs_mci_host *mxs_mci, unsigned * @param mci_dev MCI device instance * @return 0 on success, negative value else */ -static int mxs_mci_initialize(struct mci_host *host, struct device_d *mci_dev) +static int mxs_mci_initialize(struct mci_host *host, struct device *mci_dev) { struct mxs_mci_host *mxs_mci = to_mxs_mci(host); @@ -517,7 +516,7 @@ static void mxs_mci_set_ios(struct mci_host *host, struct mci_ios *ios) const unsigned char bus_width[3] = { 1, 4, 8 }; -static void mxs_mci_info(struct device_d *hw_dev) +static void mxs_mci_info(struct device *hw_dev) { struct mxs_mci_host *mxs_mci = hw_dev->priv; @@ -529,7 +528,7 @@ static void mxs_mci_info(struct device_d *hw_dev) printf("\n"); } -static int mxs_mci_probe(struct device_d *hw_dev) +static int mxs_mci_probe(struct device *hw_dev) { struct resource *iores; struct mxs_mci_platform_data *pd = hw_dev->platform_data; @@ -598,8 +597,9 @@ static __maybe_unused struct of_device_id mxs_mmc_compatible[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, mxs_mmc_compatible); -static struct driver_d mxs_mci_driver = { +static struct driver mxs_mci_driver = { .name = "mxs_mci", .probe = mxs_mci_probe, .of_compatible = DRV_OF_COMPAT(mxs_mmc_compatible), diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c index 61a1f46805..41d5a62f32 100644 --- a/drivers/mci/omap_hsmmc.c +++ b/drivers/mci/omap_hsmmc.c @@ -12,12 +12,12 @@ #include <io.h> #include <linux/err.h> -#include <mach/omap_hsmmc.h> +#include <mach/omap/omap_hsmmc.h> #if defined(CONFIG_MFD_TWL6030) && \ defined(CONFIG_MCI_OMAP_HSMMC) && \ defined(CONFIG_ARCH_OMAP4) -#include <mach/omap4_twl6030_mmc.h> +#include <mach/omap/omap4_twl6030_mmc.h> #endif struct hsmmc { @@ -170,7 +170,7 @@ static struct omap_mmc_driver_data omap4_data = { struct omap_hsmmc { struct mci_host mci; - struct device_d *dev; + struct device *dev; struct hsmmc *base; void __iomem *iobase; }; @@ -207,7 +207,7 @@ static int mmc_init_stream(struct omap_hsmmc *hsmmc) return 0; } -static int mmc_init_setup(struct mci_host *mci, struct device_d *dev) +static int mmc_init_setup(struct mci_host *mci, struct device *dev) { struct omap_hsmmc *hsmmc = to_hsmmc(mci); struct hsmmc *mmc_base = hsmmc->base; @@ -568,7 +568,7 @@ static void mmc_set_ios(struct mci_host *mci, struct mci_ios *ios) writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl); } -static int omap_mmc_probe(struct device_d *dev) +static int omap_mmc_probe(struct device *dev) { struct resource *iores; struct omap_hsmmc *hsmmc; @@ -647,8 +647,9 @@ static __maybe_unused struct of_device_id omap_mmc_dt_ids[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, omap_mmc_dt_ids); -static struct driver_d omap_mmc_driver = { +static struct driver omap_mmc_driver = { .name = "omap-hsmmc", .probe = omap_mmc_probe, .id_table = omap_mmc_ids, diff --git a/drivers/mci/pxamci.c b/drivers/mci/pxamci.c index 1ec871afbf..5df1ef5cb6 100644 --- a/drivers/mci/pxamci.c +++ b/drivers/mci/pxamci.c @@ -15,9 +15,9 @@ #include <mci.h> #include <linux/err.h> -#include <mach/clock.h> -#include <mach/mci_pxa2xx.h> -#include <mach/pxa-regs.h> +#include <mach/pxa/clock.h> +#include <mach/pxa/mci_pxa2xx.h> +#include <mach/pxa/pxa-regs.h> #include "pxamci.h" #define DRIVER_NAME "pxa-mmc" @@ -26,7 +26,7 @@ #define TX_TIMEOUT (250 * MSECOND) #define CMD_TIMEOUT (100 * MSECOND) -static void clk_enable(void) +static void mmc_clk_enable(void) { CKEN |= CKEN_MMC; } @@ -319,7 +319,7 @@ static void pxamci_set_ios(struct mci_host *mci, struct mci_ios *ios) mmc_writel(host->clkrt, MMC_CLKRT); } -static int pxamci_init(struct mci_host *mci, struct device_d *dev) +static int pxamci_init(struct mci_host *mci, struct device *dev) { struct pxamci_host *host = to_pxamci(mci); @@ -328,13 +328,13 @@ static int pxamci_init(struct mci_host *mci, struct device_d *dev) return 0; } -static int pxamci_probe(struct device_d *dev) +static int pxamci_probe(struct device *dev) { struct resource *iores; struct pxamci_host *host; int gpio_power = -1; - clk_enable(); + mmc_clk_enable(); host = xzalloc(sizeof(*host)); iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) @@ -375,7 +375,7 @@ static int pxamci_probe(struct device_d *dev) return 0; } -static struct driver_d pxamci_driver = { +static struct driver pxamci_driver = { .name = DRIVER_NAME, .probe = pxamci_probe, }; diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c index 164f662552..f503dbae65 100644 --- a/drivers/mci/rockchip-dwcmshc-sdhci.c +++ b/drivers/mci/rockchip-dwcmshc-sdhci.c @@ -25,21 +25,32 @@ #define DWCMSHC_EMMC_DLL_RXCLK 0x804 #define DWCMSHC_EMMC_DLL_TXCLK 0x808 #define DWCMSHC_EMMC_DLL_STRBIN 0x80c +#define DECMSHC_EMMC_DLL_CMDOUT 0x810 #define DWCMSHC_EMMC_DLL_STATUS0 0x840 #define DWCMSHC_EMMC_DLL_START BIT(0) +#define DWCMSHC_EMMC_DLL_LOCKED BIT(8) +#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) #define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 #define DWCMSHC_EMMC_DLL_START_POINT 16 #define DWCMSHC_EMMC_DLL_INC 8 +#define DWCMSHC_EMMC_DLL_BYPASS BIT(24) #define DWCMSHC_EMMC_DLL_DLYENA BIT(27) -#define DLL_TXCLK_TAPNUM_DEFAULT 0x8 -#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 +#define DLL_TXCLK_TAPNUM_DEFAULT 0x10 +#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) +#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 #define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) -#define DWCMSHC_EMMC_DLL_LOCKED BIT(8) -#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) +#define DLL_STRBIN_DELAY_NUM_SEL BIT(26) +#define DLL_STRBIN_DELAY_NUM_OFFSET 16 +#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 #define DLL_RXCLK_NO_INVERTER 1 #define DLL_RXCLK_INVERTER 0 -#define DWCMSHC_ENHANCED_STROBE BIT(8) +#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8 +#define DLL_RXCLK_ORI_GATE BIT(31) +#define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24) +#define DLL_CMDOUT_SRC_CLK_NEG BIT(28) +#define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29) + #define DLL_LOCK_WO_TMOUT(x) \ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) @@ -87,26 +98,12 @@ static int rk_sdhci_card_present(struct mci_host *mci) return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT); } -static int rk_sdhci_reset(struct rk_sdhci_host *host, u8 mask) -{ - sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask); - - /* wait for reset completion */ - if (wait_on_timeout(100 * MSECOND, - !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){ - dev_err(host->mci.hw_dev, "SDHCI reset timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int rk_sdhci_init(struct mci_host *mci, struct device_d *dev) +static int rk_sdhci_init(struct mci_host *mci, struct device *dev) { struct rk_sdhci_host *host = to_rk_sdhci_host(mci); int ret; - ret = rk_sdhci_reset(host, SDHCI_RESET_ALL); + ret = sdhci_reset(&host->sdhci, SDHCI_RESET_ALL); if (ret) return ret; @@ -151,8 +148,32 @@ static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock) sdhci_set_clock(&host->sdhci, clock, clk_get_rate(host->clks[CLK_CORE].clk)); - if (clock <= 400000) + /* Disable cmd conflict check */ + extra = sdhci_read32(&host->sdhci, DWCMSHC_HOST_CTRL3); + extra &= ~BIT(0); + sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, extra); + + if (clock <= 52000000) { + /* + * Disable DLL and reset both of sample and drive clock. + * The bypass bit and start bit need to be set if DLL is not locked. + */ + sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, + DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START); + sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_RXCLK, DLL_RXCLK_ORI_GATE); + sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, 0); + sdhci_write32(&host->sdhci, DECMSHC_EMMC_DLL_CMDOUT, 0); + /* + * Before switching to hs400es mode, the driver will enable + * enhanced strobe first. PHY needs to configure the parameters + * of enhanced strobe first. + */ + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_STRBIN_DELAY_NUM_SEL | + DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET; + sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, extra); return; + } /* Reset DLL */ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, BIT(1)); @@ -172,11 +193,6 @@ static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock) return; } - /* Disable cmd conflict check */ - extra = sdhci_read32(&host->sdhci, DWCMSHC_HOST_CTRL3); - extra &= ~BIT(0); - sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, extra); - extra = 0x1 << 16 | /* tune clock stop en */ 0x2 << 17 | /* pre-change delay */ 0x3 << 19; /* post-change delay */ @@ -216,34 +232,11 @@ static void rk_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios) sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val); } -static int rk_sdhci_wait_for_done(struct rk_sdhci_host *host, u32 mask) -{ - u64 start = get_time_ns(); - u16 stat; - - do { - stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS); - if (stat & SDHCI_INT_ERROR) { - dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n", - sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS)); - return -EPERM; - } - - if (is_timeout(start, 1000 * MSECOND)) { - dev_err(host->mci.hw_dev, - "SDHCI timeout while waiting for done\n"); - return -ETIMEDOUT; - } - } while ((stat & mask) != mask); - - return 0; -} - static void print_error(struct rk_sdhci_host *host, int cmdidx) { - dev_err(host->mci.hw_dev, + dev_dbg(host->mci.hw_dev, "error while transfering data for command %d\n", cmdidx); - dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n", + dev_dbg(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n", sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE), sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS)); } @@ -252,23 +245,13 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) { struct rk_sdhci_host *host = to_rk_sdhci_host(mci); - u32 mask, command, xfer; + u32 command, xfer; int ret; dma_addr_t dma; - /* Wait for idle before next command */ - mask = SDHCI_CMD_INHIBIT_CMD; - if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION) - mask |= SDHCI_CMD_INHIBIT_DATA; - - ret = wait_on_timeout(10 * MSECOND, - !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask)); - - if (ret) { - dev_err(host->mci.hw_dev, - "SDHCI timeout while waiting for idle\n"); + ret = sdhci_wait_idle_data(&host->sdhci, cmd); + if (ret) return ret; - } sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); @@ -285,11 +268,9 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); - ret = rk_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE); - if (ret == -EPERM) + ret = sdhci_wait_for_done(&host->sdhci, SDHCI_INT_CMD_COMPLETE); + if (ret) goto error; - else if (ret) - return ret; sdhci_read_response(&host->sdhci, cmd); sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE); @@ -299,15 +280,15 @@ static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, error: if (ret) { print_error(host, cmd->cmdidx); - rk_sdhci_reset(host, BIT(1)); /* SDHCI_RESET_CMD */ - rk_sdhci_reset(host, BIT(2)); /* SDHCI_RESET_DATA */ + sdhci_reset(&host->sdhci, SDHCI_RESET_CMD); + sdhci_reset(&host->sdhci, SDHCI_RESET_DATA); } sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); return ret; } -static int rk_sdhci_probe(struct device_d *dev) +static int rk_sdhci_probe(struct device *dev) { struct rk_sdhci_host *host; struct resource *iores; @@ -365,11 +346,14 @@ static __maybe_unused struct of_device_id rk_sdhci_compatible[] = { { .compatible = "rockchip,rk3568-dwcmshc" }, { + .compatible = "rockchip,rk3588-dwcmshc" + }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, rk_sdhci_compatible); -static struct driver_d rk_sdhci_driver = { +static struct driver rk_sdhci_driver = { .name = "rk3568-dwcmshc-sdhci", .probe = rk_sdhci_probe, .of_compatible = DRV_OF_COMPAT(rk_sdhci_compatible), diff --git a/drivers/mci/s3c.c b/drivers/mci/s3c.c deleted file mode 100644 index 1de57a608f..0000000000 --- a/drivers/mci/s3c.c +++ /dev/null @@ -1,761 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2010 Juergen Beisert <juergen@kreuzholzen.de> -// SPDX-FileCopyrightText: 2004-2006 Thomas Kleffel <tk@maintech.de>, maintech GmbH -// SPDX-FileCopyrightText: 2008 Simtec Electronics <ben-linux@fluff.org> -// SPDX-FileCopyrightText: 2006 OpenMoko, Inc (Harald Welte <laforge@openmoko.org>) -// SPDX-FileCopyrightText: 2005 Thomas Kleffel - -/* - * This code is partially based on Linux and u-boot sources, among others the - * u-boot pxa MMC driver and linux/drivers/mmc/s3c2410mci.c. - */ - -/** - * @file - * @brief MCI card host interface for S3C2440 CPU - */ - -/* #define DEBUG */ - -#include <common.h> -#include <init.h> -#include <mci.h> -#include <errno.h> -#include <clock.h> -#include <io.h> -#include <linux/err.h> -#include <mach/s3c-mci.h> -#include <mach/s3c-generic.h> -#include <mach/s3c-iomap.h> - -#define GET_HOST_DATA(x) (x->priv) -#define GET_MCI_PDATA(x) (x->platform_data) - -#define SDICON 0x0 -# define SDICON_SDRESET (1 << 8) -# define SDICON_MMCCLOCK (1 << 5) /* this is a clock type SD or MMC style WTF? */ -# define SDICON_BYTEORDER (1 << 4) -# define SDICON_SDIOIRQ (1 << 3) -# define SDICON_RWAITEN (1 << 2) -# define SDICON_FIFORESET (1 << 1) /* reserved bit on 2440 ????? */ -# define SDICON_CLKEN (1 << 0) /* enable/disable external clock */ - -#define SDIPRE 0x4 - -#define SDICMDARG 0x8 - -#define SDICMDCON 0xc -# define SDICMDCON_ABORT (1 << 12) -# define SDICMDCON_WITHDATA (1 << 11) -# define SDICMDCON_LONGRSP (1 << 10) -# define SDICMDCON_WAITRSP (1 << 9) -# define SDICMDCON_CMDSTART (1 << 8) -# define SDICMDCON_SENDERHOST (1 << 6) -# define SDICMDCON_INDEX (0x3f) - -#define SDICMDSTAT 0x10 -# define SDICMDSTAT_CRCFAIL (1 << 12) -# define SDICMDSTAT_CMDSENT (1 << 11) -# define SDICMDSTAT_CMDTIMEOUT (1 << 10) -# define SDICMDSTAT_RSPFIN (1 << 9) -# define SDICMDSTAT_XFERING (1 << 8) -# define SDICMDSTAT_INDEX (0xff) - -#define SDIRSP0 0x14 -#define SDIRSP1 0x18 -#define SDIRSP2 0x1C -#define SDIRSP3 0x20 - -#define SDITIMER 0x24 -#define SDIBSIZE 0x28 - -#define SDIDCON 0x2c -# define SDIDCON_DS_BYTE (0 << 22) -# define SDIDCON_DS_HALFWORD (1 << 22) -# define SDIDCON_DS_WORD (2 << 22) -# define SDIDCON_IRQPERIOD (1 << 21) -# define SDIDCON_TXAFTERRESP (1 << 20) -# define SDIDCON_RXAFTERCMD (1 << 19) -# define SDIDCON_BUSYAFTERCMD (1 << 18) -# define SDIDCON_BLOCKMODE (1 << 17) -# define SDIDCON_WIDEBUS (1 << 16) -# define SDIDCON_DMAEN (1 << 15) -# define SDIDCON_STOP (0 << 14) -# define SDIDCON_DATSTART (1 << 14) -# define SDIDCON_DATMODE (3 << 12) -# define SDIDCON_BLKNUM (0xfff) -# define SDIDCON_XFER_READY (0 << 12) -# define SDIDCON_XFER_CHKSTART (1 << 12) -# define SDIDCON_XFER_RXSTART (2 << 12) -# define SDIDCON_XFER_TXSTART (3 << 12) - -#define SDIDCNT 0x30 -# define SDIDCNT_BLKNUM_SHIFT 12 - -#define SDIDSTA 0x34 -# define SDIDSTA_RDYWAITREQ (1 << 10) -# define SDIDSTA_SDIOIRQDETECT (1 << 9) -# define SDIDSTA_FIFOFAIL (1 << 8) /* reserved on 2440 */ -# define SDIDSTA_CRCFAIL (1 << 7) -# define SDIDSTA_RXCRCFAIL (1 << 6) -# define SDIDSTA_DATATIMEOUT (1 << 5) -# define SDIDSTA_XFERFINISH (1 << 4) -# define SDIDSTA_BUSYFINISH (1 << 3) -# define SDIDSTA_SBITERR (1 << 2) /* reserved on 2410a/2440 */ -# define SDIDSTA_TXDATAON (1 << 1) -# define SDIDSTA_RXDATAON (1 << 0) - -#define SDIFSTA 0x38 -# define SDIFSTA_FIFORESET (1<<16) -# define SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */ -# define SDIFSTA_TFDET (1<<13) -# define SDIFSTA_RFDET (1<<12) -# define SDIFSTA_TFHALF (1<<11) -# define SDIFSTA_TFEMPTY (1<<10) -# define SDIFSTA_RFLAST (1<<9) -# define SDIFSTA_RFFULL (1<<8) -# define SDIFSTA_RFHALF (1<<7) -# define SDIFSTA_COUNTMASK (0x7f) - -#define SDIIMSK 0x3C -# define SDIIMSK_RESPONSECRC (1<<17) -# define SDIIMSK_CMDSENT (1<<16) -# define SDIIMSK_CMDTIMEOUT (1<<15) -# define SDIIMSK_RESPONSEND (1<<14) -# define SDIIMSK_READWAIT (1<<13) -# define SDIIMSK_SDIOIRQ (1<<12) -# define SDIIMSK_FIFOFAIL (1<<11) -# define SDIIMSK_CRCSTATUS (1<<10) -# define SDIIMSK_DATACRC (1<<9) -# define SDIIMSK_DATATIMEOUT (1<<8) -# define SDIIMSK_DATAFINISH (1<<7) -# define SDIIMSK_BUSYFINISH (1<<6) -# define SDIIMSK_SBITERR (1<<5) /* reserved 2440/2410a */ -# define SDIIMSK_TXFIFOHALF (1<<4) -# define SDIIMSK_TXFIFOEMPTY (1<<3) -# define SDIIMSK_RXFIFOLAST (1<<2) -# define SDIIMSK_RXFIFOFULL (1<<1) -# define SDIIMSK_RXFIFOHALF (1<<0) - -#define SDIDATA 0x40 - -struct s3c_mci_host { - struct mci_host host; - void __iomem *base; - int bus_width:2; /* 0 = 1 bit, 1 = 4 bit, 2 = 8 bit */ - unsigned clock; /* current clock in Hz */ - unsigned data_size; /* data transfer in bytes */ -}; - -#define to_s3c_host(h) container_of(h, struct s3c_mci_host, host) - -/** - * Finish a request - * @param hw_dev Host interface instance - * - * Just a little bit paranoia. - */ -static void s3c_finish_request(struct s3c_mci_host *host_data) -{ - /* TODO ensure the engines are stopped */ -} - -/** - * Setup a new clock frequency on this MCI bus - * @param hw_dev Host interface instance - * @param nc New clock value in Hz (can be 0) - * @return New clock value (may differ from 'nc') - */ -static unsigned s3c_setup_clock_speed(struct s3c_mci_host *host_data, unsigned nc) -{ - unsigned clock; - uint32_t mci_psc; - - if (nc == 0) - return 0; - - clock = s3c_get_pclk(); - /* Calculate the required prescaler value to get the requested frequency */ - mci_psc = (clock + (nc >> 2)) / nc; - - if (mci_psc > 256) { - mci_psc = 256; - pr_warning("SD/MMC clock might be too high!\n"); - } - - writel(mci_psc - 1, host_data->base + SDIPRE); - - return clock / mci_psc; -} - -/** - * Reset the MCI engine (the hard way) - * @param hw_dev Host interface instance - * - * This will reset everything in all registers of this unit! - */ -static void s3c_mci_reset(struct s3c_mci_host *host_data) -{ - /* reset the hardware */ - writel(SDICON_SDRESET, host_data->base + SDICON); - /* wait until reset it finished */ - while (readl(host_data->base + SDICON) & SDICON_SDRESET) - ; -} - -/** - * Initialize hard and software - * @param hw_dev Host interface instance - * @param mci_dev MCI device instance (might be NULL) - */ -static int s3c_mci_initialize(struct s3c_mci_host *host_data, struct device_d *mci_dev) -{ - s3c_mci_reset(host_data); - - /* restore last settings */ - host_data->clock = s3c_setup_clock_speed(host_data, host_data->clock); - writel(0x007FFFFF, host_data->base + SDITIMER); - writel(SDICON_MMCCLOCK, host_data->base + SDICON); - writel(512, host_data->base + SDIBSIZE); - - return 0; -} - -/** - * Prepare engine's bits for the next command transfer - * @param cmd_flags MCI's command flags - * @param data_flags MCI's data flags - * @return Register bits for this transfer - */ -static uint32_t s3c_prepare_command_setup(unsigned cmd_flags, unsigned data_flags) -{ - uint32_t reg; - - /* source (=host) */ - reg = SDICMDCON_SENDERHOST; - - if (cmd_flags & MMC_RSP_PRESENT) { - reg |= SDICMDCON_WAITRSP; - pr_debug("Command with response\n"); - } - if (cmd_flags & MMC_RSP_136) { - reg |= SDICMDCON_LONGRSP; - pr_debug("Command with long response\n"); - } - if (cmd_flags & MMC_RSP_CRC) - ; /* FIXME */ - if (cmd_flags & MMC_RSP_BUSY) - ; /* FIXME */ - if (cmd_flags & MMC_RSP_OPCODE) - ; /* FIXME */ - if (data_flags != 0) - reg |= SDICMDCON_WITHDATA; - - return reg; -} - -/** - * Prepare engine's bits for the next data transfer - * @param hw_dev Host interface device instance - * @param data_flags MCI's data flags - * @return Register bits for this transfer - */ -static uint32_t s3c_prepare_data_setup(struct s3c_mci_host *host_data, unsigned data_flags) -{ - uint32_t reg = SDIDCON_BLOCKMODE; /* block mode only is supported */ - - if (host_data->bus_width == 1) - reg |= SDIDCON_WIDEBUS; - - /* enable any kind of data transfers on demand only */ - if (data_flags & MMC_DATA_WRITE) - reg |= SDIDCON_TXAFTERRESP | SDIDCON_XFER_TXSTART; - - if (data_flags & MMC_DATA_READ) - reg |= SDIDCON_RXAFTERCMD | SDIDCON_XFER_RXSTART; - - /* TODO: Support more than the 2440 CPU */ - reg |= SDIDCON_DS_WORD | SDIDCON_DATSTART; - - return reg; -} - -/** - * Terminate a current running transfer - * @param hw_dev Host interface device instance - * @return 0 on success - * - * Note: Try to stop a running transfer. This should not happen, as all - * transfers must complete in this driver. But who knows... ;-) - */ -static int s3c_terminate_transfer(struct s3c_mci_host *host_data) -{ - unsigned stoptries = 3; - - while (readl(host_data->base + SDIDSTA) & (SDIDSTA_TXDATAON | SDIDSTA_RXDATAON)) { - pr_debug("Transfer still in progress.\n"); - - writel(SDIDCON_STOP, host_data->base + SDIDCON); - s3c_mci_initialize(host_data, NULL); - - if ((stoptries--) == 0) { - pr_warning("Cannot stop the engine!\n"); - return -EINVAL; - } - } - - return 0; -} - -/** - * Setup registers for data transfer - * @param hw_dev Host interface device instance - * @param data The data information (buffer, direction aso.) - * @return 0 on success - */ -static int s3c_prepare_data_transfer(struct s3c_mci_host *host_data, struct mci_data *data) -{ - uint32_t reg; - - writel(data->blocksize, host_data->base + SDIBSIZE); - reg = s3c_prepare_data_setup(host_data, data->flags); - reg |= data->blocks & SDIDCON_BLKNUM; - writel(reg, host_data->base + SDIDCON); - writel(0x007FFFFF, host_data->base + SDITIMER); - - return 0; -} - -/** - * Send a command and receive the response - * @param hw_dev Host interface device instance - * @param cmd The command to handle - * @param data The data information (buffer, direction aso.) - * @return 0 on success - */ -static int s3c_send_command(struct s3c_mci_host *host_data, struct mci_cmd *cmd, - struct mci_data *data) -{ - uint32_t reg, t1; - int rc; - - writel(0x007FFFFF, host_data->base + SDITIMER); - - /* setup argument */ - writel(cmd->cmdarg, host_data->base + SDICMDARG); - - /* setup command and transfer characteristic */ - reg = s3c_prepare_command_setup(cmd->resp_type, data != NULL ? data->flags : 0); - reg |= cmd->cmdidx & SDICMDCON_INDEX; - - /* run the command right now */ - writel(reg | SDICMDCON_CMDSTART, host_data->base + SDICMDCON); - t1 = readl(host_data->base + SDICMDSTAT); - /* wait until command is done */ - while (1) { - reg = readl(host_data->base + SDICMDSTAT); - /* done? */ - if (cmd->resp_type & MMC_RSP_PRESENT) { - if (reg & SDICMDSTAT_RSPFIN) { - writel(SDICMDSTAT_RSPFIN, - host_data->base + SDICMDSTAT); - rc = 0; - break; - } - } else { - if (reg & SDICMDSTAT_CMDSENT) { - writel(SDICMDSTAT_CMDSENT, - host_data->base + SDICMDSTAT); - rc = 0; - break; - } - } - /* timeout? */ - if (reg & SDICMDSTAT_CMDTIMEOUT) { - writel(SDICMDSTAT_CMDTIMEOUT, - host_data->base + SDICMDSTAT); - rc = -ETIMEDOUT; - break; - } - } - - if ((rc == 0) && (cmd->resp_type & MMC_RSP_PRESENT)) { - cmd->response[0] = readl(host_data->base + SDIRSP0); - cmd->response[1] = readl(host_data->base + SDIRSP1); - cmd->response[2] = readl(host_data->base + SDIRSP2); - cmd->response[3] = readl(host_data->base + SDIRSP3); - } - /* do not disable the clock! */ - return rc; -} - -/** - * Clear major registers prior a new transaction - * @param hw_dev Host interface device instance - * @return 0 on success - * - * FIFO clear is only necessary on 2440, but doesn't hurt on 2410 - */ -static int s3c_prepare_engine(struct s3c_mci_host *host_data) -{ - int rc; - - rc = s3c_terminate_transfer(host_data); - if (rc != 0) - return rc; - - writel(-1, host_data->base + SDICMDSTAT); - writel(-1, host_data->base + SDIDSTA); - writel(-1, host_data->base + SDIFSTA); - - return 0; -} - -/** - * Handle MCI commands without data - * @param hw_dev Host interface device instance - * @param cmd The command to handle - * @return 0 on success - * - * This functions handles the following MCI commands: - * - "broadcast command (BC)" without a response - * - "broadcast commands with response (BCR)" - * - "addressed command (AC)" with response, but without data - */ -static int s3c_mci_std_cmds(struct s3c_mci_host *host_data, struct mci_cmd *cmd) -{ - int rc; - - rc = s3c_prepare_engine(host_data); - if (rc != 0) - return 0; - - return s3c_send_command(host_data, cmd, NULL); -} - -/** - * Read one block of data from the FIFO - * @param hw_dev Host interface device instance - * @param data The data information (buffer, direction aso.) - * @return 0 on success - */ -static int s3c_mci_read_block(struct s3c_mci_host *host_data, struct mci_data *data) -{ - uint32_t *p; - unsigned cnt, data_size; - -#define READ_REASON_TO_FAIL (SDIDSTA_CRCFAIL | SDIDSTA_RXCRCFAIL | SDIDSTA_DATATIMEOUT) - - p = (uint32_t*)data->dest; - data_size = data->blocksize * data->blocks; - - while (data_size > 0) { - - /* serious error? */ - if (readl(host_data->base + SDIDSTA) & READ_REASON_TO_FAIL) { - pr_err("Failed while reading data\n"); - return -EIO; - } - - /* now check the FIFO status */ - if (readl(host_data->base + SDIFSTA) & SDIFSTA_FIFOFAIL) { - pr_err("Data loss due to FIFO overflow when reading\n"); - return -EIO; - } - - /* we only want to read full words */ - cnt = (readl(host_data->base + SDIFSTA) & SDIFSTA_COUNTMASK) >> 2; - - /* read one chunk of data from the FIFO */ - while (cnt--) { - *p = readl(host_data->base + SDIDATA); - p++; - if (data_size >= 4) - data_size -= 4; - else { - data_size = 0; - break; - } - } - } - - return 0; -} - -/** - * Write one block of data into the FIFO - * @param hw_dev Host interface device instance - * @param cmd The command to handle - * @param data The data information (buffer, direction aso.) - * @return 0 on success - * - * We must ensure data in the FIFO when the command phase changes into the - * data phase. To ensure this, the FIFO gets filled first, then the command. - */ -static int s3c_mci_write_block(struct s3c_mci_host *host_data, struct mci_cmd *cmd, - struct mci_data *data) -{ - const uint32_t *p = (const uint32_t*)data->src; - unsigned cnt, data_size; - uint32_t reg; - -#define WRITE_REASON_TO_FAIL (SDIDSTA_CRCFAIL | SDIDSTA_DATATIMEOUT) - - data_size = data->blocksize * data->blocks; - /* - * With high clock rates we must fill the FIFO as early as possible - * Its size is 16 words. We assume its empty, when this function is - * entered. - */ - cnt = 16; - while (cnt--) { - writel(*p, host_data->base + SDIDATA); - p++; - if (data_size >= 4) - data_size -= 4; - else { - data_size = 0; - break; - } - } - - /* data is now in place and waits for transmitt. Start the command right now */ - s3c_send_command(host_data, cmd, data); - - if ((reg = readl(host_data->base + SDIFSTA)) & SDIFSTA_FIFOFAIL) { - pr_err("Command fails immediatly due to FIFO underrun when writing %08X\n", - reg); - return -EIO; - } - - while (data_size > 0) { - - if (readl(host_data->base + SDIDSTA) & WRITE_REASON_TO_FAIL) { - pr_err("Failed writing data\n"); - return -EIO; - } - - /* now check the FIFO status */ - if ((reg = readl(host_data->base + SDIFSTA)) & SDIFSTA_FIFOFAIL) { - pr_err("Data loss due to FIFO underrun when writing %08X\n", - reg); - return -EIO; - } - - /* we only want to write full words */ - cnt = 16 - (((readl(host_data->base + SDIFSTA) & SDIFSTA_COUNTMASK) + 3) >> 2); - - /* fill the FIFO if it has free entries */ - while (cnt--) { - writel(*p, host_data->base + SDIDATA); - p++; - if (data_size >= 4) - data_size -= 4; - else { - data_size = 0; - break; - } - } - } - - return 0; -} - -/** - * Handle MCI commands with or without data - * @param hw_dev Host interface device instance - * @param cmd The command to handle - * @param data The data information (buffer, direction aso.) - * @return 0 on success -*/ -static int s3c_mci_adtc(struct s3c_mci_host *host_data, struct mci_cmd *cmd, - struct mci_data *data) -{ - int rc; - - rc = s3c_prepare_engine(host_data); - if (rc != 0) - return rc; - - rc = s3c_prepare_data_transfer(host_data, data); - if (rc != 0) - return rc; - - if (data->flags & MMC_DATA_READ) { - s3c_send_command(host_data, cmd, data); - rc = s3c_mci_read_block(host_data, data); - if (rc == 0) { - while (!(readl(host_data->base + SDIDSTA) & SDIDSTA_XFERFINISH)) - ; - } else - s3c_terminate_transfer(host_data); - } - - if (data->flags & MMC_DATA_WRITE) { - rc = s3c_mci_write_block(host_data, cmd, data); - if (rc == 0) { - while (!(readl(host_data->base + SDIDSTA) & SDIDSTA_XFERFINISH)) - ; - } else - s3c_terminate_transfer(host_data); - } - writel(0, host_data->base + SDIDCON); - - return rc; -} - -/* ------------------------- MCI API -------------------------------------- */ - -/** - * Keep the attached MMC/SD unit in a well know state - * @param host MCI host - * @param mci_dev MCI device instance - * @return 0 on success, negative value else - */ -static int mci_reset(struct mci_host *host, struct device_d *mci_dev) -{ - struct s3c_mci_host *host_data = to_s3c_host(host); - - return s3c_mci_initialize(host_data, mci_dev); -} - -/** - * Process one command to the MCI card - * @param host MCI host - * @param cmd The command to process - * @param data The data to handle in the command (can be NULL) - * @return 0 on success, negative value else - */ -static int mci_request(struct mci_host *host, struct mci_cmd *cmd, - struct mci_data *data) -{ - struct s3c_mci_host *host_data = to_s3c_host(host); - int rc; - - /* enable clock */ - writel(readl(host_data->base + SDICON) | SDICON_CLKEN, - host_data->base + SDICON); - - if ((cmd->resp_type == 0) || (data == NULL)) - rc = s3c_mci_std_cmds(host_data, cmd); - else - rc = s3c_mci_adtc(host_data, cmd, data); /* with response and data */ - - s3c_finish_request(host_data); - - /* disable clock */ - writel(readl(host_data->base + SDICON) & ~SDICON_CLKEN, - host_data->base + SDICON); - return rc; -} - -/** - * Setup the bus width and IO speed - * @param host MCI host - * @param bus_width New bus width value (1, 4 or 8) - * @param clock New clock in Hz (can be '0' to disable the clock) - */ -static void mci_set_ios(struct mci_host *host, struct mci_ios *ios) -{ - struct s3c_mci_host *host_data = to_s3c_host(host); - uint32_t reg; - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_4: - host_data->bus_width = 1; - break; - case MMC_BUS_WIDTH_1: - host_data->bus_width = 0; - break; - default: - return; - } - - reg = readl(host_data->base + SDICON); - if (ios->clock) { - /* setup the IO clock frequency and enable it */ - host_data->clock = s3c_setup_clock_speed(host_data, ios->clock); - reg |= SDICON_CLKEN; /* enable the clock */ - } else { - reg &= ~SDICON_CLKEN; /* disable the clock */ - host_data->clock = 0; - } - writel(reg, host_data->base + SDICON); - - pr_debug("IO settings: bus width=%d, frequency=%u Hz\n", - host_data->bus_width, host_data->clock); -} - -/* ----------------------------------------------------------------------- */ - -static void s3c_info(struct device_d *hw_dev) -{ - struct s3c_mci_host *host = hw_dev->priv; - struct s3c_mci_platform_data *pd = hw_dev->platform_data; - - printf(" Bus data width: %d bit\n", host->bus_width == 1 ? 4 : 1); - printf(" Bus frequency: %u Hz\n", host->clock); - printf(" Frequency limits: "); - if (pd->f_min == 0) - printf("no lower limit "); - else - printf("%u Hz lower limit ", pd->f_min); - if (pd->f_max == 0) - printf("- no upper limit"); - else - printf("- %u Hz upper limit", pd->f_max); - printf("\n Card detection support: %s\n", - pd->gpio_detect != 0 ? "yes" : "no"); -} - -static int s3c_mci_probe(struct device_d *hw_dev) -{ - struct resource *iores; - struct s3c_mci_host *s3c_host; - struct s3c_mci_platform_data *pd = hw_dev->platform_data; - - s3c_host = xzalloc(sizeof(*s3c_host)); - s3c_host->host.send_cmd = mci_request; - s3c_host->host.set_ios = mci_set_ios; - s3c_host->host.init = mci_reset; - - /* TODO replace by the global func: enable the SDI unit clock */ - writel(readl(S3C_CLOCK_POWER_BASE + 0x0c) | 0x200, - S3C_CLOCK_POWER_BASE + 0x0c); - - if (pd == NULL) { - pr_err("Missing platform data\n"); - return -EINVAL; - } - - hw_dev->priv = s3c_host; - iores = dev_request_mem_resource(hw_dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - s3c_host->base = IOMEM(iores->start); - - s3c_host->host.hw_dev = hw_dev; - - /* feed forward the platform specific values */ - s3c_host->host.voltages = pd->voltages; - s3c_host->host.host_caps = pd->caps; - s3c_host->host.f_min = pd->f_min == 0 ? s3c_get_pclk() / 256 : pd->f_min; - s3c_host->host.f_max = pd->f_max == 0 ? s3c_get_pclk() / 2 : pd->f_max; - - if (IS_ENABLED(CONFIG_MCI_INFO)) - hw_dev->info = s3c_info; - - /* - * Start the clock to let the engine and the card finishes its startup - */ - s3c_host->clock = s3c_setup_clock_speed(s3c_host, pd->f_min); - writel(SDICON_FIFORESET | SDICON_MMCCLOCK, s3c_host->base + SDICON); - - return mci_register(&s3c_host->host); -} - -static struct driver_d s3c_mci_driver = { - .name = "s3c_mci", - .probe = s3c_mci_probe, -}; -device_platform_driver(s3c_mci_driver); diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c index 8da32d57c2..ba1e07e966 100644 --- a/drivers/mci/sdhci.c +++ b/drivers/mci/sdhci.c @@ -9,6 +9,227 @@ #include "sdhci.h" +#define MAX_TUNING_LOOP 40 +#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) + +enum sdhci_reset_reason { + SDHCI_RESET_FOR_INIT, + SDHCI_RESET_FOR_REQUEST_ERROR, + SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY, + SDHCI_RESET_FOR_TUNING_ABORT, + SDHCI_RESET_FOR_CARD_REMOVED, + SDHCI_RESET_FOR_CQE_RECOVERY, +}; + +static void sdhci_reset_for_reason(struct sdhci *host, enum sdhci_reset_reason reason) +{ + if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) { + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + return; + } + + switch (reason) { + case SDHCI_RESET_FOR_INIT: + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + break; + case SDHCI_RESET_FOR_REQUEST_ERROR: + case SDHCI_RESET_FOR_TUNING_ABORT: + case SDHCI_RESET_FOR_CARD_REMOVED: + case SDHCI_RESET_FOR_CQE_RECOVERY: + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); + break; + case SDHCI_RESET_FOR_REQUEST_ERROR_DATA_ONLY: + sdhci_reset(host, SDHCI_RESET_DATA); + break; + } +} + +#define sdhci_reset_for(h, r) sdhci_reset_for_reason((h), SDHCI_RESET_FOR_##r) + +static int sdhci_send_command_retry(struct sdhci *host, struct mci_cmd *cmd) +{ + int timeout = 10; + + while ((sdhci_read32(host, SDHCI_PRESENT_STATE) & SDHCI_CMD_INHIBIT_CMD)) { + if (!timeout--) + return -ETIMEDOUT; + + mdelay(1); + } + + return host->mci->send_cmd(host->mci, cmd, NULL); +} + +/* + * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI + * tuning command does not have a data payload (or rather the hardware does it + * automatically) so mmc_send_tuning() will return -EIO. Also the tuning command + * interrupt setup is different to other commands and there is no timeout + * interrupt so special handling is needed. + */ +static int sdhci_send_tuning(struct sdhci *host, u32 opcode) +{ + struct mci_cmd cmd = {}; + int ret; + + cmd.cmdidx = opcode; + cmd.resp_type = MMC_RSP_R1 | MMC_CMD_ADTC; + + /* + * In response to CMD19, the card sends 64 bytes of tuning + * block to the Host Controller. So we set the block size + * to 64 here. + */ + if (cmd.cmdidx == MMC_SEND_TUNING_BLOCK_HS200 && + host->mci->bus_width == MMC_BUS_WIDTH_8) { + sdhci_write16(host, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 128)); + } else { + sdhci_write16(host, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 64)); + } + + ret = sdhci_send_command_retry(host, &cmd); + + return ret; +} + +static void sdhci_end_tuning(struct sdhci *host) +{ + sdhci_write32(host, SDHCI_INT_ENABLE, host->tuning_old_ier); + sdhci_write32(host, SDHCI_SIGNAL_ENABLE, host->tuning_old_sig); +} + +static void sdhci_start_tuning(struct sdhci *host) +{ + u16 ctrl; + + ctrl = sdhci_read16(host, SDHCI_HOST_CONTROL2); + ctrl |= SDHCI_CTRL_EXEC_TUNING; + sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl); + + mdelay(1); + + host->tuning_old_ier = sdhci_read32(host, SDHCI_INT_ENABLE); + host->tuning_old_sig = sdhci_read32(host, SDHCI_SIGNAL_ENABLE); + + sdhci_write32(host, SDHCI_INT_ENABLE, SDHCI_INT_DATA_AVAIL); + sdhci_write32(host, SDHCI_SIGNAL_ENABLE, SDHCI_INT_DATA_AVAIL); +} + +static void sdhci_reset_tuning(struct sdhci *host) +{ + u16 ctrl; + + ctrl = sdhci_read16(host, SDHCI_HOST_CONTROL2); + ctrl &= ~SDHCI_CTRL_TUNED_CLK; + ctrl &= ~SDHCI_CTRL_EXEC_TUNING; + sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl); +} + +static void sdhci_abort_tuning(struct sdhci *host, u32 opcode) +{ + sdhci_reset_tuning(host); + + sdhci_reset_for(host, TUNING_ABORT); + + sdhci_end_tuning(host); + + mci_send_abort_tuning(host->mci->mci, opcode); +} + +static int __sdhci_execute_tuning(struct sdhci *host, u32 opcode) +{ + int i; + int ret; + + /* + * Issue opcode repeatedly till Execute Tuning is set to 0 or the number + * of loops reaches tuning loop count. + * Some controllers are known to always require 40 iterations. + */ + for (i = 0; i < host->tuning_loop_count; i++) { + u16 ctrl; + + ret = sdhci_send_tuning(host, opcode); + if (ret) { + sdhci_abort_tuning(host, opcode); + return -ETIMEDOUT; + } + + /* Spec does not require a delay between tuning cycles */ + if (host->tuning_delay > 0) + mdelay(host->tuning_delay); + + ctrl = sdhci_read16(host, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { + if (ctrl & SDHCI_CTRL_TUNED_CLK) { + return 0; /* Success! */ + } + break; + } + + } + + dev_dbg(&host->mci->mci->dev, "Tuning timeout, falling back to fixed sampling clock\n"); + sdhci_reset_tuning(host); + return -EAGAIN; +} + +int sdhci_execute_tuning(struct sdhci *sdhci, u32 opcode) +{ + struct mci_host *host = sdhci->mci; + int err = 0; + unsigned int tuning_count = 0; + + if (sdhci->tuning_mode == SDHCI_TUNING_MODE_1) + tuning_count = sdhci->tuning_count; + + /* + * The Host Controller needs tuning in case of SDR104 and DDR50 + * mode, and for SDR50 mode when Use Tuning for SDR50 is set in + * the Capabilities register. + * If the Host Controller supports the HS200 mode then the + * tuning function has to be executed. + */ + switch (host->timing) { + /* HS400 tuning is done in HS200 mode */ + case MMC_TIMING_MMC_HS400: + err = -EINVAL; + goto out; + + case MMC_TIMING_MMC_HS200: + break; + + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_DDR50: + break; + + case MMC_TIMING_UHS_SDR50: + fallthrough; + + default: + goto out; + } + + if (sdhci->platform_execute_tuning) { + err = sdhci->platform_execute_tuning(host, opcode); + goto out; + } + + if (sdhci->tuning_delay < 0) + sdhci->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK; + + sdhci_start_tuning(sdhci); + + sdhci->tuning_err = __sdhci_execute_tuning(sdhci, opcode); + + sdhci_end_tuning(sdhci); +out: + + return err; +} +EXPORT_SYMBOL_GPL(sdhci_execute_tuning); + void sdhci_read_response(struct sdhci *sdhci, struct mci_cmd *cmd) { if (cmd->resp_type & MMC_RSP_136) { @@ -50,7 +271,12 @@ void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd, *command |= SDHCI_CMD_INDEX(cmd->cmdidx); - if (data) { + if (cmd->cmdidx == MMC_SEND_TUNING_BLOCK || + cmd->cmdidx == MMC_SEND_TUNING_BLOCK_HS200) { + *command |= SDHCI_DATA_PRESENT; + *xfer = SDHCI_DATA_TO_HOST; + + } else if (data) { *command |= SDHCI_DATA_PRESENT; *xfer |= SDHCI_BLOCK_COUNT_EN; @@ -111,6 +337,60 @@ void sdhci_set_bus_width(struct sdhci *host, int width) sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl); } +static void sdhci_set_uhs_signaling(struct sdhci *host, unsigned timing) +{ + u16 ctrl_2; + + ctrl_2 = sdhci_read16(host, SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + if ((timing == MMC_TIMING_MMC_HS200) || + (timing == MMC_TIMING_UHS_SDR104)) + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + else if (timing == MMC_TIMING_UHS_SDR12) + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + else if (timing == MMC_TIMING_UHS_SDR25) + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + else if (timing == MMC_TIMING_UHS_SDR50) + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + else if ((timing == MMC_TIMING_UHS_DDR50) || + (timing == MMC_TIMING_MMC_DDR52)) + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */ + sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl_2); +} +EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); + +static inline bool sdhci_can_64bit_dma(struct sdhci *host) +{ + /* + * According to SD Host Controller spec v4.10, bit[27] added from + * version 4.10 in Capabilities Register is used as 64-bit System + * Address support for V4 mode. + */ + if (host->version >= SDHCI_SPEC_410 && host->v4_mode) + return host->caps & SDHCI_CAN_64BIT_V4; + + return host->caps & SDHCI_CAN_64BIT; +} + + +static void sdhci_set_adma_addr(struct sdhci *host, dma_addr_t addr) +{ + sdhci_write32(host, SDHCI_ADMA_ADDRESS, lower_32_bits(addr)); + if (host->flags & SDHCI_USE_64_BIT_DMA) + sdhci_write32(host, SDHCI_ADMA_ADDRESS_HI, upper_32_bits(addr)); +} + +static void sdhci_set_sdma_addr(struct sdhci *host, dma_addr_t addr) +{ + if (host->v4_mode) + sdhci_set_adma_addr(host, addr); + else + sdhci_write32(host, SDHCI_DMA_ADDRESS, addr); +} + #ifdef __PBL__ /* * Stubs to make timeout logic below work in PBL @@ -124,6 +404,33 @@ void sdhci_set_bus_width(struct sdhci *host, int width) #endif +int sdhci_wait_for_done(struct sdhci *sdhci, u32 mask) +{ + u64 start = get_time_ns(); + u32 stat; + + do { + stat = sdhci_read32(sdhci, SDHCI_INT_STATUS); + + if (stat & SDHCI_INT_TIMEOUT) + return -ETIMEDOUT; + + if (stat & SDHCI_INT_ERROR) { + dev_err(sdhci->mci->hw_dev, "SDHCI_INT_ERROR: 0x%08x\n", + stat); + return -EPERM; + } + + if (is_timeout(start, 1000 * MSECOND)) { + dev_err(sdhci->mci->hw_dev, + "SDHCI timeout while waiting for done\n"); + return -ETIMEDOUT; + } + } while ((stat & mask) != mask); + + return 0; +} + void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data) { if (!data) @@ -133,10 +440,37 @@ void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data) SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize) | data->blocks << 16); } +static void sdhci_config_dma(struct sdhci *host) +{ + u8 ctrl; + u16 ctrl2; + + if (host->version < SDHCI_SPEC_200) + return; + + ctrl = sdhci_read8(host, SDHCI_HOST_CONTROL); + /* Note if DMA Select is zero then SDMA is selected */ + ctrl &= ~SDHCI_CTRL_DMA_MASK; + sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl); + + if (host->flags & SDHCI_USE_64_BIT_DMA) { + /* + * If v4 mode, all supported DMA can be 64-bit addressing if + * controller supports 64-bit system address, otherwise only + * ADMA can support 64-bit addressing. + */ + if (host->v4_mode) { + ctrl2 = sdhci_read16(host, SDHCI_HOST_CONTROL2); + ctrl2 |= SDHCI_CTRL_64BIT_ADDR; + sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl2); + } + } +} + void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t *dma) { - struct device_d *dev = sdhci->mci->hw_dev; + struct device *dev = sdhci->mci->hw_dev; int nbytes; if (!data) @@ -150,10 +484,10 @@ void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, nbytes = data->blocks * data->blocksize; if (data->flags & MMC_DATA_READ) - *dma = dma_map_single(dev, (void *)data->src, nbytes, + *dma = dma_map_single(dev, data->dest, nbytes, DMA_FROM_DEVICE); else - *dma = dma_map_single(dev, data->dest, nbytes, + *dma = dma_map_single(dev, (void *)data->src, nbytes, DMA_TO_DEVICE); if (dma_mapping_error(dev, *dma)) { @@ -161,13 +495,15 @@ void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, return; } - sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, *dma); + sdhci_config_dma(sdhci); + sdhci_set_sdma_addr(sdhci, *dma); } int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma) { - struct device_d *dev = sdhci->mci->hw_dev; + struct device *dev = sdhci->mci->hw_dev; + u64 start; int nbytes; u32 irqstat; int ret; @@ -177,6 +513,8 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data, nbytes = data->blocks * data->blocksize; + start = get_time_ns(); + do { irqstat = sdhci_read32(sdhci, SDHCI_INT_STATUS); @@ -195,19 +533,33 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data, goto out; } + /* + * We currently don't do anything fancy with DMA + * boundaries, but as we can't disable the feature + * we need to at least restart the transfer. + * + * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS) + * should return a valid address to continue from, but as + * some controllers are faulty, don't trust them. + */ if (irqstat & SDHCI_INT_DMA) { - u32 addr = sdhci_read32(sdhci, SDHCI_DMA_ADDRESS); - /* * DMA engine has stopped on buffer boundary. Acknowledge * the interrupt and kick the DMA engine again. */ sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA); - sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, addr); + sdhci_set_sdma_addr(sdhci, ALIGN(dma, SDHCI_DEFAULT_BOUNDARY_SIZE)); } if (irqstat & SDHCI_INT_XFER_COMPLETE) break; + + if (is_timeout(start, 10 * SECOND)) { + dev_alert(dev, "DMA wait timed out. Resetting, but recovery unlikely\n"); + sdhci_reset(sdhci, SDHCI_RESET_ALL); + ret = -ETIMEDOUT; + goto out; + } } while (1); ret = 0; @@ -217,7 +569,7 @@ out: else dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE); - return 0; + return ret; } int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data) @@ -263,7 +615,7 @@ int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data) int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma) { - struct device_d *dev = sdhci->mci->hw_dev; + struct device *dev = sdhci->mci->hw_dev; if (!data) return 0; @@ -436,6 +788,53 @@ void sdhci_enable_clk(struct sdhci *host, u16 clk) sdhci_write16(host, SDHCI_CLOCK_CONTROL, clk); } +int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data) +{ + u32 mask; + int ret; + + mask = SDHCI_CMD_INHIBIT_CMD; + + if (data || (cmd && (cmd->resp_type & MMC_RSP_BUSY))) + mask |= SDHCI_CMD_INHIBIT_DATA; + + if (cmd && cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + mask &= ~SDHCI_CMD_INHIBIT_DATA; + + ret = wait_on_timeout(10 * MSECOND, + !(sdhci_read32(host, SDHCI_PRESENT_STATE) & mask)); + + if (ret) { + dev_err(host->mci->hw_dev, + "SDHCI timeout while waiting for idle\n"); + return -EBUSY; + } + + return 0; +} + +int sdhci_wait_idle_data(struct sdhci *host, struct mci_cmd *cmd) +{ + u32 mask; + int ret; + + mask = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA; + + if (cmd && cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) + mask &= ~SDHCI_CMD_INHIBIT_DATA; + + ret = wait_on_timeout(10 * MSECOND, + !(sdhci_read32(host, SDHCI_PRESENT_STATE) & mask)); + + if (ret) { + dev_err(host->mci->hw_dev, + "SDHCI timeout while waiting for idle\n"); + return -EBUSY; + } + + return 0; +} + void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock) { u16 clk; @@ -444,6 +843,10 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_ host->mci->clock = 0; + sdhci_set_uhs_signaling(host, host->mci->timing); + + sdhci_wait_idle_data(host, NULL); + sdhci_write16(host, SDHCI_CLOCK_CONTROL, 0); if (clock == 0) @@ -453,13 +856,31 @@ void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_ sdhci_enable_clk(host, clk); } +static void sdhci_do_enable_v4_mode(struct sdhci *host) +{ + u16 ctrl2; + + ctrl2 = sdhci_read16(host, SDHCI_HOST_CONTROL2); + if (ctrl2 & SDHCI_CTRL_V4_MODE) + return; + + ctrl2 |= SDHCI_CTRL_V4_MODE; + sdhci_write16(host, SDHCI_HOST_CONTROL2, ctrl2); +} + +void sdhci_enable_v4_mode(struct sdhci *host) +{ + host->v4_mode = true; + sdhci_do_enable_v4_mode(host); +} + void __sdhci_read_caps(struct sdhci *host, const u16 *ver, const u32 *caps, const u32 *caps1) { u16 v; u64 dt_caps_mask = 0; u64 dt_caps = 0; - struct device_node *np = host->mci->hw_dev->device_node; + struct device_node *np = host->mci->hw_dev->of_node; BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */ @@ -470,6 +891,9 @@ void __sdhci_read_caps(struct sdhci *host, const u16 *ver, sdhci_reset(host, SDHCI_RESET_ALL); + if (host->v4_mode) + sdhci_do_enable_v4_mode(host); + of_property_read_u64(np, "sdhci-caps-mask", &dt_caps_mask); of_property_read_u64(np, "sdhci-caps", &dt_caps); @@ -541,7 +965,33 @@ int sdhci_setup_host(struct sdhci *host) if (host->caps & SDHCI_CAN_DO_HISPD) mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - host->sdma_boundary = SDHCI_DMA_BOUNDARY_512K; + if (host->caps & SDHCI_CAN_DO_8BIT) + mci->host_caps |= MMC_CAP_8_BIT_DATA; + + host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG; + + if (sdhci_can_64bit_dma(host)) + host->flags |= SDHCI_USE_64_BIT_DMA; + + if ((mci->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) + host->flags |= SDHCI_SIGNALING_180; + + host->tuning_delay = -1; + host->tuning_loop_count = MAX_TUNING_LOOP; + + /* Initial value for re-tuning timer count */ + host->tuning_count = FIELD_GET(SDHCI_RETUNING_TIMER_COUNT_MASK, + host->caps1); + + /* + * In case Re-tuning Timer is not disabled, the actual value of + * re-tuning timer will be 2 ^ (n - 1). + */ + if (host->tuning_count) + host->tuning_count = 1 << (host->tuning_count - 1); + + /* Re-tuning mode supported by the Host Controller */ + host->tuning_mode = FIELD_GET(SDHCI_RETUNING_MODE_MASK, host->caps1); return 0; } diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h index c538385939..5de85239b1 100644 --- a/drivers/mci/sdhci.h +++ b/drivers/mci/sdhci.h @@ -5,6 +5,7 @@ #include <pbl.h> #include <dma.h> #include <linux/iopoll.h> +#include <linux/sizes.h> #define SDHCI_DMA_ADDRESS 0x00 #define SDHCI_BLOCK_SIZE__BLOCK_COUNT 0x04 @@ -18,6 +19,8 @@ #define SDHCI_DMA_BOUNDARY_8K SDHCI_DMA_BOUNDARY(1) #define SDHCI_DMA_BOUNDARY_4K SDHCI_DMA_BOUNDARY(0) #define SDHCI_DMA_BOUNDARY(x) (((x) & 0x7) << 12) +#define SDHCI_DEFAULT_BOUNDARY_SIZE SZ_512K +#define SDHCI_DEFAULT_BOUNDARY_ARG SDHCI_DMA_BOUNDARY_512K #define SDHCI_TRANSFER_BLOCK_SIZE(x) ((x) & 0xfff) #define SDHCI_BLOCK_COUNT 0x06 #define SDHCI_ARGUMENT 0x08 @@ -25,9 +28,11 @@ #define SDHCI_TRANSFER_MODE 0x0c #define SDHCI_MULTIPLE_BLOCKS BIT(5) #define SDHCI_DATA_TO_HOST BIT(4) +#define SDHCI_TRNS_AUTO_CMD12 BIT(3) #define SDHCI_BLOCK_COUNT_EN BIT(1) #define SDHCI_DMA_EN BIT(0) #define SDHCI_COMMAND 0x0e +#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) #define SDHCI_CMD_INDEX(c) (((c) & 0x3f) << 8) #define SDHCI_COMMAND_CMDTYP_SUSPEND (1 << 6) #define SDHCI_COMMAND_CMDTYP_RESUME (2 << 6) @@ -117,6 +122,18 @@ #define SDHCI_INT_ERROR_ENABLE 0x36 #define SDHCI_SIGNAL_ENABLE 0x38 #define SDHCI_ACMD12_ERR__HOST_CONTROL2 0x3C +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL_UHS_MASK GENMASK(3, 0) +#define SDHCI_CTRL_UHS_SDR12 0x0 +#define SDHCI_CTRL_UHS_SDR25 0x1 +#define SDHCI_CTRL_UHS_SDR50 0x2 +#define SDHCI_CTRL_UHS_SDR104 0x3 +#define SDHCI_CTRL_UHS_DDR50 0x4 +#define SDHCI_CTRL_HS400 0x5 /* Non-standard */ +#define SDHCI_CTRL_EXEC_TUNING BIT(6) +#define SDHCI_CTRL_TUNED_CLK BIT(7) +#define SDHCI_CTRL_64BIT_ADDR BIT(13) +#define SDHCI_CTRL_V4_MODE BIT(12) #define SDHCI_CAPABILITIES 0x40 #define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0) #define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 @@ -159,6 +176,8 @@ #define SDHCI_PRESET_CLKGEN_SEL BIT(10) #define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0) +#define SDHCI_P_VENDOR_SPEC_AREA 0xE8 +#define SDHCI_P_VENDOR_SPEC_AREA_MASK GENMASK(11, 0) #define SDHCI_HOST_VERSION 0xFE #define SDHCI_VENDOR_VER_MASK 0xFF00 #define SDHCI_VENDOR_VER_SHIFT 8 @@ -173,6 +192,9 @@ #define SDHCI_CLOCK_MUL_SHIFT 16 +#define SDHCI_ADMA_ADDRESS 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5c + #define SDHCI_MMC_BOOT 0xC4 #define SDHCI_MAX_DIV_SPEC_200 256 @@ -191,21 +213,52 @@ struct sdhci { int max_clk; /* Max possible freq (Hz) */ int clk_mul; /* Clock Muliplier value */ + int flags; /* Host attributes */ +#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */ +#define SDHCI_USE_ADMA (1<<1) /* Host is ADMA capable */ +#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */ +#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */ +#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */ +#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ +#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ +#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ +#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ +#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ +#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */ +#define SDHCI_SIGNALING_180 (1<<15) /* Host is capable of 1.8V signaling */ +#define SDHCI_SIGNALING_120 (1<<16) /* Host is capable of 1.2V signaling */ + unsigned int version; /* SDHCI spec. version */ enum mci_timing timing; bool preset_enabled; /* Preset is enabled */ + bool v4_mode; /* Host Version 4 Enable */ unsigned int quirks; #define SDHCI_QUIRK_MISSING_CAPS BIT(27) unsigned int quirks2; #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN BIT(15) +#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER BIT(19) u32 caps; /* CAPABILITY_0 */ u32 caps1; /* CAPABILITY_1 */ bool read_caps; /* Capability flags have been read */ u32 sdma_boundary; + unsigned int tuning_count; /* Timer count for re-tuning */ + unsigned int tuning_mode; /* Re-tuning mode supported by host */ + unsigned int tuning_err; /* Error code for re-tuning */ +#define SDHCI_TUNING_MODE_1 0 +#define SDHCI_TUNING_MODE_2 1 +#define SDHCI_TUNING_MODE_3 2 + /* Delay (ms) between tuning commands */ + int tuning_delay; + int tuning_loop_count; + int tuning_old_ier; + int tuning_old_sig; + struct mci_host *mci; + + int (*platform_execute_tuning)(struct mci_host *host, u32 opcode); }; static inline u32 sdhci_read32(struct sdhci *host, int reg) @@ -257,6 +310,10 @@ static inline void sdhci_write8(struct sdhci *host, int reg, u32 val) } #define SDHCI_NO_DMA DMA_ERROR_CODE +int sdhci_execute_tuning(struct sdhci *sdhci, u32 opcode); +int sdhci_wait_idle_data(struct sdhci *host, struct mci_cmd *cmd); +int sdhci_wait_idle(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data); +int sdhci_wait_for_done(struct sdhci *host, u32 mask); void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd); void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd, struct mci_data *data, bool dma, u32 *command, @@ -272,6 +329,7 @@ u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock, unsigned int *actual_clock, unsigned int input_clock); void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock); void sdhci_enable_clk(struct sdhci *host, u16 clk); +void sdhci_enable_v4_mode(struct sdhci *host); int sdhci_setup_host(struct sdhci *host); void __sdhci_read_caps(struct sdhci *host, const u16 *ver, const u32 *caps, const u32 *caps1); diff --git a/drivers/mci/stm32_sdmmc2.c b/drivers/mci/stm32_sdmmc2.c index 40ffc17908..418213a1b3 100644 --- a/drivers/mci/stm32_sdmmc2.c +++ b/drivers/mci/stm32_sdmmc2.c @@ -176,7 +176,7 @@ struct stm32_sdmmc2_priv { void __iomem *base; struct mci_host mci; - struct device_d *dev; + struct device *dev; struct clk *clk; struct reset_control *reset_ctl; u32 clk_reg_msk; @@ -185,7 +185,7 @@ struct stm32_sdmmc2_priv { #define to_mci_host(mci) container_of(mci, struct stm32_sdmmc2_priv, mci) -static int stm32_sdmmc2_reset(struct mci_host *mci, struct device_d *mci_dev) +static int stm32_sdmmc2_reset(struct mci_host *mci, struct device *mci_dev) { struct stm32_sdmmc2_priv *priv = to_mci_host(mci); @@ -257,11 +257,12 @@ static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_priv *priv) udelay(DIV_ROUND_UP(74 * USEC_PER_SEC, priv->mci.clock)); } -static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, - struct mci_data *data, u32 data_length) +static dma_addr_t stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, + struct mci_data *data, u32 data_length) { unsigned int num_bytes = data->blocks * data->blocksize; - u32 data_ctrl, idmabase0; + dma_addr_t idmabase0; + u32 data_ctrl; /* Configure the SDMMC DPSM (Data Path State Machine) */ data_ctrl = (__ilog2_u32(data->blocksize) << @@ -270,27 +271,27 @@ static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, if (data->flags & MMC_DATA_READ) { data_ctrl |= SDMMC_DCTRL_DTDIR; - idmabase0 = (u32)data->dest; + idmabase0 = dma_map_single(priv->dev, (void *)data->src, num_bytes, + DMA_FROM_DEVICE); } else { - idmabase0 = (u32)data->src; + idmabase0 = dma_map_single(priv->dev, (void *)data->src, num_bytes, + DMA_TO_DEVICE); } + if (dma_mapping_error(priv->dev, idmabase0)) + return DMA_ERROR_CODE; + /* Set the SDMMC DataLength value */ writel(data_length, priv->base + SDMMC_DLEN); /* Write to SDMMC DCTRL */ writel(data_ctrl, priv->base + SDMMC_DCTRL); - if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_device((unsigned long)idmabase0, - num_bytes, DMA_TO_DEVICE); - else - dma_sync_single_for_device((unsigned long)idmabase0, - num_bytes, DMA_FROM_DEVICE); - /* Enable internal DMA */ writel(idmabase0, priv->base + SDMMC_IDMABASE0); writel(SDMMC_IDMACTRL_IDMAEN, priv->base + SDMMC_IDMACTRL); + + return idmabase0; } static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv, @@ -415,7 +416,8 @@ static int stm32_sdmmc2_end_cmd(struct stm32_sdmmc2_priv *priv, static int stm32_sdmmc2_end_data(struct stm32_sdmmc2_priv *priv, struct mci_cmd *cmd, - struct mci_data *data) + struct mci_data *data, + dma_addr_t dma_addr) { u32 mask = SDMMC_STA_DCRCFAIL | SDMMC_STA_DTIMEOUT | SDMMC_STA_IDMATE | SDMMC_STA_DATAEND; @@ -436,12 +438,10 @@ static int stm32_sdmmc2_end_data(struct stm32_sdmmc2_priv *priv, return ret; } - if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_cpu((unsigned long)data->src, - num_bytes, DMA_TO_DEVICE); + if (data->flags & MMC_DATA_READ) + dma_unmap_single(priv->dev, dma_addr, num_bytes, DMA_FROM_DEVICE); else - dma_sync_single_for_cpu((unsigned long)data->dest, - num_bytes, DMA_FROM_DEVICE); + dma_unmap_single(priv->dev, dma_addr, num_bytes, DMA_TO_DEVICE); if (status & SDMMC_STA_DCRCFAIL) { dev_err(priv->dev, "error SDMMC_STA_DCRCFAIL (0x%x) for cmd %d\n", @@ -481,23 +481,26 @@ static int stm32_sdmmc2_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, { struct stm32_sdmmc2_priv *priv = to_mci_host(mci); u32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0; + dma_addr_t dma_addr = DMA_ERROR_CODE; u32 data_length = 0; int ret; if (data) { data_length = data->blocks * data->blocksize; - stm32_sdmmc2_start_data(priv, data, data_length); + dma_addr = stm32_sdmmc2_start_data(priv, data, data_length); + if (dma_addr == DMA_ERROR_CODE) + return -EFAULT; } stm32_sdmmc2_start_cmd(priv, cmd, cmdat, data_length); - dev_dbg(priv->dev, "%s: send cmd %d data: 0x%x @ 0x%x\n", __func__, - cmd->cmdidx, data ? data_length : 0, (unsigned int)data); + dev_dbg(priv->dev, "%s: send cmd %d data: 0x%x @ %p\n", __func__, + cmd->cmdidx, data ? data_length : 0, data); ret = stm32_sdmmc2_end_cmd(priv, cmd); if (data && !ret) - ret = stm32_sdmmc2_end_data(priv, cmd, data); + ret = stm32_sdmmc2_end_data(priv, cmd, data, dma_addr); /* Clear flags */ writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR); @@ -538,11 +541,14 @@ static void stm32_sdmmc2_set_ios(struct mci_host *mci, struct mci_ios *ios) struct stm32_sdmmc2_priv *priv = to_mci_host(mci); u32 desired = mci->clock; u32 sys_clock = clk_get_rate(priv->clk); - u32 clk = 0; + u32 clk = 0, ddr = 0; dev_dbg(priv->dev, "%s: bus_width = %d, clock = %d\n", __func__, mci->bus_width, mci->clock); + if (mci_timing_is_ddr(ios->timing)) + ddr = SDMMC_CLKCR_DDR; + if (mci->clock) stm32_sdmmc2_pwron(priv); else @@ -555,13 +561,15 @@ static void stm32_sdmmc2_set_ios(struct mci_host *mci, struct mci_ios *ios) * clk_div > 0 and NEGEDGE = 1 => command and data generated on * SDMMCCLK falling edge */ - if (desired && (sys_clock > desired || + if (desired && (sys_clock > desired || ddr || IS_RISING_EDGE(priv->clk_reg_msk))) { clk = DIV_ROUND_UP(sys_clock, 2 * desired); if (clk > SDMMC_CLKCR_CLKDIV_MAX) clk = SDMMC_CLKCR_CLKDIV_MAX; } + clk |= ddr; + if (mci->bus_width == MMC_BUS_WIDTH_4) clk |= SDMMC_CLKCR_WIDBUS_4; if (mci->bus_width == MMC_BUS_WIDTH_8) @@ -574,8 +582,8 @@ static void stm32_sdmmc2_set_ios(struct mci_host *mci, struct mci_ios *ios) static int stm32_sdmmc2_probe(struct amba_device *adev, const struct amba_id *id) { - struct device_d *dev = &adev->dev; - struct device_node *np = dev->device_node; + struct device *dev = &adev->dev; + struct device_node *np = dev->of_node; struct stm32_sdmmc2_priv *priv; struct mci_host *mci; int ret; @@ -624,6 +632,11 @@ static int stm32_sdmmc2_probe(struct amba_device *adev, if (mci->f_max >= 52000000) mci->host_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ; + if (of_property_read_bool(np, "mmc-ddr-3_3v")) + mci->host_caps |= MMC_CAP_MMC_3_3V_DDR; + if (of_property_read_bool(np, "mmc-ddr-1_8v")) + mci->host_caps |= MMC_CAP_MMC_1_8V_DDR; + return mci_register(&priv->mci); priv_free: diff --git a/drivers/mci/tegra-sdmmc.c b/drivers/mci/tegra-sdmmc.c index 756fb94c52..e940edf322 100644 --- a/drivers/mci/tegra-sdmmc.c +++ b/drivers/mci/tegra-sdmmc.c @@ -113,13 +113,15 @@ static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, num_bytes = data->blocks * data->blocksize; if (data->flags & MMC_DATA_WRITE) { - dma_sync_single_for_device((unsigned long)data->src, + dma_sync_single_for_device(mci->hw_dev, (unsigned long)data->src, num_bytes, DMA_TO_DEVICE); - sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->src); + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, + lower_32_bits(virt_to_phys(data->src))); } else { - dma_sync_single_for_device((unsigned long)data->dest, + dma_sync_single_for_device(mci->hw_dev, (unsigned long)data->dest, num_bytes, DMA_FROM_DEVICE); - sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, (u32)data->dest); + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, + lower_32_bits(virt_to_phys(data->dest))); } sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT, @@ -220,10 +222,10 @@ static int tegra_sdmmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, val); if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_cpu((unsigned long)data->src, + dma_sync_single_for_cpu(mci->hw_dev, (unsigned long)data->src, num_bytes, DMA_TO_DEVICE); else - dma_sync_single_for_cpu((unsigned long)data->dest, + dma_sync_single_for_cpu(mci->hw_dev, (unsigned long)data->dest, num_bytes, DMA_FROM_DEVICE); } @@ -282,7 +284,7 @@ static void tegra_sdmmc_set_ios(struct mci_host *mci, struct mci_ios *ios) sdhci_write32(&host->sdhci, TEGRA_SDMMC_PWR_CNTL, val); } -static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev) +static int tegra_sdmmc_init(struct mci_host *mci, struct device *dev) { struct tegra_sdmmc_host *host = to_tegra_sdmmc_host(mci); void __iomem *regs = host->regs; @@ -308,9 +310,8 @@ static int tegra_sdmmc_init(struct mci_host *mci, struct device_d *dev) sdhci_write32(&host->sdhci, TEGRA_SDMMC_PWR_CNTL, val); /* sdmmc1 and sdmmc3 on T30 need a bit of padctrl init */ - if (of_device_is_compatible(mci->hw_dev->device_node, - "nvidia,tegra30-sdhci") && - ((u32)regs == 0x78000000 || (u32)regs == 78000400)) { + if (of_device_is_compatible(mci->hw_dev->of_node, "nvidia,tegra30-sdhci") && + (regs == IOMEM(0x78000000) || regs == IOMEM(0x78000400))) { val = readl(regs + TEGRA_SDMMC_SDMEMCOMPPADCTRL); val &= 0xfffffff0; val |= 0x7 << TEGRA_SDMMC_SDMEMCOMPPADCTRL_VREF_SEL_SHIFT; @@ -366,14 +367,14 @@ static int tegra_sdmmc_card_present(struct mci_host *mci) static void tegra_sdmmc_parse_dt(struct tegra_sdmmc_host *host) { - struct device_node *np = host->mci.hw_dev->device_node; + struct device_node *np = host->mci.hw_dev->of_node; host->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); host->gpio_pwr = of_get_named_gpio(np, "power-gpios", 0); mci_of_parse(&host->mci); } -static int tegra_sdmmc_probe(struct device_d *dev) +static int tegra_sdmmc_probe(struct device *dev) { struct resource *iores; struct tegra_sdmmc_host *host; @@ -451,8 +452,9 @@ static __maybe_unused struct of_device_id tegra_sdmmc_compatible[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, tegra_sdmmc_compatible); -static struct driver_d tegra_sdmmc_driver = { +static struct driver tegra_sdmmc_driver = { .name = "tegra-sdmmc", .probe = tegra_sdmmc_probe, .of_compatible = DRV_OF_COMPAT(tegra_sdmmc_compatible), |