/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if CONFIG(STORAGE_LOG) struct log_entry log[LOG_ENTRIES]; uint8_t log_index; int log_full; long log_start_time; #endif static uint8_t drivers_storage[256]; #define STORAGE_DEBUG BIOS_DEBUG #define LOG_DEBUG (CONFIG(STORAGE_LOG) ? STORAGE_DEBUG : BIOS_NEVER) #ifdef __SIMPLE_DEVICE__ uint32_t storage_test_init(pci_devfn_t dev, uint32_t *previous_bar, uint16_t *previous_command) #else uint32_t storage_test_init(struct device *dev, uint32_t *previous_bar, uint16_t *previous_command) #endif { uint32_t bar; /* Display the vendor/device IDs */ printk(LOG_DEBUG, "Vendor ID: 0x%04x, Device ID: 0x%04x\n", pci_read_config16(dev, PCI_VENDOR_ID), pci_read_config16(dev, PCI_DEVICE_ID)); /* Set the temporary base address */ bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0); *previous_bar = bar; bar &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; if (!bar) { bar = SD_BASE_ADDRESS; pci_write_config32(dev, PCI_BASE_ADDRESS_0, bar); } /* Enable the SD/MMC controller */ *previous_command = pci_read_config16(dev, PCI_COMMAND); pci_write_config16(dev, PCI_COMMAND, *previous_command | PCI_COMMAND_MEMORY); /* Return the controller address */ return bar; } #ifdef __SIMPLE_DEVICE__ void storage_test_complete(pci_devfn_t dev, uint32_t previous_bar, uint16_t previous_command) #else void storage_test_complete(struct device *dev, uint32_t previous_bar, uint16_t previous_command) #endif { pci_write_config16(dev, PCI_COMMAND, previous_command); pci_write_config32(dev, PCI_BASE_ADDRESS_0, previous_bar); } #if !ENV_BOOTBLOCK static void display_log(void) { /* Determine the array bounds */ if (CONFIG(STORAGE_LOG)) { long delta; uint8_t end; uint8_t index; uint8_t start; end = log_index; start = log_full ? log_index : 0; for (index = start; (log_full || (index != end)); index++) { log_full = 0; delta = log[index].time.microseconds - log_start_time; printk(BIOS_DEBUG, "%3ld.%03ld mSec, cmd: %2d 0x%08x%s", delta / 1000, delta % 1000, log[index].cmd.cmdidx, log[index].cmd.cmdarg, log[index].cmd_issued ? "" : "(not issued)"); if (log[index].response_entries == 1) printk(BIOS_DEBUG, ", rsp: 0x%08x", log[index].response[0]); else if (log[index].response_entries == 4) printk(BIOS_DEBUG, ", rsp: 0x%08x.%08x.%08x.%08x", log[index].response[3], log[index].response[2], log[index].response[1], log[index].response[0]); printk(BIOS_DEBUG, ", ret: %d\n", log[index].ret); } } } void sdhc_log_command(struct mmc_command *cmd) { if (CONFIG(STORAGE_LOG)) { timer_monotonic_get(&log[log_index].time); log[log_index].cmd = *cmd; log[log_index].cmd_issued = 0; log[log_index].response_entries = 0; if ((log_index == 0) && (!log_full)) log_start_time = log[0].time.microseconds; } } void sdhc_log_command_issued(void) { if (CONFIG(STORAGE_LOG)) { log[log_index].cmd_issued = 1; } } void sdhc_log_response(uint32_t entries, uint32_t *response) { unsigned int entry; if (CONFIG(STORAGE_LOG)) { log[log_index].response_entries = entries; for (entry = 0; entry < entries; entry++) log[log_index].response[entry] = response[entry]; } } void sdhc_log_ret(int ret) { if (CONFIG(STORAGE_LOG)) { log[log_index].ret = ret; if (++log_index == 0) log_full = 1; } } void storage_test(uint32_t bar, int full_initialization) { uint64_t blocks_read; uint8_t buffer[512]; int err; struct storage_media *media; const char *name; unsigned int partition; unsigned int previous_partition; struct sdhci_ctrlr *sdhci_ctrlr; ASSERT(sizeof(struct sdhci_ctrlr) <= sizeof(drivers_storage)); /* Get the structure addresses */ media = NULL; if (ENV_ROMSTAGE) media = (struct storage_media *)drivers_storage; else media = cbmem_find(CBMEM_ID_STORAGE_DATA); sdhci_ctrlr = (void *)(((uintptr_t)(media + 1) + 0x7) & ~7); media->ctrlr = (struct sd_mmc_ctrlr *)sdhci_ctrlr; sdhci_ctrlr->ioaddr = (void *)bar; /* Initialize the controller */ if (!full_initialization) { /* Perform fast initialization */ sdhci_update_pointers(sdhci_ctrlr); sdhci_display_setup(sdhci_ctrlr); storage_display_setup(media); } else { /* Initialize the log */ if (CONFIG(STORAGE_LOG)) { log_index = 0; log_full = 0; } printk(LOG_DEBUG, "Initializing the SD/MMC controller\n"); err = sdhci_controller_init(sdhci_ctrlr, (void *)bar); if (err) { display_log(); printk(BIOS_ERR, "ERROR - Controller failed to initialize, err = %d\n", err); return; } /* Initialize the SD/MMC/eMMC card or device */ printk(LOG_DEBUG, "Initializing the device\n"); err = storage_setup_media(media, &sdhci_ctrlr->sd_mmc_ctrlr); if (err) { display_log(); printk(BIOS_ERR, "ERROR: Device failed to initialize, err = %d\n", err); return; } display_log(); } /* Save the current partition */ previous_partition = storage_get_current_partition(media); /* Read block 0 from each partition */ for (partition = 0; partition < ARRAY_SIZE(media->capacity); partition++) { if (media->capacity[partition] == 0) continue; name = storage_partition_name(media, partition); printk(STORAGE_DEBUG, "%s%sReading block 0\n", name, name[0] ? ": " : ""); err = storage_set_partition(media, partition); if (err) continue; blocks_read = storage_block_read(media, 0, 1, &buffer); if (blocks_read) hexdump(buffer, sizeof(buffer)); } /* Restore the previous partition */ storage_set_partition(media, previous_partition); } #endif #if ENV_ROMSTAGE static void copy_storage_structures(int is_recovery) { struct storage_media *media; struct sdhci_ctrlr *sdhci_ctrlr; size_t size = sizeof(drivers_storage); /* Locate the data structures in CBMEM */ media = cbmem_add(CBMEM_ID_STORAGE_DATA, size); ASSERT(media != NULL); sdhci_ctrlr = (void *)(((uintptr_t)(media + 1) + 0x7) & ~7); /* Migrate the data into CBMEM */ memcpy(media, drivers_storage, size); media->ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr; } ROMSTAGE_CBMEM_INIT_HOOK(copy_storage_structures); #endif