Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/30136 )
Change subject: Work in progress: Early eMMC phase 1
......................................................................
Patch Set 1:
This change is ready for review.
--
To view, visit https://review.coreboot.org/c/coreboot/+/30136
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I753a3324aadc1cb00aae560b17e342469f804832
Gerrit-Change-Number: 30136
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-Reviewer: Daniel Kurtz <djkurtz(a)google.com>
Gerrit-Reviewer: Martin Roth <martinroth(a)google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi(a)google.com>
Gerrit-Reviewer: Raul Rangel <rrangel(a)chromium.org>
Gerrit-Reviewer: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-Reviewer: Simon Glass <sjg(a)chromium.org>
Gerrit-Comment-Date: Mon, 10 Dec 2018 22:16:06 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment
Richard Spiegel has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30136
Change subject: Work in progress: Early eMMC phase 1
......................................................................
Work in progress: Early eMMC phase 1
Global objective: Early ready of eMMC by sending CMD0 and CMD1.
This phase objective: Create bh720 driver to be used by phase 2.
BUG=b:118680303
TEST=
Change-Id: I753a3324aadc1cb00aae560b17e342469f804832
Signed-off-by: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
---
A src/drivers/emmc/README
A src/drivers/emmc/bh7720/Kconfig
A src/drivers/emmc/bh7720/Makefile.inc
A src/drivers/emmc/bh7720/bh720.c
A src/include/device/emmc/bh720.h
A src/include/device/emmc/emmc.h
6 files changed, 450 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/36/30136/1
diff --git a/src/drivers/emmc/README b/src/drivers/emmc/README
new file mode 100644
index 0000000..b95b477
--- /dev/null
+++ b/src/drivers/emmc/README
@@ -0,0 +1,51 @@
+/*
+ * Documentation for eMMC host drivers
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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.
+ */
+
+This folder has drivers for several eMMC hosts. There's a minimum set of
+commands these drivers must implement, though it can implement more:
+emmc_driver_init -> initializes all required registers of a particular host,
+ so that commands can be send.
+emmc_send_command -> the host sends a command to the eMMC card, status is
+ returned.
+emmc_get_ocr -> The OCR value is read.
+
+Commands description:
+int emmc_driver_init(void *params);
+Some parameters are always the same, so they don't need to be send for code
+execution. Only parameters that are board dependent plus the base address
+should be send.
+The input is a void pointer to parameters, which is internally converted to
+a pointer to structure, defined in the chip specific header file. Inside
+this structure, the first 2 elements are common: (uint8_t) total and
+(uint16_t/uint32_t) base_address. The remaining are chip specific,.
+The return can be 0 if success, or a negative number if there's a problem.
+
+uint32_t emmc_send_command(uint8_t command, uint32_t argument);
+Using the base address from emmc_driver_init, it sends commands to the eMMC
+and return the host status at the moment the command was issued. This is only
+for 48-bits commands (start, stop, direction,CRC77, command and argument).
+
+uint32_t emmc_get_ocr(uint32_t base_address);
+This function can be called before or after PCI enumeration, as it receives
+the base address to use. If the base address is IO, the upper word should
+be 0. It assumes that CMD1 was already issued, and returns the OCR received
+from the eMMC.
+
+Generally speaking, emmc_driver_init must be used at romstage, while the
+other 2 can be romstage or ramstage, though if PCI access is needed by the
+particular chip to execute them, then they must be either romstage or have
+a device declared to be used in ramstage.
diff --git a/src/drivers/emmc/bh7720/Kconfig b/src/drivers/emmc/bh7720/Kconfig
new file mode 100644
index 0000000..27b5c80
--- /dev/null
+++ b/src/drivers/emmc/bh7720/Kconfig
@@ -0,0 +1,2 @@
+config DRIVERS_EMMC_BH720
+ bool
diff --git a/src/drivers/emmc/bh7720/Makefile.inc b/src/drivers/emmc/bh7720/Makefile.inc
new file mode 100644
index 0000000..e282a67
--- /dev/null
+++ b/src/drivers/emmc/bh7720/Makefile.inc
@@ -0,0 +1,2 @@
+romstage-$(CONFIG_DRIVERS_EMMC_BH720) += bh720.c
+ramstage-$(CONFIG_DRIVERS_EMMC_BH720) += bh720.c
diff --git a/src/drivers/emmc/bh7720/bh720.c b/src/drivers/emmc/bh7720/bh720.c
new file mode 100644
index 0000000..7dbafe4
--- /dev/null
+++ b/src/drivers/emmc/bh7720/bh720.c
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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 <rules.h>
+#include <device/pci_def.h>
+#include <device/emmc/emmc.h>
+#include <device/emmc/bh720.h>
+
+static uint8_t *base_ptr;
+static boolean flag = false;
+
+static void pci_set32(uint32_t dev, uint8_t reg, uint32_t bits)
+{
+ uint32_t value;
+ value = pci_read_config32(dev, reg);
+ value |= bits;
+ pci_write_config32(dev, reg, value);
+}
+
+static void pci_clear32(uint32_t dev, uint8_t reg, uint32_t bits)
+{
+ uint32_t value, mask;
+ mask = ~bits;
+ value = pci_read_config32(dev, reg);
+ value &= mask;
+ pci_write_config32(dev, reg, value);
+}
+
+static void pci_and_or32(uint32_t dev, uint8_t reg, uint32_t mask,
+ uint32_t bits)
+{
+ uint32_t value;
+ value = pci_read_config32(dev, reg);
+ value &= ~mask;
+ value |= bits;
+ pci_write_config32(dev, reg, value);
+}
+
+{
+
+static void program_base(uint32_t dev, uint32_t base)
+{
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
+ pci_write_config8(dev, PCI_COMMAND,
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+}
+
+static void clear_base(uint32_t dev)
+{
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, 0);
+ pci_write_config8(dev, PCI_COMMAND, 0);
+}
+
+static uint32_t host_dev_from_bridge(uint32_t dev)
+{
+ uint8_t byte;
+
+ byte = pci_read_config8(dev, PCI_SECONDARY_BUS);
+ return PCI_DEV(byte, 0, 0);
+}
+
+static int program_bridge(uint32_t dev, uintptr_t base), uint32_t size)
+{
+ uint32_t value, limit, h_dev;
+ uint8_t byte = pci_read_config8(dev, PCI_HEADER_TYPE);
+
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return EMMC_STATUS_INVALID_PCI;
+ byte = pci_read_config8(dev, PCI_COMMAND);
+ /* If not initialized, program bridge and device */
+ if ((byte & 0x0f) != (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY) {
+ /* Before enumeration, primary bus 0, secondary bus 1 */
+ pci_write_config32(dev, PCI_PRIMARY_BUS, 0x00010100);
+ limit = TEMP_BASE + (TEMP_SIZE - 1);
+ limit &= 0xffff0000;
+ value = (TEMP_BASE >> 16) & 0xffff;
+ value |= limit;
+ pci_write_config32(dev, PCI_MEMORY_BASE, value);
+ pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY);
+ h_dev = PCI_DEV(1, 0, 0);
+ program_base(h_dev, TEMP_BASE);
+ }
+ return EMMC_STATUS_SUCCESS;
+}
+
+static void clear_bridge(uint32_t dev)
+{
+ pci_write_config8(dev, PCI_COMMAND, 0);
+ pci_write_config32(dev, PCI_PRIMARY_BUS, 0);
+ pci_write_config32(dev, PCI_MEMORY_BASE, 0);
+}
+
+static void program_id(uint32_t dev, uint32_t id)
+{
+ pci_clear32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+ pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, id);
+ pci_set32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+}
+
+static int read_base(uint32_t dev, uint32_t id)
+{
+ uint32_t emmc_dev;
+ int status;
+
+ status = program_bridge(dev, (uint32_t)base_ptr, TEMP_SIZE);
+ if (status != EMMC_STATUS_SUCCESS)
+ return status;
+ emmc_dev = host_dev_from_bridge(dev);
+ base_ptr = (uint8_t *)pci_read_config32(emmc_dev, PCI_BASE_ADDRESS_0);
+ if (id)
+ program_id(emmc_dev, id);
+ return EMMC_STATUS_SUCCESS;
+}
+
+int emmc_driver_init(void *params)
+{
+ bh720_params *param = (bh720_params *)params;
+ uint32_t temp;
+ uint32_t device = param->pci_dev;
+ uint32_t subsys_id = param->subsys_vend_dev_id;
+ uint8_t total = param->total
+ uint8_t mode = DEFAUT_MODE;
+ int status = EMMC_STATUS_SUCCESS;
+
+ base_ptr = (uint8_t *)param->base_address;
+ if (total > 4)
+ mode = param->mode;
+ if (total == 0)
+ return EMMC_STATUS_INVALID_PARAM;
+ if (total == 1)
+ return read_base(device, subsys_id);
+ if ((total == 2) || (total == 3)) {
+ if (base_ptr == NULL)
+ return EMMC_STATUS_INVALID_PARAM;
+ return status;
+ }
+ if (subsys_id && (mode & MODE_VEND_DEV))
+ program_id(device, subsys_id);
+/* If romstage, no other action is allowed. */
+#if defined(__SIMPLE_DEVICE__)
+ if (mode > MODE_VEND_DEV)
+ return EMMC_STATUS_INVALID_STAGE;
+#endif
+ pci_clear32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+ if (mode & MODE_DIS_SD) {
+ pci_and_or32(dev, BH720_PML1_TIMER,
+ BH720_PML1_TIMER_MASK, BH720_PML1_TIMER_16US);
+ pci_set_32(dev, BH720_RTD3_L1, BH720_RTD3_L1_DISABLE_L1);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_L0_ENABLE |
+ BH720_LINK_CTRL_L1_ENABLE);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_CLKREQ);
+ pci_clear32(dev, BH720_ENABLES, BH_720_SD_ENABLE);
+ }
+ if (mode & MODE_VCCQ_18)
+ pci_set_32(dev, BH720_PCR_EMMC_SETTING,
+ BH720_PCR_EMMC_SETTING_1_8V};
+ if (mode & MODE_POWER_SAVE) {
+ pci_set_32(dev, BH720_RTD3_L1, BH720_RTD3_L1_DISABLE_L1);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_L0_ENABLE |
+ BH720_LINK_CTRL_L1_ENABLE);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_CLKREQ);
+ }
+ if (mode & MODE_L1_TIMER) {
+ pci_and_or32(dev, BH720_PML1_TIMER,
+ BH720_PML1_TIMER_MASK, BH720_PML1_TIMER_16US);
+ pci_and_or32(dev, BH720_ASPM_TIMERS,
+ BH720_L1_ENTRANCE_TIMER_MASK,
+ BH720_L1_ENTRANCE_TIMER_512US);
+ }
+ if (mode & MODE_IDDQ)
+ pci_set_32(dev, BH720_PCR_CSR, BH720_PCR_CSR__IDD_SEL);
+ if (mode & MODE_TUNING)
+ pci_and_or32(dev, BH720_TUNING,
+ BH720_TUNING_HS200_MASK,
+ 5 << BH720_TUNING_HS200_SHIFT);
+ if (mode & MODE_DLL_CLK_PHASE)
+ pci_and_or32(dev, BH720_TUNING,
+ BH720_TUNING_SAMPLE_CLK_MASK,
+ 6 << BH720_TUNING_SAMPLE_CLK_SHIFT);
+ pci_set32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+ return status;
+}
+
+uint32_t emmc_send_command(uint8_t command, uint32_t argument)
+{
+ uint32_t *arg_ptr = (uint32_t *)base_ptr + 8;
+ uint32_t *resp_ptr = (uint32_t *)base_ptr + 0x10;
+ uint16_t *cmd_ptr = (uint16_t *)base_ptr + 0x0e;
+ uint16_t cmd = (command & 0x3f) << 8;
+
+ cmd |= 0x1a; /* check index and CRC, 48 bits. */
+ if (command == 1)
+ cmd++; /* 48 bits with busy */
+ *arg_ptr = argument;
+ *cmd_ptr = cmd; /* send command */
+ udelay(5)
+ return *resp_ptr;
+}
+
+/* Todo: need to understand if there's status for CMD1 or just OCR */
+uint32_t emmc_get_ocr(uint32_t base_address)
+{
+ uint32_t *ocr_ptr = (uint32_t *)base_address + 0x10;
+ return *ocr_ptr;
+}
+
+/*
+ * If initialized with total = 1 before PCI initialization (program base
+ * address with temporary value, then use this at the end, before PCI
+ * enumeration.
+ */
+int release_base(uint32_t dev)
+{
+ uint32_t host;
+ uint8_t byte = pci_read_config8(dev, PCI_HEADER_TYPE);
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return EMMC_STATUS_INVALID_PCI;
+ host = host_dev_from_bridge(dev);
+ clear_base(host);
+ clear_bridge(dev);
+}
+
+/*
+ * If used temporary base before PCI enumeration, use this function to update
+ * eMMC base address, based on actual PCI enumeration.
+ */
+int update_base(uint32_t dev)
+{
+ uint32_t emmc_dev, base;
+ uint8_t byte = pci_read_config8(dev, PCI_HEADER_TYPE);
+
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return EMMC_STATUS_INVALID_PCI;
+ emmc_dev = host_dev_from_bridge(dev);
+ base = (0xffff & pci_read_config32(dev, PCI_MEMORY_BASE));
+ base_ptr = (uint8_t *)(base << 16);
+ program_base(emmc_dev, base << 16);
+ return EMMC_STATUS_SUCCESS;
+}
diff --git a/src/include/device/emmc/bh720.h b/src/include/device/emmc/bh720.h
new file mode 100644
index 0000000..7210130
--- /dev/null
+++ b/src/include/device/emmc/bh720.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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 __BH720_H__
+#define __BH720_H__
+
+#include <types.h>
+
+struct bh720_params {
+ uint8_t total; /* Note 1 */
+ uintptr_t base_address; /* memory address */
+ uint32_t pci_dev; /* PCI_DEV(bus, slot, func) */
+ uint32_t subsys_vend_dev_id; /* if 0 or total = 3, do not set */
+ uint8_t mode; /* optional, note 2 */
+}; /* total 5 parameters, so if all parameters, total = 5 */
+/*
+ * Note 1: The value of total shold be between 3 and 5, so use value of 1 for:
+ * A) pci_dev is relative to the bridge the host resides.
+ * B) If the bridge has not been programmed, then program the BAR with base
+ * address.
+ * C) If bridge is programmed, then read BAR0 into base_address.
+ * D) If subsys_vend_dev_id is provided and (B) than program subsystem vendor
+ * and device IDs.
+ *
+ * Note 2: MODE_DIS_SD, MODE_VCCQ_18, MODE_POWER_SAVE, MODE_IDDQ, MODE_TUNING,
+ * MODE_DLL_CLK_PHASE can only be set in ramstage, with a BH720 device defined,
+ * because they access PCI config space above 0xff.
+ */
+
+#define BH720_LINK_CTRL 0x90
+#define BH720_LINK_CTRL_L0_ENABLE BIT(0)
+#define BH720_LINK_CTRL_L1_ENABLE BIT(1)
+#define BH720_LINK_CTRL_CLKREQ BIT(8)
+#define BH720_PROTECT 0xd0
+#define BH720_PROTECT_LOCK_ON BIT(0)
+#define BH720_PROTECT_ON BIT(31)
+#define BH720_ENABLES 0xdc
+#define BH_720_SD_ENABLE BIT(0)
+#define BH720_PML1_TIMER 0xe0
+#define BH720_PML1_TIMER_SHIFT 28
+#define BH720_PML1_TIMER_MASK (0xf << BH720_PML1_TIMER_SHIFT)
+#define BH720_PML1_TIMER_16US (0x3 << BH720_PML1_TIMER_SHIFT)
+#define BH720_MISC2 0xf0
+#define BH720_MISC2_ASPM_DISABLE BIT(0)
+#define BH720_MISC2_APSM_CLKREQ_L1 BIT(7)
+#define BH720_MISC2_APSM_PHY_L1 BIT(10)
+#define BH720_MISC2_APSM_MORE BIT(12)
+#define BH720_ASPM_TIMERS 0xfc
+#define BH720_L1_ENTR_TIMER_SHIFT 16
+#define BH720_L1_ENTRANCE_TIMER_MASK (0xf << BH720_L1_ENTR_TIMER_SHIFT)
+#define BH720_L1_ENTRANCE_TIMER_512US (0x1000 << BH720_L1_ENTR_TIMER_SHIFT)
+#define BH720_MEM_RW_DATA 0x200
+#define BH720_MEM_RW_ADR 0x204
+#define BH720_MEM_RW_READ BIT(30)
+#define BH720_MEM_RW_WRITE BIT(31)
+#define BH720_MEM_ACCESS_EN 0x208
+#define BH720_TUNING 0x300
+#define BH720_TUNING_HS200_SHIFT 4
+#define BH720_TUNING_HS200_MASK (0xf << BH720_TUNING_HS200_SHIFT)
+#define BH720_TUNING_SAMPLE_CLK_SHIFT 12
+#define BH720_TUNING_SAMPLE_CLK_MASK (0xf << BH720_TUNING_SAMPLE_CLK_SHIFT)
+#define BH720_PCR_DRV_STRENGHT_PLL 0x304
+#define BH720_PCR_DATA_CMD_DRV_MAX 7
+#define BH720_PCR_CLK_DRV_MAX 7
+#define BH720_PCR_EMMC_SETTING 0x308
+#define BH720_PCR_EMMC_SETTING_1_8V BIT(4)
+#define BH720_RTD3_L1 0x3e0
+#define BH720_RTD3_L1_DISABLE_L1 BIT(28)
+#define BH720_PCR_CSR 0x3e4
+#define BH720_PCR_CSR__IDD_SEL BIT(19)
+#define BH720_PCR_CSR_EMMC_MODE_SEL BIT(22)
+
+#define TEMP_BASE 0xf4a00000
+#define TEMP_SIZE 0x1000
+
+#define MODE_VEND_DEV BIT(0)
+#define MODE_DIS_SD BIT(1)
+#define MODE_VCCQ_18 BIT(2)
+#define MODE_POWER_SAVE BIT(3)
+#define MODE_L1_TIMER BIT(4)
+#define MODE_IDDQ BIT(5)
+#define MODE_TUNING BIT(6)
+#define MODE_DLL_CLK_PHASE BIT(7)
+
+#define DEFAUT_MODE MODE_VEND_DEV
+
+/* Input is bridge device/func */
+int release_base(uint32_t dev);
+int update_base(uint32_t dev);
+#endif
diff --git a/src/include/device/emmc/emmc.h b/src/include/device/emmc/emmc.h
new file mode 100644
index 0000000..0826f53
--- /dev/null
+++ b/src/include/device/emmc/emmc.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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 __EMMC_H__
+#define __EMMC_H__
+
+#define EMMC_PARAM_BYTE 1
+#define EMMC_PARAM_WORD 2
+#define EMMC_PARAM_DWORD 3
+#define EMMC_PARAM_QWORD 4
+#define EMMC_PARAM_PCI_DEV 5
+
+#define EMMC_STATUS_SUCCESS 0
+#define EMMC_STATUS_INVALID_PARAM -1
+#define EMMC_STATUS_NO_BASE_ADDRESS -2 /* drive not initialized */
+#define EMMC_STATUS_INVALID_BASE_ADDR -3 /* invalid base size */
+#define EMMC_STATUS_INVALID_PCI -4 /* invalid pci */
+#define EMMC_STATUS_HOST_BUSY -5 /* bit 31 of OCR 0b */
+#define EMMC_STATUS_INVALID_STAGE -6 /* PCI reg > 0xff in romstage */
+
+int emmc_driver_init(void *params);
+uint32_t emmc_send_command(uint8_t command, uint32_t argument);
+uint32_t emmc_get_ocr(uint32_t base_address);
+
+int emmc_go_idle(void);
+int emmc_go_ready(uint32_t argument); /* CMD1 argument depends on board/host */
+int emmc_check_ready{uint32_t *ocr, uint32_t base_address);
+
+#endif
--
To view, visit https://review.coreboot.org/c/coreboot/+/30136
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I753a3324aadc1cb00aae560b17e342469f804832
Gerrit-Change-Number: 30136
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-MessageType: newchange
Richard Spiegel has abandoned this change. ( https://review.coreboot.org/c/coreboot/+/30135 )
Change subject: Work in progress: Early eMMC phase 1
......................................................................
Abandoned
duplicate
--
To view, visit https://review.coreboot.org/c/coreboot/+/30135
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I9e4f356623a00bcdd75d9ee1775ebc961807696c
Gerrit-Change-Number: 30135
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-Reviewer: Martin Roth <martinroth(a)google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi(a)google.com>
Gerrit-Reviewer: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-CC: build bot (Jenkins) <no-reply(a)coreboot.org>
Gerrit-MessageType: abandon
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/30135 )
Change subject: Work in progress: Early eMMC phase 1
......................................................................
Patch Set 1:
(2 comments)
https://review.coreboot.org/#/c/30135/1/src/include/device/emmc/bh720.h
File src/include/device/emmc/bh720.h:
https://review.coreboot.org/#/c/30135/1/src/include/device/emmc/bh720.h@32
PS1, Line 32: * adress.
'adress' may be misspelled - perhaps 'address'?
https://review.coreboot.org/#/c/30135/1/src/include/device/emmc/bh720.h@37
PS1, Line 37: * Note 2: MODE_DIS_SD, MODE_VCCQ_18, MODE_POWER_SAVE, MODE_IDDQ, MODE_TUNNING,
'TUNNING' may be misspelled - perhaps 'TUNING'?
--
To view, visit https://review.coreboot.org/c/coreboot/+/30135
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I9e4f356623a00bcdd75d9ee1775ebc961807696c
Gerrit-Change-Number: 30135
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-Reviewer: Martin Roth <martinroth(a)google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi(a)google.com>
Gerrit-Reviewer: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-CC: build bot (Jenkins) <no-reply(a)coreboot.org>
Gerrit-Comment-Date: Mon, 10 Dec 2018 21:49:46 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment
Richard Spiegel has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30135
Change subject: Work in progress: Early eMMC phase 1
......................................................................
Work in progress: Early eMMC phase 1
Global objective: Early ready of eMMC by sending CMD0 and CMD1.
This phase objective: Create bh720 driver to be used by phase 2.
BUG=b:118680303
TEST=
Change-Id: I9e4f356623a00bcdd75d9ee1775ebc961807696c
Signed-off-by: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
---
A src/drivers/emmc/README
A src/drivers/emmc/bh7720/Kconfig
A src/drivers/emmc/bh7720/Makefile.inc
A src/drivers/emmc/bh7720/bh720.c
A src/include/device/emmc/bh720.h
A src/include/device/emmc/emmc.h
6 files changed, 450 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/35/30135/1
diff --git a/src/drivers/emmc/README b/src/drivers/emmc/README
new file mode 100644
index 0000000..b95b477
--- /dev/null
+++ b/src/drivers/emmc/README
@@ -0,0 +1,51 @@
+/*
+ * Documentation for eMMC host drivers
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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.
+ */
+
+This folder has drivers for several eMMC hosts. There's a minimum set of
+commands these drivers must implement, though it can implement more:
+emmc_driver_init -> initializes all required registers of a particular host,
+ so that commands can be send.
+emmc_send_command -> the host sends a command to the eMMC card, status is
+ returned.
+emmc_get_ocr -> The OCR value is read.
+
+Commands description:
+int emmc_driver_init(void *params);
+Some parameters are always the same, so they don't need to be send for code
+execution. Only parameters that are board dependent plus the base address
+should be send.
+The input is a void pointer to parameters, which is internally converted to
+a pointer to structure, defined in the chip specific header file. Inside
+this structure, the first 2 elements are common: (uint8_t) total and
+(uint16_t/uint32_t) base_address. The remaining are chip specific,.
+The return can be 0 if success, or a negative number if there's a problem.
+
+uint32_t emmc_send_command(uint8_t command, uint32_t argument);
+Using the base address from emmc_driver_init, it sends commands to the eMMC
+and return the host status at the moment the command was issued. This is only
+for 48-bits commands (start, stop, direction,CRC77, command and argument).
+
+uint32_t emmc_get_ocr(uint32_t base_address);
+This function can be called before or after PCI enumeration, as it receives
+the base address to use. If the base address is IO, the upper word should
+be 0. It assumes that CMD1 was already issued, and returns the OCR received
+from the eMMC.
+
+Generally speaking, emmc_driver_init must be used at romstage, while the
+other 2 can be romstage or ramstage, though if PCI access is needed by the
+particular chip to execute them, then they must be either romstage or have
+a device declared to be used in ramstage.
diff --git a/src/drivers/emmc/bh7720/Kconfig b/src/drivers/emmc/bh7720/Kconfig
new file mode 100644
index 0000000..27b5c80
--- /dev/null
+++ b/src/drivers/emmc/bh7720/Kconfig
@@ -0,0 +1,2 @@
+config DRIVERS_EMMC_BH720
+ bool
diff --git a/src/drivers/emmc/bh7720/Makefile.inc b/src/drivers/emmc/bh7720/Makefile.inc
new file mode 100644
index 0000000..e282a67
--- /dev/null
+++ b/src/drivers/emmc/bh7720/Makefile.inc
@@ -0,0 +1,2 @@
+romstage-$(CONFIG_DRIVERS_EMMC_BH720) += bh720.c
+ramstage-$(CONFIG_DRIVERS_EMMC_BH720) += bh720.c
diff --git a/src/drivers/emmc/bh7720/bh720.c b/src/drivers/emmc/bh7720/bh720.c
new file mode 100644
index 0000000..7dbafe4
--- /dev/null
+++ b/src/drivers/emmc/bh7720/bh720.c
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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 <rules.h>
+#include <device/pci_def.h>
+#include <device/emmc/emmc.h>
+#include <device/emmc/bh720.h>
+
+static uint8_t *base_ptr;
+static boolean flag = false;
+
+static void pci_set32(uint32_t dev, uint8_t reg, uint32_t bits)
+{
+ uint32_t value;
+ value = pci_read_config32(dev, reg);
+ value |= bits;
+ pci_write_config32(dev, reg, value);
+}
+
+static void pci_clear32(uint32_t dev, uint8_t reg, uint32_t bits)
+{
+ uint32_t value, mask;
+ mask = ~bits;
+ value = pci_read_config32(dev, reg);
+ value &= mask;
+ pci_write_config32(dev, reg, value);
+}
+
+static void pci_and_or32(uint32_t dev, uint8_t reg, uint32_t mask,
+ uint32_t bits)
+{
+ uint32_t value;
+ value = pci_read_config32(dev, reg);
+ value &= ~mask;
+ value |= bits;
+ pci_write_config32(dev, reg, value);
+}
+
+{
+
+static void program_base(uint32_t dev, uint32_t base)
+{
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
+ pci_write_config8(dev, PCI_COMMAND,
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+}
+
+static void clear_base(uint32_t dev)
+{
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, 0);
+ pci_write_config8(dev, PCI_COMMAND, 0);
+}
+
+static uint32_t host_dev_from_bridge(uint32_t dev)
+{
+ uint8_t byte;
+
+ byte = pci_read_config8(dev, PCI_SECONDARY_BUS);
+ return PCI_DEV(byte, 0, 0);
+}
+
+static int program_bridge(uint32_t dev, uintptr_t base), uint32_t size)
+{
+ uint32_t value, limit, h_dev;
+ uint8_t byte = pci_read_config8(dev, PCI_HEADER_TYPE);
+
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return EMMC_STATUS_INVALID_PCI;
+ byte = pci_read_config8(dev, PCI_COMMAND);
+ /* If not initialized, program bridge and device */
+ if ((byte & 0x0f) != (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY) {
+ /* Before enumeration, primary bus 0, secondary bus 1 */
+ pci_write_config32(dev, PCI_PRIMARY_BUS, 0x00010100);
+ limit = TEMP_BASE + (TEMP_SIZE - 1);
+ limit &= 0xffff0000;
+ value = (TEMP_BASE >> 16) & 0xffff;
+ value |= limit;
+ pci_write_config32(dev, PCI_MEMORY_BASE, value);
+ pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY);
+ h_dev = PCI_DEV(1, 0, 0);
+ program_base(h_dev, TEMP_BASE);
+ }
+ return EMMC_STATUS_SUCCESS;
+}
+
+static void clear_bridge(uint32_t dev)
+{
+ pci_write_config8(dev, PCI_COMMAND, 0);
+ pci_write_config32(dev, PCI_PRIMARY_BUS, 0);
+ pci_write_config32(dev, PCI_MEMORY_BASE, 0);
+}
+
+static void program_id(uint32_t dev, uint32_t id)
+{
+ pci_clear32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+ pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, id);
+ pci_set32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+}
+
+static int read_base(uint32_t dev, uint32_t id)
+{
+ uint32_t emmc_dev;
+ int status;
+
+ status = program_bridge(dev, (uint32_t)base_ptr, TEMP_SIZE);
+ if (status != EMMC_STATUS_SUCCESS)
+ return status;
+ emmc_dev = host_dev_from_bridge(dev);
+ base_ptr = (uint8_t *)pci_read_config32(emmc_dev, PCI_BASE_ADDRESS_0);
+ if (id)
+ program_id(emmc_dev, id);
+ return EMMC_STATUS_SUCCESS;
+}
+
+int emmc_driver_init(void *params)
+{
+ bh720_params *param = (bh720_params *)params;
+ uint32_t temp;
+ uint32_t device = param->pci_dev;
+ uint32_t subsys_id = param->subsys_vend_dev_id;
+ uint8_t total = param->total
+ uint8_t mode = DEFAUT_MODE;
+ int status = EMMC_STATUS_SUCCESS;
+
+ base_ptr = (uint8_t *)param->base_address;
+ if (total > 4)
+ mode = param->mode;
+ if (total == 0)
+ return EMMC_STATUS_INVALID_PARAM;
+ if (total == 1)
+ return read_base(device, subsys_id);
+ if ((total == 2) || (total == 3)) {
+ if (base_ptr == NULL)
+ return EMMC_STATUS_INVALID_PARAM;
+ return status;
+ }
+ if (subsys_id && (mode & MODE_VEND_DEV))
+ program_id(device, subsys_id);
+/* If romstage, no other action is allowed. */
+#if defined(__SIMPLE_DEVICE__)
+ if (mode > MODE_VEND_DEV)
+ return EMMC_STATUS_INVALID_STAGE;
+#endif
+ pci_clear32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+ if (mode & MODE_DIS_SD) {
+ pci_and_or32(dev, BH720_PML1_TIMER,
+ BH720_PML1_TIMER_MASK, BH720_PML1_TIMER_16US);
+ pci_set_32(dev, BH720_RTD3_L1, BH720_RTD3_L1_DISABLE_L1);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_L0_ENABLE |
+ BH720_LINK_CTRL_L1_ENABLE);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_CLKREQ);
+ pci_clear32(dev, BH720_ENABLES, BH_720_SD_ENABLE);
+ }
+ if (mode & MODE_VCCQ_18)
+ pci_set_32(dev, BH720_PCR_EMMC_SETTING,
+ BH720_PCR_EMMC_SETTING_1_8V};
+ if (mode & MODE_POWER_SAVE) {
+ pci_set_32(dev, BH720_RTD3_L1, BH720_RTD3_L1_DISABLE_L1);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_L0_ENABLE |
+ BH720_LINK_CTRL_L1_ENABLE);
+ pci_set_32(dev, BH720_LINK_CTRL, BH720_LINK_CTRL_CLKREQ);
+ }
+ if (mode & MODE_L1_TIMER) {
+ pci_and_or32(dev, BH720_PML1_TIMER,
+ BH720_PML1_TIMER_MASK, BH720_PML1_TIMER_16US);
+ pci_and_or32(dev, BH720_ASPM_TIMERS,
+ BH720_L1_ENTRANCE_TIMER_MASK,
+ BH720_L1_ENTRANCE_TIMER_512US);
+ }
+ if (mode & MODE_IDDQ)
+ pci_set_32(dev, BH720_PCR_CSR, BH720_PCR_CSR__IDD_SEL);
+ if (mode & MODE_TUNING)
+ pci_and_or32(dev, BH720_TUNING,
+ BH720_TUNING_HS200_MASK,
+ 5 << BH720_TUNING_HS200_SHIFT);
+ if (mode & MODE_DLL_CLK_PHASE)
+ pci_and_or32(dev, BH720_TUNING,
+ BH720_TUNING_SAMPLE_CLK_MASK,
+ 6 << BH720_TUNING_SAMPLE_CLK_SHIFT);
+ pci_set32(dev, BH720_PROTECT, BH720_PROTECT_ON);
+ return status;
+}
+
+uint32_t emmc_send_command(uint8_t command, uint32_t argument)
+{
+ uint32_t *arg_ptr = (uint32_t *)base_ptr + 8;
+ uint32_t *resp_ptr = (uint32_t *)base_ptr + 0x10;
+ uint16_t *cmd_ptr = (uint16_t *)base_ptr + 0x0e;
+ uint16_t cmd = (command & 0x3f) << 8;
+
+ cmd |= 0x1a; /* check index and CRC, 48 bits. */
+ if (command == 1)
+ cmd++; /* 48 bits with busy */
+ *arg_ptr = argument;
+ *cmd_ptr = cmd; /* send command */
+ udelay(5)
+ return *resp_ptr;
+}
+
+/* Todo: need to understand if there's status for CMD1 or just OCR */
+uint32_t emmc_get_ocr(uint32_t base_address)
+{
+ uint32_t *ocr_ptr = (uint32_t *)base_address + 0x10;
+ return *ocr_ptr;
+}
+
+/*
+ * If initialized with total = 1 before PCI initialization (program base
+ * address with temporary value, then use this at the end, before PCI
+ * enumeration.
+ */
+int release_base(uint32_t dev)
+{
+ uint32_t host;
+ uint8_t byte = pci_read_config8(dev, PCI_HEADER_TYPE);
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return EMMC_STATUS_INVALID_PCI;
+ host = host_dev_from_bridge(dev);
+ clear_base(host);
+ clear_bridge(dev);
+}
+
+/*
+ * If used temporary base before PCI enumeration, use this function to update
+ * eMMC base address, based on actual PCI enumeration.
+ */
+int update_base(uint32_t dev)
+{
+ uint32_t emmc_dev, base;
+ uint8_t byte = pci_read_config8(dev, PCI_HEADER_TYPE);
+
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return EMMC_STATUS_INVALID_PCI;
+ emmc_dev = host_dev_from_bridge(dev);
+ base = (0xffff & pci_read_config32(dev, PCI_MEMORY_BASE));
+ base_ptr = (uint8_t *)(base << 16);
+ program_base(emmc_dev, base << 16);
+ return EMMC_STATUS_SUCCESS;
+}
diff --git a/src/include/device/emmc/bh720.h b/src/include/device/emmc/bh720.h
new file mode 100644
index 0000000..3715d0b
--- /dev/null
+++ b/src/include/device/emmc/bh720.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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 __BH720_H__
+#define __BH720_H__
+
+#include <types.h>
+
+struct bh720_params {
+ uint8_t total; /* Note 1 */
+ uintptr_t base_address; /* memory address */
+ uint32_t pci_dev; /* PCI_DEV(bus, slot, func) */
+ uint32_t subsys_vend_dev_id; /* if 0 or total = 3, do not set */
+ uint8_t mode; /* optional, note 2 */
+}; /* total 5 parameters, so if all parameters, total = 5 */
+/*
+ * Note 1: The value of total shold be between 3 and 5, so use value of 1 for:
+ * A) pci_dev is relative to the bridge the host resides.
+ * B) If the bridge has not been programmed, then program the BAR with base
+ * adress.
+ * C) If bridge is programmed, then read BAR0 into base_address.
+ * D) If subsys_vend_dev_id is provided and (B) than program subsystem vendor
+ * and device IDs.
+ *
+ * Note 2: MODE_DIS_SD, MODE_VCCQ_18, MODE_POWER_SAVE, MODE_IDDQ, MODE_TUNNING,
+ * MODE_DLL_CLK_PHASE can only be set in ramstage, with a BH720 device defined,
+ * because they access PCI config space above 0xff.
+ */
+
+#define BH720_LINK_CTRL 0x90
+#define BH720_LINK_CTRL_L0_ENABLE BIT(0)
+#define BH720_LINK_CTRL_L1_ENABLE BIT(1)
+#define BH720_LINK_CTRL_CLKREQ BIT(8)
+#define BH720_PROTECT 0xd0
+#define BH720_PROTECT_LOCK_ON BIT(0)
+#define BH720_PROTECT_ON BIT(31)
+#define BH720_ENABLES 0xdc
+#define BH_720_SD_ENABLE BIT(0)
+#define BH720_PML1_TIMER 0xe0
+#define BH720_PML1_TIMER_SHIFT 28
+#define BH720_PML1_TIMER_MASK (0xf << BH720_PML1_TIMER_SHIFT)
+#define BH720_PML1_TIMER_16US (0x3 << BH720_PML1_TIMER_SHIFT)
+#define BH720_MISC2 0xf0
+#define BH720_MISC2_ASPM_DISABLE BIT(0)
+#define BH720_MISC2_APSM_CLKREQ_L1 BIT(7)
+#define BH720_MISC2_APSM_PHY_L1 BIT(10)
+#define BH720_MISC2_APSM_MORE BIT(12)
+#define BH720_ASPM_TIMERS 0xfc
+#define BH720_L1_ENTR_TIMER_SHIFT 16
+#define BH720_L1_ENTRANCE_TIMER_MASK (0xf << BH720_L1_ENTR_TIMER_SHIFT)
+#define BH720_L1_ENTRANCE_TIMER_512US (0x1000 << BH720_L1_ENTR_TIMER_SHIFT)
+#define BH720_MEM_RW_DATA 0x200
+#define BH720_MEM_RW_ADR 0x204
+#define BH720_MEM_RW_READ BIT(30)
+#define BH720_MEM_RW_WRITE BIT(31)
+#define BH720_MEM_ACCESS_EN 0x208
+#define BH720_TUNING 0x300
+#define BH720_TUNING_HS200_SHIFT 4
+#define BH720_TUNING_HS200_MASK (0xf << BH720_TUNING_HS200_SHIFT)
+#define BH720_TUNING_SAMPLE_CLK_SHIFT 12
+#define BH720_TUNING_SAMPLE_CLK_MASK (0xf << BH720_TUNING_SAMPLE_CLK_SHIFT)
+#define BH720_PCR_DRV_STRENGHT_PLL 0x304
+#define BH720_PCR_DATA_CMD_DRV_MAX 7
+#define BH720_PCR_CLK_DRV_MAX 7
+#define BH720_PCR_EMMC_SETTING 0x308
+#define BH720_PCR_EMMC_SETTING_1_8V BIT(4)
+#define BH720_RTD3_L1 0x3e0
+#define BH720_RTD3_L1_DISABLE_L1 BIT(28)
+#define BH720_PCR_CSR 0x3e4
+#define BH720_PCR_CSR__IDD_SEL BIT(19)
+#define BH720_PCR_CSR_EMMC_MODE_SEL BIT(22)
+
+#define TEMP_BASE 0xf4a00000
+#define TEMP_SIZE 0x1000
+
+#define MODE_VEND_DEV BIT(0)
+#define MODE_DIS_SD BIT(1)
+#define MODE_VCCQ_18 BIT(2)
+#define MODE_POWER_SAVE BIT(3)
+#define MODE_L1_TIMER BIT(4)
+#define MODE_IDDQ BIT(5)
+#define MODE_TUNING BIT(6)
+#define MODE_DLL_CLK_PHASE BIT(7)
+
+#define DEFAUT_MODE MODE_VEND_DEV
+
+/* Input is bridge device/func */
+int release_base(uint32_t dev);
+int update_base(uint32_t dev);
+#endif
diff --git a/src/include/device/emmc/emmc.h b/src/include/device/emmc/emmc.h
new file mode 100644
index 0000000..0826f53
--- /dev/null
+++ b/src/include/device/emmc/emmc.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Silverback Ltd.
+ *
+ * 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 __EMMC_H__
+#define __EMMC_H__
+
+#define EMMC_PARAM_BYTE 1
+#define EMMC_PARAM_WORD 2
+#define EMMC_PARAM_DWORD 3
+#define EMMC_PARAM_QWORD 4
+#define EMMC_PARAM_PCI_DEV 5
+
+#define EMMC_STATUS_SUCCESS 0
+#define EMMC_STATUS_INVALID_PARAM -1
+#define EMMC_STATUS_NO_BASE_ADDRESS -2 /* drive not initialized */
+#define EMMC_STATUS_INVALID_BASE_ADDR -3 /* invalid base size */
+#define EMMC_STATUS_INVALID_PCI -4 /* invalid pci */
+#define EMMC_STATUS_HOST_BUSY -5 /* bit 31 of OCR 0b */
+#define EMMC_STATUS_INVALID_STAGE -6 /* PCI reg > 0xff in romstage */
+
+int emmc_driver_init(void *params);
+uint32_t emmc_send_command(uint8_t command, uint32_t argument);
+uint32_t emmc_get_ocr(uint32_t base_address);
+
+int emmc_go_idle(void);
+int emmc_go_ready(uint32_t argument); /* CMD1 argument depends on board/host */
+int emmc_check_ready{uint32_t *ocr, uint32_t base_address);
+
+#endif
--
To view, visit https://review.coreboot.org/c/coreboot/+/30135
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I9e4f356623a00bcdd75d9ee1775ebc961807696c
Gerrit-Change-Number: 30135
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel(a)silverbackltd.com>
Gerrit-MessageType: newchange
Duncan Laurie has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30133
Change subject: soc/intel/cannonlake: Add GPIO group pad base for ACPI
......................................................................
soc/intel/cannonlake: Add GPIO group pad base for ACPI
The GPIO drivers in Windows and Linux for the Cannonlake CPU
have a sparse GPIO map and do not allocate pins contiguously.
Each GPIO group is allocated as 32 pads regardless of whether
the hardware actually has that many in the group.
It appears this originated with a bug in Windows/UEFI and was
carried over to Linux in order to work with existing firmware:
https://lore.kernel.org/patchwork/patch/855244/
In order to support using ACPI GPIOs it is necessary for coreboot
to be compatible with this implementation. The GPIO groups that
are usable by the OS are declared with a pad base which is then
used to compute the number for ACPI GPIOs.
BUG=b:120686247
TEST=tested with write protect GPIO on sarien board. Before this
change the ACPI pin number was 220 which did not correspond to the
pin number in Linux. After this change the ACPI number is 303,
which maps to the correct GPIO in Linux. Now the GPIO value reported
by the kernel changes when the WP pin is toggled in hardware.
Change-Id: I4f1a9e118d7e48f2445ccbb62a12a22e9a832c51
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
M src/soc/intel/cannonlake/gpio.c
1 file changed, 28 insertions(+), 13 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/33/30133/1
diff --git a/src/soc/intel/cannonlake/gpio.c b/src/soc/intel/cannonlake/gpio.c
index 2705bcf..701eb0b 100644
--- a/src/soc/intel/cannonlake/gpio.c
+++ b/src/soc/intel/cannonlake/gpio.c
@@ -32,34 +32,49 @@
{ .logical = PAD_CFG0_LOGICAL_RESET_RSMRST, .chipset = 3U << 30 },
};
+/*
+ * The GPIO driver for Cannonlake on Windows/Linux expects 32 GPIOs per pad
+ * group, regardless of whether or not there is a physical pad for each
+ * exposed GPIO number.
+ *
+ * This results in the OS having a sparse GPIO map, and devices that need
+ * to export an ACPI GPIO must use the OS expected number.
+ *
+ * Not all pins are usable as GPIO and those groups do not have a pad base.
+ *
+ * This layout matches the Linux kernel pinctrl map for CNL-LP at:
+ * linux/drivers/pinctrl/intel/pinctrl-cannonlake.c
+ */
static const struct pad_group cnl_community0_groups[] = {
- INTEL_GPP(GPP_A0, GPP_A0, GPIO_RSVD_0), /* GPP_A */
- INTEL_GPP(GPP_A0, GPP_B0, GPIO_RSVD_2), /* GPP_B */
- INTEL_GPP(GPP_A0, GPP_G0, GPP_G7), /* GPP_G */
- INTEL_GPP(GPP_A0, GPIO_RSVD_3, GPIO_RSVD_11), /* SPI */
+ INTEL_GPP_BASE(GPP_A0, GPP_A0, GPIO_RSVD_0, 0), /* GPP_A */
+ INTEL_GPP_BASE(GPP_A0, GPP_B0, GPIO_RSVD_2, 32), /* GPP_B */
+ INTEL_GPP_BASE(GPP_A0, GPP_G0, GPP_G7, 64), /* GPP_G */
+ INTEL_GPP(GPP_A0, GPIO_RSVD_3, GPIO_RSVD_11), /* SPI */
};
static const struct pad_group cnl_community1_groups[] = {
- INTEL_GPP(GPP_D0, GPP_D0, GPIO_RSVD_12), /* GPP_D */
- INTEL_GPP(GPP_D0, GPP_F0, GPP_F23), /* GPP_F */
- INTEL_GPP(GPP_D0, GPP_H0, GPP_H23), /* GPP_H */
- INTEL_GPP(GPP_D0, GPIO_RSVD_13, GPIO_RSVD_52), /* VGPIO */
+ INTEL_GPP_BASE(GPP_D0, GPP_D0, GPIO_RSVD_12, 96), /* GPP_D */
+ INTEL_GPP_BASE(GPP_D0, GPP_F0, GPP_F23, 128), /* GPP_F */
+ INTEL_GPP_BASE(GPP_D0, GPP_H0, GPP_H23, 160), /* GPP_H */
+ INTEL_GPP_BASE(GPP_D0, GPIO_RSVD_13, GPIO_RSVD_52, 192),/* VGPIO */
};
+/* This community is not visible to the OS */
static const struct pad_group cnl_community2_groups[] = {
- INTEL_GPP(GPD0, GPD0, GPD11), /* GPD */
+ INTEL_GPP(GPD0, GPD0, GPD11), /* GPD */
};
+/* This community is not visible to the OS */
static const struct pad_group cnl_community3_groups[] = {
INTEL_GPP(HDA_BCLK, HDA_BCLK, SSP1_TXD), /* AZA */
INTEL_GPP(HDA_BCLK, GPIO_RSVD_68, GPIO_RSVD_78), /* CPU */
};
static const struct pad_group cnl_community4_groups[] = {
- INTEL_GPP(GPP_C0, GPP_C0, GPP_C23), /* GPP_C */
- INTEL_GPP(GPP_C0, GPP_E0, GPP_E23), /* GPP_E */
- INTEL_GPP(GPP_C0, GPIO_RSVD_53, GPIO_RSVD_61), /* JTAG */
- INTEL_GPP(GPP_C0, GPIO_RSVD_62, GPIO_RSVD_67), /* HVMOS */
+ INTEL_GPP_BASE(GPP_C0, GPP_C0, GPP_C23, 256), /* GPP_C */
+ INTEL_GPP_BASE(GPP_C0, GPP_E0, GPP_E23, 288), /* GPP_E */
+ INTEL_GPP(GPP_C0, GPIO_RSVD_53, GPIO_RSVD_61), /* JTAG */
+ INTEL_GPP(GPP_C0, GPIO_RSVD_62, GPIO_RSVD_67), /* HVMOS */
};
static const struct pad_community cnl_communities[] = {
--
To view, visit https://review.coreboot.org/c/coreboot/+/30133
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I4f1a9e118d7e48f2445ccbb62a12a22e9a832c51
Gerrit-Change-Number: 30133
Gerrit-PatchSet: 1
Gerrit-Owner: Duncan Laurie <dlaurie(a)chromium.org>
Gerrit-MessageType: newchange
Duncan Laurie has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30132
Change subject: vendorcode/google/chromeos: Get ACPI pin from GPIO library
......................................................................
vendorcode/google/chromeos: Get ACPI pin from GPIO library
If the generic GPIO library is enabled the code that generates the
GPIO table in ACPI should attempt to get the GPIO pin value from
the gpio_acpi_pin() function.
BUG=b:120686247
TEST=Tested on Sarien board to ensure that GPIO pin exported by
Chrome OS for the Write Protect signal is correct.
Change-Id: I267694b576009f79bacac6eda5f32bbf51742d78
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
M src/vendorcode/google/chromeos/acpi.c
1 file changed, 6 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/32/30132/1
diff --git a/src/vendorcode/google/chromeos/acpi.c b/src/vendorcode/google/chromeos/acpi.c
index 6605809..a1e0b6e 100644
--- a/src/vendorcode/google/chromeos/acpi.c
+++ b/src/vendorcode/google/chromeos/acpi.c
@@ -14,6 +14,7 @@
*/
#include <arch/acpigen.h>
+#include <gpio.h>
#include "chromeos.h"
void chromeos_acpi_gpio_generate(const struct cros_gpio *gpios, size_t num)
@@ -28,7 +29,11 @@
acpigen_write_package(4);
acpigen_write_integer(gpios[i].type);
acpigen_write_integer(gpios[i].polarity);
- acpigen_write_integer(gpios[i].gpio_num);
+ /* Get ACPI pin from GPIO library if available */
+ if (IS_ENABLED(CONFIG_GENERIC_GPIO_LIB))
+ acpigen_write_integer(gpio_acpi_pin(gpios[i].gpio_num));
+ else
+ acpigen_write_integer(gpios[i].gpio_num);
acpigen_write_string(gpios[i].device);
acpigen_pop_len();
}
--
To view, visit https://review.coreboot.org/c/coreboot/+/30132
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I267694b576009f79bacac6eda5f32bbf51742d78
Gerrit-Change-Number: 30132
Gerrit-PatchSet: 1
Gerrit-Owner: Duncan Laurie <dlaurie(a)chromium.org>
Gerrit-MessageType: newchange
Duncan Laurie has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30131
Change subject: soc/intel/common: Add support for GPIO group pad base
......................................................................
soc/intel/common: Add support for GPIO group pad base
In some situations the GPIO pad numbers used by the OS are not
contiguous and coreboot must provide a way for ACPI to provide
the expected GPIO number to the OS.
To do this each GPIO group can now have a pad base value, which
will be used as the starting pin number for this group and it
is added to the relative pin number of this GPIO to compute the
ACPI pin number for a particular GPIO.
By default this change has no effect because the existing uses
of INTEL_GPP() will set the pad base to PAD_BASE_NONE and the
GPIO number is used as the ACPI pin number without translation.
BUG=b:120686247
TEST=tested on a sarien(cannonlake) board
Change-Id: I25f73df45ffae18c5721a00ca230a6b07c250bab
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
M src/soc/intel/common/block/gpio/gpio.c
M src/soc/intel/common/block/include/intelblocks/gpio.h
2 files changed, 45 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/31/30131/1
diff --git a/src/soc/intel/common/block/gpio/gpio.c b/src/soc/intel/common/block/gpio/gpio.c
index 9b6ca7e..79cc573 100644
--- a/src/soc/intel/common/block/gpio/gpio.c
+++ b/src/soc/intel/common/block/gpio/gpio.c
@@ -397,10 +397,26 @@
uint16_t gpio_acpi_pin(gpio_t gpio_num)
{
- if (!IS_ENABLED(CONFIG_SOC_INTEL_COMMON_BLOCK_GPIO_MULTI_ACPI_DEVICES))
+ const struct pad_community *comm;
+ size_t group, pin;
+
+ if (IS_ENABLED(CONFIG_SOC_INTEL_COMMON_BLOCK_GPIO_MULTI_ACPI_DEVICES))
+ return relative_pad_in_comm(gpio_get_community(gpio_num),
+ gpio_num);
+
+ comm = gpio_get_community(gpio_num);
+ pin = relative_pad_in_comm(comm, gpio_num);
+ group = gpio_group_index(comm, pin);
+
+ /* If pad base is not set then use GPIO number as ACPI pin number. */
+ if (comm->groups[group].pad_base == PAD_BASE_NONE)
return gpio_num;
- return relative_pad_in_comm(gpio_get_community(gpio_num), gpio_num);
+ /*
+ * If this group has a non-zero pad base then compute the ACPI pin
+ * number from the pad base and the relative pad in the group.
+ */
+ return comm->groups[group].pad_base + gpio_within_group(comm, pin);
}
static void print_gpi_status(const struct gpi_status *sts)
diff --git a/src/soc/intel/common/block/include/intelblocks/gpio.h b/src/soc/intel/common/block/include/intelblocks/gpio.h
index 4e26db3..b6112d4 100644
--- a/src/soc/intel/common/block/include/intelblocks/gpio.h
+++ b/src/soc/intel/common/block/include/intelblocks/gpio.h
@@ -23,13 +23,30 @@
#ifndef __ACPI__
#include <types.h>
-#define INTEL_GPP(first_of_community, start_of_group, end_of_group) \
- { \
- .first_pad = (start_of_group) - (first_of_community), \
- .size = (end_of_group) - (start_of_group) + 1, \
+/*
+ * GPIO numbers may not be contiguous and instead will have a different
+ * starting pin number for each pad group.
+ */
+#define INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\
+ group_pad_base) \
+ { \
+ .first_pad = (start_of_group) - (first_of_community), \
+ .size = (end_of_group) - (start_of_group) + 1, \
+ .pad_base = (group_pad_base), \
}
/*
+ * A pad base of -1 indicates that this group uses contiguous numbering
+ * and a pad base should not be used for this group.
+ */
+#define PAD_BASE_NONE -1
+
+/* The common/default group numbering is contiguous */
+#define INTEL_GPP(first_of_community, start_of_group, end_of_group) \
+ INTEL_GPP_BASE(first_of_community, start_of_group, end_of_group,\
+ PAD_BASE_NONE)
+
+/*
* Following should be defined in soc/gpio.h
* GPIO_MISCCFG - offset to GPIO MISCCFG Register
*
@@ -67,6 +84,12 @@
int first_pad; /* offset of first pad of the group relative
to the community */
unsigned int size; /* Size of the group */
+ /*
+ * This is the starting pin number for the pads in this group, if
+ * if the pins are not contiguous across groups. Most groups will
+ * have this set to PAD_BASE_NONE and use contiguous numbering.
+ */
+ int pad_base;
};
/* This structure will be used to describe a community or each group within a
--
To view, visit https://review.coreboot.org/c/coreboot/+/30131
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I25f73df45ffae18c5721a00ca230a6b07c250bab
Gerrit-Change-Number: 30131
Gerrit-PatchSet: 1
Gerrit-Owner: Duncan Laurie <dlaurie(a)chromium.org>
Gerrit-MessageType: newchange