Lines Matching +full:sdhci +full:- +full:caps

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2020 - 2021 Alstom Group.
5 * Copyright (c) 2020 - 2021 Semihalf.
49 #include <dev/sdhci/sdhci.h>
50 #include <dev/sdhci/sdhci_fdt_gpio.h>
56 #define RD4 (sc->read)
57 #define WR4 (sc->write)
219 .syscon_compat = "fsl,ls1012a-scfg",
234 .syscon_compat = "fsl,ls1046a-scfg",
250 {"fsl,ls1012a-esdhc", (uintptr_t)&sdhci_fsl_fdt_ls1012a_soc_data},
251 {"fsl,ls1028a-esdhc", (uintptr_t)&sdhci_fsl_fdt_ls1028a_soc_data},
252 {"fsl,ls1046a-esdhc", (uintptr_t)&sdhci_fsl_fdt_ls1046a_soc_data},
261 return (be32toh(bus_read_4(sc->mem_res, off))); in read_be()
268 bus_write_4(sc->mem_res, off, htobe32(val)); in write_be()
275 return (bus_read_4(sc->mem_res, off)); in read_le()
282 bus_write_4(sc->mem_res, off, val); in write_le()
291 val = sc->sdclk_bits | SDHCI_CLOCK_INT_EN; in sdhci_fsl_fdt_get_clock()
306 (pre) = (sc)->vendor_ver < SDHCI_FSL_VENDOR_V23 ? 2 : 1;\
321 sc->sdclk_bits = val & SDHCI_DIVIDERS_MASK; in fsl_sdhc_fdt_set_clock()
333 SDHCI_FSL_FDT_CLK_DIV(sc, sc->baseclk_hz, slot->clock, prescale, div); in fsl_sdhc_fdt_set_clock()
341 if ((sc->soc_data->errata & SDHCI_FSL_HS400_LIMITED_CLK_DIV) && in fsl_sdhc_fdt_set_clock()
342 (sc->slot.host.ios.timing == bus_timing_mmc_hs400 || in fsl_sdhc_fdt_set_clock()
343 (sc->flags & SDHCI_FSL_HS400_FLAG))) { in fsl_sdhc_fdt_set_clock()
354 device_printf(sc->dev, "Unsupported clock divider.\n"); in fsl_sdhc_fdt_set_clock()
358 sc->div_ratio = prescale * div; in fsl_sdhc_fdt_set_clock()
360 device_printf(sc->dev, in fsl_sdhc_fdt_set_clock()
362 slot->clock, sc->baseclk_hz / (prescale * div), in fsl_sdhc_fdt_set_clock()
363 sc->baseclk_hz, prescale, div); in fsl_sdhc_fdt_set_clock()
366 div -= 1; in fsl_sdhc_fdt_set_clock()
416 return (sc->cmd_and_mode & UINT16_MAX); in sdhci_fsl_fdt_read_2()
418 return (sc->cmd_and_mode >> 16); in sdhci_fsl_fdt_read_2()
441 return (bus_read_4(sc->mem_res, off)); in sdhci_fsl_fdt_read_4()
464 bus_read_multi_4(sc->mem_res, off, data, count); in sdhci_fsl_fdt_read_multi_4()
485 /* Bus width is 1-bit when this flag is not set. */ in sdhci_fsl_fdt_write_1()
524 sc->cmd_and_mode = val; in sdhci_fsl_fdt_write_2()
527 sc->cmd_and_mode = in sdhci_fsl_fdt_write_2()
528 (sc->cmd_and_mode & UINT16_MAX) | (val << 16); in sdhci_fsl_fdt_write_2()
529 WR4(sc, SDHCI_TRANSFER_MODE, sc->cmd_and_mode); in sdhci_fsl_fdt_write_2()
530 sc->cmd_and_mode = 0; in sdhci_fsl_fdt_write_2()
558 bus_write_4(sc->mem_res, off, val); in sdhci_fsl_fdt_write_4()
584 bus_write_multi_4(sc->mem_res, off, data, count); in sdhci_fsl_fdt_write_multi_4()
593 sdhci_generic_intr(&sc->slot); in sdhci_fsl_fdt_irq()
611 ios = &slot->host.ios; in sdhci_fsl_fdt_update_ios()
613 switch (ios->power_mode) { in sdhci_fsl_fdt_update_ios()
618 device_printf(sc->dev, "Powering down sd/mmc\n"); in sdhci_fsl_fdt_update_ios()
620 if (sc->fdt_helper.vmmc_supply) in sdhci_fsl_fdt_update_ios()
621 regulator_disable(sc->fdt_helper.vmmc_supply); in sdhci_fsl_fdt_update_ios()
622 if (sc->fdt_helper.vqmmc_supply) in sdhci_fsl_fdt_update_ios()
623 regulator_disable(sc->fdt_helper.vqmmc_supply); in sdhci_fsl_fdt_update_ios()
627 device_printf(sc->dev, "Powering up sd/mmc\n"); in sdhci_fsl_fdt_update_ios()
629 if (sc->fdt_helper.vmmc_supply) in sdhci_fsl_fdt_update_ios()
630 regulator_enable(sc->fdt_helper.vmmc_supply); in sdhci_fsl_fdt_update_ios()
631 if (sc->fdt_helper.vqmmc_supply) in sdhci_fsl_fdt_update_ios()
632 regulator_enable(sc->fdt_helper.vqmmc_supply); in sdhci_fsl_fdt_update_ios()
647 if (sc->soc_data->syscon_compat == NULL) { in sdhci_fsl_fdt_switch_syscon_voltage()
653 sc->soc_data->syscon_compat); in sdhci_fsl_fdt_switch_syscon_voltage()
707 switch (slot->host.ios.vccq) { in sdhci_fsl_fdt_switch_vccq()
709 if (sc->soc_data->errata & SDHCI_FSL_UNSUPP_1_8V) in sdhci_fsl_fdt_switch_vccq()
725 if (sc->soc_data->errata & SDHCI_FSL_MISSING_VCCQ_REG) { in sdhci_fsl_fdt_switch_vccq()
727 slot->host.ios.vccq); in sdhci_fsl_fdt_switch_vccq()
732 vqmmc_supply = sc->fdt_helper.vqmmc_supply; in sdhci_fsl_fdt_switch_vccq()
746 device_printf(sc->dev, "Cannot set vqmmc to %d<->%d\n", uvolt, uvolt); in sdhci_fsl_fdt_switch_vccq()
758 return (sdhci_fdt_gpio_get_readonly(sc->gpio)); in sdhci_fsl_fdt_get_ro()
767 return (sdhci_fdt_gpio_get_present(sc->gpio)); in sdhci_fsl_fdt_get_card_present()
790 device_printf(dev, "Voltage range %d - %d is out of bounds\n", in sdhci_fsl_fdt_vddrange_to_mask()
819 mmc_fdt_parse(dev, node, &sc->fdt_helper, &sc->slot.host); in sdhci_fsl_fdt_of_parse()
821 sc->slot.quirks |= SDHCI_QUIRK_MISSING_CAPS; in sdhci_fsl_fdt_of_parse()
822 sc->slot.caps = sdhci_fsl_fdt_read_4(dev, &sc->slot, in sdhci_fsl_fdt_of_parse()
824 sc->slot.caps2 = sdhci_fsl_fdt_read_4(dev, &sc->slot, in sdhci_fsl_fdt_of_parse()
827 /* Parse the "voltage-ranges" dts property. */ in sdhci_fsl_fdt_of_parse()
828 num_ranges = OF_getencprop_alloc(node, "voltage-ranges", in sdhci_fsl_fdt_of_parse()
836 /* Overwrite voltage caps only if we got something from dts. */ in sdhci_fsl_fdt_of_parse()
838 (vdd_mask != (sc->slot.caps & SDHCI_FSL_CAN_VDD_MASK))) { in sdhci_fsl_fdt_of_parse()
839 sc->slot.caps &= ~(SDHCI_FSL_CAN_VDD_MASK); in sdhci_fsl_fdt_of_parse()
840 sc->slot.caps |= vdd_mask; in sdhci_fsl_fdt_of_parse()
853 if (!retries--) in sdhci_fsl_poll_register()
877 sdhci_fsl_fdt_compat_data)->ocd_data; in sdhci_fsl_fdt_attach()
878 sc->dev = dev; in sdhci_fsl_fdt_attach()
879 sc->flags = 0; in sdhci_fsl_fdt_attach()
880 host = &sc->slot.host; in sdhci_fsl_fdt_attach()
889 sc->soc_data = &sdhci_fsl_fdt_lx2160a_soc_data; in sdhci_fsl_fdt_attach()
891 sc->soc_data = (struct sdhci_fsl_fdt_soc_data *)ocd_data; in sdhci_fsl_fdt_attach()
893 sc->slot.quirks = sc->soc_data->quirks; in sdhci_fsl_fdt_attach()
895 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, in sdhci_fsl_fdt_attach()
897 if (sc->mem_res == NULL) { in sdhci_fsl_fdt_attach()
904 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, in sdhci_fsl_fdt_attach()
906 if (sc->irq_res == NULL) { in sdhci_fsl_fdt_attach()
913 ret = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, in sdhci_fsl_fdt_attach()
914 NULL, sdhci_fsl_fdt_irq, sc, &sc->irq_cookie); in sdhci_fsl_fdt_attach()
933 sc->baseclk_hz = clk_hz / sc->soc_data->baseclk_div; in sdhci_fsl_fdt_attach()
936 if (OF_hasprop(node, "little-endian")) { in sdhci_fsl_fdt_attach()
937 sc->read = read_le; in sdhci_fsl_fdt_attach()
938 sc->write = write_le; in sdhci_fsl_fdt_attach()
941 sc->read = read_be; in sdhci_fsl_fdt_attach()
942 sc->write = write_be; in sdhci_fsl_fdt_attach()
946 sc->vendor_ver = (RD4(sc, SDHCI_FSL_HOST_VERSION) & in sdhci_fsl_fdt_attach()
950 sc->maxclk_hz = host->f_max ? host->f_max : sc->baseclk_hz; in sdhci_fsl_fdt_attach()
954 * If the eSDHC block is connected over a big-endian bus, the data in sdhci_fsl_fdt_attach()
973 sc->slot.max_clk = sc->maxclk_hz; in sdhci_fsl_fdt_attach()
974 sc->gpio = sdhci_fdt_gpio_setup(dev, &sc->slot); in sdhci_fsl_fdt_attach()
981 * re-check the status and potentially wait for more data. The main in sdhci_fsl_fdt_attach()
982 * sdhci driver provides no hook for doing status checking on less than in sdhci_fsl_fdt_attach()
992 ret = sdhci_init_slot(dev, &sc->slot, 0); in sdhci_fsl_fdt_attach()
995 sc->slot_init_done = true; in sdhci_fsl_fdt_attach()
996 sdhci_start_slot(&sc->slot); in sdhci_fsl_fdt_attach()
1002 sdhci_fdt_gpio_teardown(sc->gpio); in sdhci_fsl_fdt_attach()
1004 bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); in sdhci_fsl_fdt_attach()
1006 bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); in sdhci_fsl_fdt_attach()
1008 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); in sdhci_fsl_fdt_attach()
1018 if (sc->slot_init_done) in sdhci_fsl_fdt_detach()
1019 sdhci_cleanup_slot(&sc->slot); in sdhci_fsl_fdt_detach()
1020 if (sc->gpio != NULL) in sdhci_fsl_fdt_detach()
1021 sdhci_fdt_gpio_teardown(sc->gpio); in sdhci_fsl_fdt_detach()
1022 if (sc->irq_cookie != NULL) in sdhci_fsl_fdt_detach()
1023 bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); in sdhci_fsl_fdt_detach()
1024 if (sc->irq_res != NULL) in sdhci_fsl_fdt_detach()
1025 bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); in sdhci_fsl_fdt_detach()
1026 if (sc->mem_res != NULL) in sdhci_fsl_fdt_detach()
1027 bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); in sdhci_fsl_fdt_detach()
1039 sdhci_fsl_fdt_compat_data)->ocd_data) in sdhci_fsl_fdt_probe()
1052 if (which == MMCBR_IVAR_MAX_DATA && (slot->opt & SDHCI_HAVE_DMA)) { in sdhci_fsl_fdt_read_ivar()
1058 *result = howmany(slot->sdma_bbufsz, 512); in sdhci_fsl_fdt_read_ivar()
1072 /* Don't depend on clock resolution limits from sdhci core. */ in sdhci_fsl_fdt_write_ivar()
1075 slot->host.ios.clock = 0; in sdhci_fsl_fdt_write_ivar()
1081 SDHCI_FSL_FDT_CLK_DIV(sc, sc->baseclk_hz, value, prescale, div); in sdhci_fsl_fdt_write_ivar()
1082 slot->host.ios.clock = sc->baseclk_hz / (prescale * div); in sdhci_fsl_fdt_write_ivar()
1104 if (slot->version >= SDHCI_SPEC_300) { in sdhci_fsl_fdt_reset()
1114 if (sc->soc_data->errata & SDHCI_FSL_UNRELIABLE_PULSE_DET) { in sdhci_fsl_fdt_reset()
1120 sc->flags = 0; in sdhci_fsl_fdt_reset()
1148 if (sc->soc_data->errata & SDHCI_FSL_TUNING_ERRATUM_TYPE1 || in sdhci_fsl_sw_tuning()
1149 abs(wnd_start - wnd_end) <= (4 * sc->div_ratio + 2)) { in sdhci_fsl_sw_tuning()
1150 wnd_start = 5 * sc->div_ratio; in sdhci_fsl_sw_tuning()
1151 wnd_end = 3 * sc->div_ratio; in sdhci_fsl_sw_tuning()
1153 wnd_start = 8 * sc->div_ratio; in sdhci_fsl_sw_tuning()
1154 wnd_end = 4 * sc->div_ratio; in sdhci_fsl_sw_tuning()
1201 if (sc->slot.host.ios.timing == bus_timing_uhs_sdr50 && in sdhci_fsl_fdt_tune()
1202 !(slot->opt & SDHCI_SDR50_NEEDS_TUNING)) in sdhci_fsl_fdt_tune()
1211 clk_divider = sc->baseclk_hz / slot->clock; in sdhci_fsl_fdt_tune()
1216 sc->flags |= SDHCI_FSL_HS400_FLAG; in sdhci_fsl_fdt_tune()
1219 fsl_sdhc_fdt_set_clock(sc, slot, sc->sdclk_bits); in sdhci_fsl_fdt_tune()
1243 * "eSDHC takes care of the re-tuning during data transfer in sdhci_fsl_fdt_tune()
1244 * (auto re-tuning).". in sdhci_fsl_fdt_tune()
1253 fsl_sdhc_fdt_set_clock(sc, slot, SDHCI_CLOCK_CARD_EN | sc->sdclk_bits); in sdhci_fsl_fdt_tune()
1276 sc->soc_data->errata & SDHCI_FSL_TUNING_ERRATUM_TYPE2 && in sdhci_fsl_fdt_tune()
1277 abs(wnd_start - wnd_end) > (4 * sc->div_ratio + 2)) { in sdhci_fsl_fdt_tune()
1283 (sc->soc_data->errata & in sdhci_fsl_fdt_tune()
1314 if (!(slot->opt & SDHCI_TUNING_ENABLED)) in sdhci_fsl_fdt_retune()
1318 if (slot->host.ios.timing == bus_timing_mmc_hs400) in sdhci_fsl_fdt_retune()
1322 * Only re-tuning with full reset is supported. in sdhci_fsl_fdt_retune()
1324 * periodic re-tuning is done automatically. See comment in in sdhci_fsl_fdt_retune()
1326 * Because of that re-tuning should only be triggered as a result in sdhci_fsl_fdt_retune()
1333 sc->flags & SDHCI_FSL_HS400_FLAG)); in sdhci_fsl_fdt_retune()
1354 fsl_sdhc_fdt_set_clock(sc, &sc->slot, sc->sdclk_bits); in sdhci_fsl_disable_hs400_mode()
1365 fsl_sdhc_fdt_set_clock(sc, &sc->slot, SDHCI_CLOCK_CARD_EN | in sdhci_fsl_disable_hs400_mode()
1366 sc->sdclk_bits); in sdhci_fsl_disable_hs400_mode()
1394 fsl_sdhc_fdt_set_clock(sc, slot, sc->sdclk_bits); in sdhci_fsl_enable_hs400_mode()
1410 sc->sdclk_bits); in sdhci_fsl_enable_hs400_mode()
1440 fsl_sdhc_fdt_set_clock(sc, slot, sc->sdclk_bits); in sdhci_fsl_enable_hs400_mode()
1459 sc->sdclk_bits); in sdhci_fsl_enable_hs400_mode()
1476 ios = &slot->host.ios; in sdhci_fsl_fdt_set_uhs_timing()
1486 if (slot->host.ios.timing == bus_timing_mmc_hs400 && in sdhci_fsl_fdt_set_uhs_timing()
1487 ios->clock > SD_SDR50_MAX) in sdhci_fsl_fdt_set_uhs_timing()
1489 else if (slot->host.ios.timing < bus_timing_mmc_hs400) { in sdhci_fsl_fdt_set_uhs_timing()
1499 if (ios->clock > SD_SDR50_MAX) in sdhci_fsl_fdt_set_uhs_timing()
1501 else if (ios->clock > SD_SDR25_MAX) in sdhci_fsl_fdt_set_uhs_timing()
1503 else if (ios->clock > SD_SDR12_MAX) { in sdhci_fsl_fdt_set_uhs_timing()
1504 if (ios->timing == bus_timing_uhs_ddr50 || in sdhci_fsl_fdt_set_uhs_timing()
1505 ios->timing == bus_timing_mmc_ddr52) in sdhci_fsl_fdt_set_uhs_timing()
1509 } else if (ios->clock > SD_MMC_CARD_ID_FREQUENCY) in sdhci_fsl_fdt_set_uhs_timing()
1537 /* SDHCI accessors. */