0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/acpi.h>
0009 #include <linux/delay.h>
0010 #include <linux/module.h>
0011 #include <linux/mmc/host.h>
0012 #include <linux/of.h>
0013 #include <linux/of_device.h>
0014 #include "sdhci-pltfm.h"
0015
0016 struct sdhci_iproc_data {
0017 const struct sdhci_pltfm_data *pdata;
0018 u32 caps;
0019 u32 caps1;
0020 u32 mmc_caps;
0021 };
0022
0023 struct sdhci_iproc_host {
0024 const struct sdhci_iproc_data *data;
0025 u32 shadow_cmd;
0026 u32 shadow_blk;
0027 bool is_cmd_shadowed;
0028 bool is_blk_shadowed;
0029 };
0030
0031 #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
0032
0033 static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg)
0034 {
0035 u32 val = readl(host->ioaddr + reg);
0036
0037 pr_debug("%s: readl [0x%02x] 0x%08x\n",
0038 mmc_hostname(host->mmc), reg, val);
0039 return val;
0040 }
0041
0042 static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg)
0043 {
0044 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0045 struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
0046 u32 val;
0047 u16 word;
0048
0049 if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) {
0050
0051 val = iproc_host->shadow_cmd;
0052 } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
0053 iproc_host->is_blk_shadowed) {
0054
0055 val = iproc_host->shadow_blk;
0056 } else {
0057 val = sdhci_iproc_readl(host, (reg & ~3));
0058 }
0059 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
0060 return word;
0061 }
0062
0063 static u8 sdhci_iproc_readb(struct sdhci_host *host, int reg)
0064 {
0065 u32 val = sdhci_iproc_readl(host, (reg & ~3));
0066 u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff;
0067 return byte;
0068 }
0069
0070 static inline void sdhci_iproc_writel(struct sdhci_host *host, u32 val, int reg)
0071 {
0072 pr_debug("%s: writel [0x%02x] 0x%08x\n",
0073 mmc_hostname(host->mmc), reg, val);
0074
0075 writel(val, host->ioaddr + reg);
0076
0077 if (host->clock <= 400000) {
0078
0079 if (host->clock)
0080 udelay((4 * 1000000 + host->clock - 1) / host->clock);
0081 else
0082 udelay(10);
0083 }
0084 }
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg)
0106 {
0107 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0108 struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
0109 u32 word_shift = REG_OFFSET_IN_BITS(reg);
0110 u32 mask = 0xffff << word_shift;
0111 u32 oldval, newval;
0112
0113 if (reg == SDHCI_COMMAND) {
0114
0115 if (iproc_host->is_blk_shadowed) {
0116 sdhci_iproc_writel(host, iproc_host->shadow_blk,
0117 SDHCI_BLOCK_SIZE);
0118 iproc_host->is_blk_shadowed = false;
0119 }
0120 oldval = iproc_host->shadow_cmd;
0121 iproc_host->is_cmd_shadowed = false;
0122 } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
0123 iproc_host->is_blk_shadowed) {
0124
0125 oldval = iproc_host->shadow_blk;
0126 } else {
0127
0128 oldval = sdhci_iproc_readl(host, (reg & ~3));
0129 }
0130 newval = (oldval & ~mask) | (val << word_shift);
0131
0132 if (reg == SDHCI_TRANSFER_MODE) {
0133
0134 iproc_host->shadow_cmd = newval;
0135 iproc_host->is_cmd_shadowed = true;
0136 } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
0137
0138 iproc_host->shadow_blk = newval;
0139 iproc_host->is_blk_shadowed = true;
0140 } else {
0141
0142 sdhci_iproc_writel(host, newval, reg & ~3);
0143 }
0144 }
0145
0146 static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg)
0147 {
0148 u32 oldval = sdhci_iproc_readl(host, (reg & ~3));
0149 u32 byte_shift = REG_OFFSET_IN_BITS(reg);
0150 u32 mask = 0xff << byte_shift;
0151 u32 newval = (oldval & ~mask) | (val << byte_shift);
0152
0153 sdhci_iproc_writel(host, newval, reg & ~3);
0154 }
0155
0156 static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host)
0157 {
0158 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0159
0160 if (pltfm_host->clk)
0161 return sdhci_pltfm_clk_get_max_clock(host);
0162 else
0163 return pltfm_host->clock;
0164 }
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178 static unsigned int sdhci_iproc_bcm2711_get_min_clock(struct sdhci_host *host)
0179 {
0180 return 200000;
0181 }
0182
0183 static const struct sdhci_ops sdhci_iproc_ops = {
0184 .set_clock = sdhci_set_clock,
0185 .get_max_clock = sdhci_iproc_get_max_clock,
0186 .set_bus_width = sdhci_set_bus_width,
0187 .reset = sdhci_reset,
0188 .set_uhs_signaling = sdhci_set_uhs_signaling,
0189 };
0190
0191 static const struct sdhci_ops sdhci_iproc_32only_ops = {
0192 .read_l = sdhci_iproc_readl,
0193 .read_w = sdhci_iproc_readw,
0194 .read_b = sdhci_iproc_readb,
0195 .write_l = sdhci_iproc_writel,
0196 .write_w = sdhci_iproc_writew,
0197 .write_b = sdhci_iproc_writeb,
0198 .set_clock = sdhci_set_clock,
0199 .get_max_clock = sdhci_iproc_get_max_clock,
0200 .set_bus_width = sdhci_set_bus_width,
0201 .reset = sdhci_reset,
0202 .set_uhs_signaling = sdhci_set_uhs_signaling,
0203 };
0204
0205 static const struct sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = {
0206 .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
0207 SDHCI_QUIRK_NO_HISPD_BIT,
0208 .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_HOST_OFF_CARD_ON,
0209 .ops = &sdhci_iproc_32only_ops,
0210 };
0211
0212 static const struct sdhci_iproc_data iproc_cygnus_data = {
0213 .pdata = &sdhci_iproc_cygnus_pltfm_data,
0214 .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
0215 & SDHCI_MAX_BLOCK_MASK) |
0216 SDHCI_CAN_VDD_330 |
0217 SDHCI_CAN_VDD_180 |
0218 SDHCI_CAN_DO_SUSPEND |
0219 SDHCI_CAN_DO_HISPD |
0220 SDHCI_CAN_DO_ADMA2 |
0221 SDHCI_CAN_DO_SDMA,
0222 .caps1 = SDHCI_DRIVER_TYPE_C |
0223 SDHCI_DRIVER_TYPE_D |
0224 SDHCI_SUPPORT_DDR50,
0225 .mmc_caps = MMC_CAP_1_8V_DDR,
0226 };
0227
0228 static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
0229 .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
0230 SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 |
0231 SDHCI_QUIRK_NO_HISPD_BIT,
0232 .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
0233 .ops = &sdhci_iproc_ops,
0234 };
0235
0236 static const struct sdhci_iproc_data iproc_data = {
0237 .pdata = &sdhci_iproc_pltfm_data,
0238 .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
0239 & SDHCI_MAX_BLOCK_MASK) |
0240 SDHCI_CAN_VDD_330 |
0241 SDHCI_CAN_VDD_180 |
0242 SDHCI_CAN_DO_SUSPEND |
0243 SDHCI_CAN_DO_HISPD |
0244 SDHCI_CAN_DO_ADMA2 |
0245 SDHCI_CAN_DO_SDMA,
0246 .caps1 = SDHCI_DRIVER_TYPE_C |
0247 SDHCI_DRIVER_TYPE_D |
0248 SDHCI_SUPPORT_DDR50,
0249 };
0250
0251 static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
0252 .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
0253 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
0254 SDHCI_QUIRK_MISSING_CAPS |
0255 SDHCI_QUIRK_NO_HISPD_BIT,
0256 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
0257 .ops = &sdhci_iproc_32only_ops,
0258 };
0259
0260 static const struct sdhci_iproc_data bcm2835_data = {
0261 .pdata = &sdhci_bcm2835_pltfm_data,
0262 .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
0263 & SDHCI_MAX_BLOCK_MASK) |
0264 SDHCI_CAN_VDD_330 |
0265 SDHCI_CAN_DO_HISPD,
0266 .caps1 = SDHCI_DRIVER_TYPE_A |
0267 SDHCI_DRIVER_TYPE_C,
0268 .mmc_caps = 0x00000000,
0269 };
0270
0271 static const struct sdhci_ops sdhci_iproc_bcm2711_ops = {
0272 .read_l = sdhci_iproc_readl,
0273 .read_w = sdhci_iproc_readw,
0274 .read_b = sdhci_iproc_readb,
0275 .write_l = sdhci_iproc_writel,
0276 .write_w = sdhci_iproc_writew,
0277 .write_b = sdhci_iproc_writeb,
0278 .set_clock = sdhci_set_clock,
0279 .set_power = sdhci_set_power_and_bus_voltage,
0280 .get_max_clock = sdhci_iproc_get_max_clock,
0281 .get_min_clock = sdhci_iproc_bcm2711_get_min_clock,
0282 .set_bus_width = sdhci_set_bus_width,
0283 .reset = sdhci_reset,
0284 .set_uhs_signaling = sdhci_set_uhs_signaling,
0285 };
0286
0287 static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = {
0288 .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
0289 .ops = &sdhci_iproc_bcm2711_ops,
0290 };
0291
0292 static const struct sdhci_iproc_data bcm2711_data = {
0293 .pdata = &sdhci_bcm2711_pltfm_data,
0294 .mmc_caps = MMC_CAP_3_3V_DDR,
0295 };
0296
0297 static const struct sdhci_pltfm_data sdhci_bcm7211a0_pltfm_data = {
0298 .quirks = SDHCI_QUIRK_MISSING_CAPS |
0299 SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
0300 SDHCI_QUIRK_BROKEN_DMA |
0301 SDHCI_QUIRK_BROKEN_ADMA,
0302 .ops = &sdhci_iproc_ops,
0303 };
0304
0305 #define BCM7211A0_BASE_CLK_MHZ 100
0306 static const struct sdhci_iproc_data bcm7211a0_data = {
0307 .pdata = &sdhci_bcm7211a0_pltfm_data,
0308 .caps = ((BCM7211A0_BASE_CLK_MHZ / 2) << SDHCI_TIMEOUT_CLK_SHIFT) |
0309 (BCM7211A0_BASE_CLK_MHZ << SDHCI_CLOCK_BASE_SHIFT) |
0310 ((0x2 << SDHCI_MAX_BLOCK_SHIFT)
0311 & SDHCI_MAX_BLOCK_MASK) |
0312 SDHCI_CAN_VDD_330 |
0313 SDHCI_CAN_VDD_180 |
0314 SDHCI_CAN_DO_SUSPEND |
0315 SDHCI_CAN_DO_HISPD,
0316 .caps1 = SDHCI_DRIVER_TYPE_C |
0317 SDHCI_DRIVER_TYPE_D,
0318 };
0319
0320 static const struct of_device_id sdhci_iproc_of_match[] = {
0321 { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
0322 { .compatible = "brcm,bcm2711-emmc2", .data = &bcm2711_data },
0323 { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data},
0324 { .compatible = "brcm,sdhci-iproc", .data = &iproc_data },
0325 { .compatible = "brcm,bcm7211a0-sdhci", .data = &bcm7211a0_data },
0326 { }
0327 };
0328 MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
0329
0330 #ifdef CONFIG_ACPI
0331
0332
0333
0334
0335 static const struct sdhci_pltfm_data sdhci_bcm_arasan_data = {
0336 .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
0337 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
0338 SDHCI_QUIRK_NO_HISPD_BIT,
0339 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
0340 .ops = &sdhci_iproc_32only_ops,
0341 };
0342
0343 static const struct sdhci_iproc_data bcm_arasan_data = {
0344 .pdata = &sdhci_bcm_arasan_data,
0345 };
0346
0347 static const struct acpi_device_id sdhci_iproc_acpi_ids[] = {
0348 { .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data },
0349 { .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data },
0350 { .id = "BCM2847", .driver_data = (kernel_ulong_t)&bcm_arasan_data },
0351 { .id = "BRCME88C", .driver_data = (kernel_ulong_t)&bcm2711_data },
0352 { }
0353 };
0354 MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids);
0355 #endif
0356
0357 static int sdhci_iproc_probe(struct platform_device *pdev)
0358 {
0359 struct device *dev = &pdev->dev;
0360 const struct sdhci_iproc_data *iproc_data = NULL;
0361 struct sdhci_host *host;
0362 struct sdhci_iproc_host *iproc_host;
0363 struct sdhci_pltfm_host *pltfm_host;
0364 int ret;
0365
0366 iproc_data = device_get_match_data(dev);
0367 if (!iproc_data)
0368 return -ENODEV;
0369
0370 host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host));
0371 if (IS_ERR(host))
0372 return PTR_ERR(host);
0373
0374 pltfm_host = sdhci_priv(host);
0375 iproc_host = sdhci_pltfm_priv(pltfm_host);
0376
0377 iproc_host->data = iproc_data;
0378
0379 ret = mmc_of_parse(host->mmc);
0380 if (ret)
0381 goto err;
0382
0383 sdhci_get_property(pdev);
0384
0385 host->mmc->caps |= iproc_host->data->mmc_caps;
0386
0387 if (dev->of_node) {
0388 pltfm_host->clk = devm_clk_get(dev, NULL);
0389 if (IS_ERR(pltfm_host->clk)) {
0390 ret = PTR_ERR(pltfm_host->clk);
0391 goto err;
0392 }
0393 ret = clk_prepare_enable(pltfm_host->clk);
0394 if (ret) {
0395 dev_err(dev, "failed to enable host clk\n");
0396 goto err;
0397 }
0398 }
0399
0400 if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
0401 host->caps = iproc_host->data->caps;
0402 host->caps1 = iproc_host->data->caps1;
0403 }
0404
0405 ret = sdhci_add_host(host);
0406 if (ret)
0407 goto err_clk;
0408
0409 return 0;
0410
0411 err_clk:
0412 if (dev->of_node)
0413 clk_disable_unprepare(pltfm_host->clk);
0414 err:
0415 sdhci_pltfm_free(pdev);
0416 return ret;
0417 }
0418
0419 static void sdhci_iproc_shutdown(struct platform_device *pdev)
0420 {
0421 sdhci_pltfm_suspend(&pdev->dev);
0422 }
0423
0424 static struct platform_driver sdhci_iproc_driver = {
0425 .driver = {
0426 .name = "sdhci-iproc",
0427 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0428 .of_match_table = sdhci_iproc_of_match,
0429 .acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids),
0430 .pm = &sdhci_pltfm_pmops,
0431 },
0432 .probe = sdhci_iproc_probe,
0433 .remove = sdhci_pltfm_unregister,
0434 .shutdown = sdhci_iproc_shutdown,
0435 };
0436 module_platform_driver(sdhci_iproc_driver);
0437
0438 MODULE_AUTHOR("Broadcom");
0439 MODULE_DESCRIPTION("IPROC SDHCI driver");
0440 MODULE_LICENSE("GPL v2");