Hello Subrata Banik,
I'd like you to do a code review. Please visit
https://review.coreboot.org/25188
to review the following change.
Change subject: intel/common/block/emmc: Add intel common EMMC init code over AP ......................................................................
intel/common/block/emmc: Add intel common EMMC init code over AP
This patch adds new block to do multi-threaded EMMC controller initialization code. Thus on selecting this block from SOC, EMMC controller init code will get executed in parallel thread, without disturbing the already running code in BSP.
This is done to save around 100-300 msecs of booting time for emmc initialization depending on different booting scenarios.
BUG=none BRANCH=none TEST=Done 3K Stability Test in Soraka (SKL) to see the boot time optimizations in the following scenarios - * Warm Reboot --> ~100-150 msecs * Cold Reboot --> ~100-150 msecs * EC Reeboot --> ~300 msecs
Change-Id: I10e91b4d9b5385331100f7eabc3be2f1e47bf377 Signed-off-by: Barnali Sarkar barnali.sarkar@intel.com Signed-off-by: Subrata Banik subrata.banik@intel.com --- A src/soc/intel/common/block/emmc/Kconfig A src/soc/intel/common/block/emmc/Makefile.inc A src/soc/intel/common/block/emmc/emmc_ap_init.c 3 files changed, 231 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/88/25188/1
diff --git a/src/soc/intel/common/block/emmc/Kconfig b/src/soc/intel/common/block/emmc/Kconfig new file mode 100644 index 0000000..26279f5 --- /dev/null +++ b/src/soc/intel/common/block/emmc/Kconfig @@ -0,0 +1,21 @@ +config SOC_INTEL_COMMON_BLOCK_EMMC_INIT_OVER_AP + bool "Enable eMMC device initialization in parallel thread" + default n + select COMMONLIB_STORAGE + select COMMONLIB_STORAGE_MMC + select SDHCI_CONTROLLER + help + This option selects use Intel Common multi-threaded EMMC Controller + Initializtion code. + +config SOC_INTEL_COMMON_BLOCK_EMMC_INIT_DEBUG + bool "Enable debug log for SD/MMC/eMMC card or device" + default n + depends on SOC_INTEL_COMMON_BLOCK_EMMC_INIT_OVER_AP + select SD_MMC_DEBUG + select SD_MMC_TRACE + select SDHC_DEBUG + select SDHC_TRACE + help + Enable debug log EMMC init over multi-threading. User + must also enable SOC_INTEL_COMMON_BLOCK_EMMC_INIT_OVER_AP. diff --git a/src/soc/intel/common/block/emmc/Makefile.inc b/src/soc/intel/common/block/emmc/Makefile.inc new file mode 100644 index 0000000..a5a77f2 --- /dev/null +++ b/src/soc/intel/common/block/emmc/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_EMMC_INIT_OVER_AP) += emmc_ap_init.c diff --git a/src/soc/intel/common/block/emmc/emmc_ap_init.c b/src/soc/intel/common/block/emmc/emmc_ap_init.c new file mode 100644 index 0000000..4bc70db --- /dev/null +++ b/src/soc/intel/common/block/emmc/emmc_ap_init.c @@ -0,0 +1,209 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018 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 <bootstate.h> +#include <cbmem.h> +#include <commonlib/cbmem_id.h> +#include <commonlib/sdhci.h> +#include <commonlib/storage.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/x86/mp.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <soc/pci_devs.h> +#include <soc/iomap.h> + +/* + * To use this Common block, SOC should publish the below two MACROS - + * EMMC_BASE_ADDRESS - Temporary Base Address for EMMC + * EMMC_BASE_SIZE - Size + */ + +static uint8_t cbmem_copy_done = 0; + +static void save_media_info_to_cbmem(struct storage_media *media) +{ + uint32_t *cbmem_loc; + + cbmem_loc = cbmem_add(CBMEM_ID_STORAGE_DATA, sizeof(*media)); + if (cbmem_loc == NULL) + die("Error: Could not add cbmem area\n"); + + memcpy(cbmem_loc, media, sizeof(*media)); + cbmem_copy_done = 1; +} + +static uint32_t set_temp_bar(device_t dev) +{ + uint32_t bar; + + /* Program Temporary BAR for eMMC Device */ + pci_write_config32(dev, PCI_BASE_ADDRESS_0, EMMC_BASE_ADDRESS); + + /* Set the temporary base address */ + bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0); + bar &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + + /* Enable the SD/MMC controller */ + pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER + | PCI_COMMAND_MEMORY); + + /* Return the controller address */ + return bar; +} + +static void platform_emmc_init(void) +{ + device_t dev = PCH_DEV_EMMC; + uintptr_t bar; + struct sdhci_ctrlr ctrlr; + struct sdhci_ctrlr *sdhci_ctrlr = &ctrlr; + struct storage_media media_device; + struct storage_media *media = &media_device; + + /* + * Set a temporary BAR for EMMC Device to start the initialization + * since PCI Enumuration is not yet done. Thus resouce allocation + * hasn't been done yet. + */ + bar = set_temp_bar(dev); + + /* Initialize the controller */ + if (sdhci_controller_init(sdhci_ctrlr, (void *)bar)) { + printk(BIOS_ERR, "Initializing the controller failure \n"); + /* Send all zeros to cbmem in case of failure */ + memset((void *) media, 0, sizeof(*media)); + save_media_info_to_cbmem(media); + return; + } + + /* Initialize the media */ + if (storage_setup_media(media, &sdhci_ctrlr->sd_mmc_ctrlr)) { + printk(BIOS_ERR, "Initializing the device failure \n"); + /* Send all zeros to cbmem in case of failure */ + memset((void *) media, 0, sizeof(*media)); + save_media_info_to_cbmem(media); + return; + } + + save_media_info_to_cbmem(media); + +} + +static void run_on_single_aps(void) +{ + if (cpu_index() != 1) + return; + + platform_emmc_init(); +} + +static void init_emmc(void *unused) +{ + /* + * Only do emmc init in normal boot scenario, not during + * S3 Resume path. + */ + if(acpi_is_wakeup_s3()) + return; + if (mp_run_on_aps(run_on_single_aps, 1000) < 0) + printk(BIOS_ERR, "Fail to run SDHCI init \n"); +} + +/* + * This is to make sure that even if EMMC init fails somehow in Coreboot + * and in that case, there wont be any Memory resource allocated for it. + * So, in such case, before passing control to Payload, Assign the BAR + * address for EMMC dvice, and thus init can be handled in depthcharge + * without any problem. + */ +static void check_emmc_init(void *unused) +{ + struct storage_media *media; + device_t dev = PCH_DEV_EMMC; + u32 reg32; + + /* + * To make sure that the whole media info gets copied to cbmem location + * with cbmem_id "CBMEM_ID_STORAGE_DATA". + * If this is not done, then there might be a case where AP creates cbmem + * location with this ID, and before copying the data, BSP reaches to this + * point of the code and get improper data inside this cbmem location. + */ + while (1) + { + if (cbmem_copy_done == 1) + break; + } + + media = cbmem_find(CBMEM_ID_STORAGE_DATA); + if (media->ctrlr->initialized) + return; + + /* Program Temporary BAR for eMMC Device */ + pci_write_config32(dev, PCI_BASE_ADDRESS_0, EMMC_BASE_ADDRESS); + /* Ensure Memory and Bus Master bits are set */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config32(dev, PCI_COMMAND, reg32); +} + +static void read_resources(device_t dev) +{ + struct resource *res; + + res = new_resource(dev, PCI_BASE_ADDRESS_0); + res->base = EMMC_BASE_ADDRESS; + res->size = EMMC_BASE_SIZE; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; +} + +static void set_resources(device_t dev) +{ + struct resource *res; + + res = find_resource(dev, PCI_BASE_ADDRESS_0); + dev->command |= PCI_COMMAND_MEMORY; + res->flags |= IORESOURCE_STORED; + report_resource_stored(dev, res, "EMMC BAR 0"); +} + +static struct device_operations dev_ops = { + .read_resources = read_resources, + .set_resources = set_resources, + .enable_resources = DEVICE_NOOP, + .init = DEVICE_NOOP, + .scan_bus = NULL, + .enable = DEVICE_NOOP, + .ops_pci = &pci_dev_ops_pci, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_INTEL_SKL_EMMC, + 0 +}; + +static const struct pci_driver pch_emmc __pci_driver = { + .ops = &dev_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids +}; + +BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_ENTRY, init_emmc, NULL); +BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, check_emmc_init, NULL); +BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, check_emmc_init, NULL);