soc/intel/quark: Add SD/MMC test support

The SD/MMC test support consists of:

* Add Kconfig value to enable the SD/MMC test support.
* Add Kconfig value to enable the logging support.
* Add SD/MMC controller init code and read block 0 from each partition.
* Add logging code to snapshot the transactions with the SD/MMC device.
* Add eMMC driver for ramstage to call test code.
* Add romstage code to call test code.
* Add bootblock code to call test code.

TEST=Build and run on Galileo Gen2

Change-Id: I72785f0dcd466c05c1385cef166731219b583551
Signed-off-by: Lee Leahy <leroy.p.leahy@intel.com>
Reviewed-on: https://review.coreboot.org/19211
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
Lee Leahy 2017-04-01 20:33:58 -07:00
parent 52f29743b1
commit 16bc9bab2a
8 changed files with 403 additions and 0 deletions

View file

@ -304,4 +304,22 @@ config C_ENV_BOOTBLOCK_SIZE
hex
default 0x8000
#####
# Test support
#####
config STORAGE_TEST
bool "Test SD/MMC/eMMC card or device access"
default n
select DRIVERS_STORAGE
select SDHCI_CONTROLLER
help
Read block 0 from each parition of the storage device. User must
also enable one or both of DRIVERS_STORAGE_SD or DRIVERS_STORAGE_MMC.
config STORAGE_LOG
bool "Log and display SD/MMC commands"
default n
depends on STORAGE_TEST
endif # SOC_INTEL_QUARK

View file

@ -33,6 +33,7 @@ verstage-$(CONFIG_ENABLE_BUILTIN_HSUART1) += uart_common.c
romstage-y += i2c.c
romstage-y += memmap.c
romstage-y += reg_access.c
romstage-$(CONFIG_STORAGE_TEST) += storage_test.c
romstage-y += tsc_freq.c
romstage-$(CONFIG_ENABLE_BUILTIN_HSUART1) += uart_common.c
romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += reset.c
@ -56,6 +57,8 @@ ramstage-y += memmap.c
ramstage-y += northcluster.c
ramstage-y += reg_access.c
ramstage-$(CONFIG_PLATFORM_USES_FSP2_0) += reset.c
ramstage-y += sd.c
ramstage-$(CONFIG_STORAGE_TEST) += storage_test.c
ramstage-y += tsc_freq.c
ramstage-$(CONFIG_ENABLE_BUILTIN_HSUART1) += uart_common.c
ramstage-$(CONFIG_ENABLE_BUILTIN_HSUART1) += uart.c

View file

@ -28,6 +28,9 @@
#define I2C_BASE_ADDRESS 0xa0020000
#define GPIO_BASE_ADDRESS 0xa0021000
/* Temporary BAR for SD controller */
#define SD_BASE_ADDRESS 0xa0022000
/*
* I/O port address space
*/

View file

@ -33,8 +33,10 @@
/* IO Fabric 1 */
#define SIO1_DEV 0x14
#define SD_MMC_DEV SIO1_DEV
#define HSUART0_DEV SIO1_DEV
#define HSUART1_DEV SIO1_DEV
#define SD_MMC_FUNC 0
#define HSUART0_FUNC 1
#define USB_DEV_PORT_FUNC 2
#define EHCI_FUNC 3

View file

@ -0,0 +1,53 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2017 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __STORAGE_TEST_H__
#define __STORAGE_TEST_H__
#include <device/device.h>
#include <device/pci.h>
#include <device/sd_mmc_ctrlr.h>
#include <timer.h>
#ifdef __SIMPLE_DEVICE__
#define dev_t uintptr_t
#else
#define dev_t device_t
#endif /* __SIMPLE_DEVICE__ */
uint32_t storage_test_init(dev_t dev, uint32_t *previous_bar,
uint16_t *previous_command);
void storage_test(uint32_t bar, int full_initialization);
void storage_test_complete(dev_t dev, uint32_t previous_bar,
uint16_t previous_command);
/* Logging support */
struct log_entry {
struct mono_time time;
struct mmc_command cmd;
int cmd_issued;
int ret;
uint32_t response_entries;
uint32_t response[4];
};
#define LOG_ENTRIES 256
extern struct log_entry log[LOG_ENTRIES];
extern uint8_t log_index;
extern int log_full;
extern long log_start_time;
#endif /* __STORAGE_TEST_H__ */

View file

