[coreboot-gerrit] Change in coreboot[master]: soc/intel/quark: Add SD/MMC test support

Lee Leahy (Code Review) gerrit at coreboot.org
Mon May 8 19:13:36 CEST 2017


Lee Leahy has submitted this change and it was merged. ( https://review.coreboot.org/19211 )

Change subject: soc/intel/quark: Add SD/MMC test support
......................................................................


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 at intel.com>
Reviewed-on: https://review.coreboot.org/19211
Tested-by: build bot (Jenkins) <no-reply at coreboot.org>
Reviewed-by: Martin Roth <martinroth at google.com>
---
M src/soc/intel/quark/Kconfig
M src/soc/intel/quark/Makefile.inc
M src/soc/intel/quark/include/soc/iomap.h
M src/soc/intel/quark/include/soc/pci_devs.h
A src/soc/intel/quark/include/soc/storage_test.h
M src/soc/intel/quark/romstage/fsp2_0.c
A src/soc/intel/quark/sd.c
A src/soc/intel/quark/storage_test.c
8 files changed, 403 insertions(+), 0 deletions(-)

Approvals:
  build bot (Jenkins): Verified
  Martin Roth: Looks good to me, approved



diff --git a/src/soc/intel/quark/Kconfig b/src/soc/intel/quark/Kconfig
index c697b56..7f95b71 100644
--- a/src/soc/intel/quark/Kconfig
+++ b/src/soc/intel/quark/Kconfig
@@ -304,4 +304,22 @@
 	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
diff --git a/src/soc/intel/quark/Makefile.inc b/src/soc/intel/quark/Makefile.inc
index 1d66e6b..d0a7a93 100644
--- a/src/soc/intel/quark/Makefile.inc
+++ b/src/soc/intel/quark/Makefile.inc
@@ -33,6 +33,7 @@
 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 += 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
diff --git a/src/soc/intel/quark/include/soc/iomap.h b/src/soc/intel/quark/include/soc/iomap.h
index 1224bcc..de81a1a 100644
--- a/src/soc/intel/quark/include/soc/iomap.h
+++ b/src/soc/intel/quark/include/soc/iomap.h
@@ -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
  */
diff --git a/src/soc/intel/quark/include/soc/pci_devs.h b/src/soc/intel/quark/include/soc/pci_devs.h
index fc28dfe..a4e7a87 100644
--- a/src/soc/intel/quark/include/soc/pci_devs.h
+++ b/src/soc/intel/quark/include/soc/pci_devs.h
@@ -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
diff --git a/src/soc/intel/quark/include/soc/storage_test.h b/src/soc/intel/quark/include/soc/storage_test.h
new file mode 100644
index 0000000..6e970cc
--- /dev/null
+++ b/src/soc/intel/quark/include/soc/storage_test.h
@@ -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__ */
diff --git a/src/soc/intel/quark/romstage/fsp2_0.c b/src/soc/intel/quark/romstage/fsp2_0.c
index d03545d..10e44c1 100644
--- a/src/soc/intel/quark/romstage/fsp2_0.c
+++ b/src/soc/intel/quark/romstage/fsp2_0.c
@@ -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 @@
 	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);
diff --git a/src/soc/intel/quark/sd.c b/src/soc/intel/quark/sd.c
new file mode 100644
index 0000000..7b96001
--- /dev/null
+++ b/src/soc/intel/quark/sd.c
@@ -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,
+};
diff --git a/src/soc/intel/quark/storage_test.c b/src/soc/intel/quark/storage_test.c
new file mode 100644
index 0000000..4c83dbe
--- /dev/null
+++ b/src/soc/intel/quark/storage_test.c
@@ -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

-- 
To view, visit https://review.coreboot.org/19211
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I72785f0dcd466c05c1385cef166731219b583551
Gerrit-PatchSet: 13
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Lee Leahy <leroy.p.leahy at intel.com>
Gerrit-Reviewer: Lee Leahy <leroy.p.leahy at intel.com>
Gerrit-Reviewer: Martin Roth <martinroth at google.com>
Gerrit-Reviewer: Paul Menzel <paulepanter at users.sourceforge.net>
Gerrit-Reviewer: Sumeet R Pawnikar <sumeet.r.pawnikar at intel.com>
Gerrit-Reviewer: build bot (Jenkins) <no-reply at coreboot.org>



More information about the coreboot-gerrit mailing list