blob: 1eed84e9b24d01ec447a5354ac007664cecaabbf [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/pci_ops.h>
#include <assert.h>
#include <cbmem.h>
#include <commonlib/sdhci.h>
#include <commonlib/storage.h>
#include <console/console.h>
#include <lib.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/storage_test.h>
#include <timer.h>
#include <string.h>
#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