@ -19,10 +19,12 @@
#include "../chip.h"
#include <cpu/x86/cache.h>
#include <fsp/util.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/pm.h>
#include <soc/romstage.h>
#include <soc/reg_access.h>
#include <soc/storage_test.h>
asmlinkage void *car_stage_c_entry(void)
{
@ -34,6 +36,21 @@ asmlinkage void *car_stage_c_entry(void)
post_code(0x20);
console_init();
if (IS_ENABLED(CONFIG_STORAGE_TEST)) {
uint32_t bar;
dev_t dev;
uint32_t previous_bar;
uint16_t previous_command;
/* Enable the SD/MMC controller and run the test. Restore
* the BAR and command registers upon completion.
*/
dev = PCI_DEV(0, SD_MMC_DEV, SD_MMC_FUNC);
bar = storage_test_init(dev, &previous_bar, &previous_command);
storage_test(bar, 1);
storage_test_complete(dev, previous_bar, previous_command);
}
/* Initialize DRAM */
s3wake = fill_power_state() == ACPI_S3;
fsp_memory_init(s3wake);

50
src/soc/intel/quark/sd.c Normal file
View file

@ -0,0 +1,50 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2017 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/sdhci.h>
#include <device/storage.h>
#include <soc/storage_test.h>
static void init(struct device *dev)
{
/* Run the SD test */
if (IS_ENABLED(CONFIG_STORAGE_TEST)) {
uint32_t bar;
uint32_t previous_bar;
uint16_t previous_command;
bar = storage_test_init(dev, &previous_bar, &previous_command);
storage_test(bar, 0);
storage_test_complete(dev, previous_bar, previous_command);
}
}
static const struct device_operations device_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = init,
};
static const struct pci_driver pmc __pci_driver = {
.ops = &device_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x08A7,
};

View file

@ -0,0 +1,257 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2017 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/early_variables.h>
#include <arch/io.h>
#include <assert.h>
#include <cbmem.h>
#include <commonlib/cbmem_id.h>
#include <console/console.h>
#include <device/sdhci.h>
#include <device/storage.h>
#include <lib.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/storage_test.h>
#include <string.h>
#if IS_ENABLED(CONFIG_STORAGE_LOG)
struct log_entry log[LOG_ENTRIES] CAR_GLOBAL;
uint8_t log_index CAR_GLOBAL;
int log_full CAR_GLOBAL;
long log_start_time CAR_GLOBAL;
#endif
extern uint8_t _car_drivers_storage_start;
extern uint8_t _car_drivers_storage_end;
#define STORAGE_DEBUG BIOS_DEBUG
#define LOG_DEBUG (IS_ENABLED(CONFIG_STORAGE_LOG) ? STORAGE_DEBUG : BIOS_NEVER)
uint32_t storage_test_init(dev_t dev, uint32_t *previous_bar,
uint16_t *previous_command)
{
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;
}
void storage_test_complete(dev_t dev, uint32_t previous_bar,
uint16_t previous_command)
{
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 (IS_ENABLED(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 (IS_ENABLED(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 (IS_ENABLED(CONFIG_STORAGE_LOG)) {
log[log_index].cmd_issued = 1;
}
}
void sdhc_log_response(uint32_t entries, uint32_t *response)
{
unsigned int entry;
if (IS_ENABLED(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 (IS_ENABLED(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;
/* Get the structure addresses */
media = NULL;
if (ENV_ROMSTAGE)
media = car_get_var_ptr(&_car_drivers_storage_start);
else
media = cbmem_find(CBMEM_ID_STORAGE_DATA);
sdhci_ctrlr = (void *)(((uintptr_t)(media + 1) + 0x7) & ~7);
if (ENV_ROMSTAGE)
ASSERT((struct sdhci_ctrlr *)&_car_drivers_storage_end
>= (sdhci_ctrlr + 1));
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 (IS_ENABLED(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;
/* Locate the data structures in CBMEM */
size = &_car_drivers_storage_end - &_car_drivers_storage_start;
ASSERT(size == 256);
media = cbmem_add(CBMEM_ID_STORAGE_DATA, size);
ASSERT(media != NULL);
sdhci_ctrlr = (void *)(((uintptr_t)(media + 1) + 0x7) & ~7);
ASSERT((sdhci_ctrlr + 1)
<= (struct sdhci_ctrlr *)&_car_drivers_storage_end);
/* Migrate the data into CBMEM */
memcpy(media, &_car_drivers_storage_start, size);
media->ctrlr = &sdhci_ctrlr->sd_mmc_ctrlr;
}
ROMSTAGE_CBMEM_INIT_HOOK(copy_storage_structures);
#endif