/* This file is part of the coreboot project. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Secure Digital (SD) Host Controller interface specific code */ #include #include #include #include "sdhci.h" #include "sd_mmc.h" #include "storage.h" static void sdhci_display_bus_width(struct sdhci_ctrlr *sdhci_ctrlr) { if (CONFIG(SDHC_DEBUG)) { int bits; uint8_t host_ctrl; uint16_t host2; const char *rate; uint16_t timing; /* Display the bus width */ host_ctrl = sdhci_readb(sdhci_ctrlr, SDHCI_HOST_CONTROL); host2 = sdhci_readw(sdhci_ctrlr, SDHCI_HOST_CONTROL2); timing = host2 & SDHCI_CTRL_UHS_MASK; bits = 1; if (host_ctrl & SDHCI_CTRL_8BITBUS) bits = 8; else if (host_ctrl & SDHCI_CTRL_4BITBUS) bits = 4; rate = "SDR"; if ((timing == SDHCI_CTRL_UHS_DDR50) || (timing == SDHCI_CTRL_HS400)) rate = "DDR"; sdhc_debug("SDHCI bus width: %d bit%s %s\n", bits, (bits != 1) ? "s" : "", rate); } } static void sdhci_display_clock(struct sdhci_ctrlr *sdhci_ctrlr) { if (CONFIG(SDHC_DEBUG)) { uint16_t clk_ctrl; uint32_t clock; uint32_t divisor; /* Display the clock */ clk_ctrl = sdhci_readw(sdhci_ctrlr, SDHCI_CLOCK_CONTROL); sdhc_debug("SDHCI bus clock: "); if (clk_ctrl & SDHCI_CLOCK_CARD_EN) { divisor = (clk_ctrl >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIV_MASK; divisor |= ((clk_ctrl >> SDHCI_DIVIDER_SHIFT) << SDHCI_DIV_MASK_LEN) & SDHCI_DIV_HI_MASK; divisor <<= 1; clock = sdhci_ctrlr->sd_mmc_ctrlr.clock_base; if (divisor) clock /= divisor; sdhc_debug("%d.%03d MHz\n", clock / 1000000, (clock / 1000) % 1000); } else sdhc_debug("Off\n"); } } static void sdhci_display_voltage(struct sdhci_ctrlr *sdhci_ctrlr) { if (CONFIG(SDHC_DEBUG)) { u8 pwr_ctrl; const char *voltage; const char *voltage_table[8] = { "Unknown", /* 0 */ "Unknown", /* 1 */ "Unknown", /* 2 */ "Unknown", /* 3 */ "Unknown", /* 4 */ "1.8", /* 5 */ "3.0", /* 6 */ "3.3", /* 7 */ }; pwr_ctrl = sdhci_readb(sdhci_ctrlr, SDHCI_POWER_CONTROL); if (pwr_ctrl & SDHCI_POWER_ON) { voltage = voltage_table[(pwr_ctrl & SDHCI_POWER_330) >> 1]; sdhc_debug("SDHCI voltage: %s Volts\n", voltage); } else sdhc_debug("SDHCI voltage: Off\n"); } } void sdhci_display_setup(struct sdhci_ctrlr *sdhci_ctrlr) { /* Display the controller setup */ sdhci_display_voltage(sdhci_ctrlr); sdhci_display_clock(sdhci_ctrlr); sdhci_display_bus_width(sdhci_ctrlr); }