| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <acpi/acpi.h> |
| #include <cbmem.h> |
| #include <commonlib/storage/sd_mmc.h> |
| #include <commonlib/sd_mmc_ctrlr.h> |
| #include <commonlib/sdhci.h> |
| #include <compiler.h> |
| #include <console/console.h> |
| #include <device/pci.h> |
| #include <intelblocks/mmc.h> |
| #include <soc/iomap.h> |
| #include <soc/pci_devs.h> |
| #include <string.h> |
| |
| void soc_sd_mmc_controller_quirks(struct sd_mmc_ctrlr *ctrlr) |
| { |
| uint32_t f_min, f_max; |
| |
| if (soc_get_mmc_frequencies(&f_min, &f_max) < 0) { |
| printk(BIOS_ERR, |
| "MMC early init: failed to get mmc frequencies\n"); |
| return; |
| } |
| |
| ctrlr->f_min = f_min; |
| ctrlr->f_max = f_max; |
| } |
| |
| static void enable_mmc_controller_bar(void) |
| { |
| pci_write_config32(PCH_DEV_EMMC, PCI_BASE_ADDRESS_0, |
| PRERAM_MMC_BASE_ADDRESS); |
| pci_write_config16(PCH_DEV_EMMC, PCI_COMMAND, |
| PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); |
| } |
| |
| static void disable_mmc_controller_bar(void) |
| { |
| pci_write_config32(PCH_DEV_EMMC, PCI_BASE_ADDRESS_0, 0); |
| pci_write_config16(PCH_DEV_EMMC, PCI_COMMAND, |
| ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)); |
| } |
| |
| static void set_early_mmc_wake_status(int32_t status) |
| { |
| int32_t *ms_cbmem; |
| |
| ms_cbmem = cbmem_add(CBMEM_ID_MMC_STATUS, sizeof(int)); |
| |
| if (ms_cbmem == NULL) { |
| printk(BIOS_ERR, |
| "%s: Failed to add early mmc wake status to cbmem!\n", |
| __func__); |
| return; |
| } |
| |
| *ms_cbmem = status; |
| } |
| |
| int early_mmc_wake_hw(void) |
| { |
| struct storage_media media; |
| struct sd_mmc_ctrlr *mmc_ctrlr; |
| struct sdhci_ctrlr *sdhci_ctrlr; |
| int err; |
| |
| if (acpi_is_wakeup_s3()) |
| return -1; |
| |
| /* Configure mmc gpios */ |
| if (soc_configure_mmc_gpios() < 0) { |
| printk(BIOS_ERR, |
| "%s: MMC early init: failed to configure mmc gpios\n", |
| __func__); |
| return -1; |
| } |
| /* Setup pci bar */ |
| enable_mmc_controller_bar(); |
| |
| /* Initialize sdhci */ |
| mmc_ctrlr = new_pci_sdhci_controller(PCH_DEV_EMMC); |
| if (mmc_ctrlr == NULL) |
| goto out_err; |
| |
| sdhci_ctrlr = container_of(mmc_ctrlr, struct sdhci_ctrlr, sd_mmc_ctrlr); |
| |
| /* set emmc DLL tuning parameters */ |
| if (set_mmc_dll(sdhci_ctrlr->ioaddr) < 0) |
| goto out_err; |
| |
| memset(&media, 0, sizeof(media)); |
| media.ctrlr = mmc_ctrlr; |
| SET_BUS_WIDTH(mmc_ctrlr, 1); |
| /* |
| * Set clock to 1 so that the driver can choose minimum frequency |
| * possible |
| */ |
| SET_CLOCK(mmc_ctrlr, 1); |
| |
| /* Reset emmc, send CMD0 */ |
| if (sd_mmc_go_idle(&media)) |
| goto out_err; |
| |
| /* Send CMD1 */ |
| err = mmc_send_op_cond(&media); |
| if (err != 0 && err != CARD_IN_PROGRESS) |
| goto out_err; |
| |
| disable_mmc_controller_bar(); |
| |
| set_early_mmc_wake_status(1); |
| return 0; |
| |
| out_err: |
| |
| disable_mmc_controller_bar(); |
| return -1; |
| } |