[coreboot-gerrit] Change in ...coreboot[master]: Early eMMC phase 1 - programming bridge
Richard Spiegel (Code Review)
gerrit at coreboot.org
Thu Dec 13 22:30:52 CET 2018
Richard Spiegel has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30215
Change subject: Early eMMC phase 1 - programming bridge
......................................................................
Early eMMC phase 1 - programming bridge
Global objective: Early ready of eMMC by sending "reset all".
This phase objective: Create bridge driver to be used by phase 2.
BUG=b:118680303
TEST=WIP, will test
Change-Id: Iaec1fcc4f8db8c3b4cfd3786d3ff589dc9cb22f5
Signed-off-by: Richard Spiegel <richard.spiegel at silverbackltd.com>
---
A src/drivers/generic/temp_pcie_bridge/Kconfig
A src/drivers/generic/temp_pcie_bridge/Makefile.inc
A src/drivers/generic/temp_pcie_bridge/README
A src/drivers/generic/temp_pcie_bridge/bridge_ram.c
A src/drivers/generic/temp_pcie_bridge/bridge_rom.c
A src/include/device/temp_bridge.h
6 files changed, 302 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/15/30215/1
diff --git a/src/drivers/generic/temp_pcie_bridge/Kconfig b/src/drivers/generic/temp_pcie_bridge/Kconfig
new file mode 100644
index 0000000..f2629e3
--- /dev/null
+++ b/src/drivers/generic/temp_pcie_bridge/Kconfig
@@ -0,0 +1,2 @@
+config DRIVERS_TEMP_BRIDGE
+ bool
diff --git a/src/drivers/generic/temp_pcie_bridge/Makefile.inc b/src/drivers/generic/temp_pcie_bridge/Makefile.inc
new file mode 100644
index 0000000..fcdbf6d
--- /dev/null
+++ b/src/drivers/generic/temp_pcie_bridge/Makefile.inc
@@ -0,0 +1,2 @@
+romstage-$(CONFIG_DRIVERS_TEMP_BRIDGE) += bridge_rom.c
+ramstage-$(CONFIG_DRIVERS_TEMP_BRIDGE) += bridge_ram.c
diff --git a/src/drivers/generic/temp_pcie_bridge/README b/src/drivers/generic/temp_pcie_bridge/README
new file mode 100644
index 0000000..a9bf362
--- /dev/null
+++ b/src/drivers/generic/temp_pcie_bridge/README
@@ -0,0 +1,36 @@
+/*
+ * Documentation for accessing devices behinf a bridge.
+ *
+ * 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.
+ */
+
+Sometimes you need to send commands to a device behind a PCIe bridge still
+at romstage, but bridge is not yet programmed. You need to temporarily program
+the bridge and any base address. Then you send whatever command, and disable
+the bridge, so regular PCI enumeration can do the work without bothering with
+something previous. Finally, some time later, you have to send a second command,
+or maybe read a register, but now PCI was enumerated... so you need to check
+where the base address was placed.
+
+This driver is intended to facilitate these operations by providing 3 functions:
+Program bridge and base address(es)
+Remove base addresses and reset the bridge.
+Find what base address(es) were programmed by PCI enumeration.
+
+For all these functions you need to provide the bridge device:
+<PCI_DEV(0, device, func)> at romstage.
+<dev_find_slot(0, PCI_DEVFN(device, func))> at ramstage.
+The only other parameter, for functions that return base address(es) is actually
+a pointer to a structure which tells what is expected, and place(es) to return
+the address(es).
diff --git a/src/drivers/generic/temp_pcie_bridge/bridge_ram.c b/src/drivers/generic/temp_pcie_bridge/bridge_ram.c
new file mode 100644
index 0000000..659e5af
--- /dev/null
+++ b/src/drivers/generic/temp_pcie_bridge/bridge_ram.c
@@ -0,0 +1,59 @@
+/*
+ * Obtain base addresses of device behind bridge, for ramstage.
+ *
+ * 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 <device/temp_bridge.h>
+#include <device/pci_ops.h>
+
+#define PCIE_BASE CONFIG_MMCONF_BASE_ADDRESS
+#define PADDR(dev, reg) \
+ ((((uint32_t)dev << 12) | ((uint32_t)reg & 0x0fff)) + PCIE_BASE)
+
+static uint32_t pci_read32(uint16_t dev, uint16_t reg)
+{
+ return *(uint32_t *)PADDR(dev, reg);
+}
+
+int get_bases(DEVTREE_CONST struct device *bridge,
+ struct device_addresses *params)
+{
+ uint32_t value;
+ uint16_t dev;
+ uint8_t num;
+ uint8_t byte = pci_read_config8(bridge, PCI_HEADER_TYPE);
+
+ if (byte == 0xff)
+ return TP_BRIDGE_NOT_FOUND;
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return TP_NOT_A_BRIDGE;
+
+ byte = pci_read_config8(bridge, PCI_SECONDARY_BUS);
+ dev = (uint16_t)byte << 8;
+ for (num = 0; num < 6; num++) {
+ value = pci_read32(dev, TEMP_BASE(num));
+ switch (params->used[num]) {
+ case MEMORY_ADDRESS:
+ params->bases[num] = value;
+ break;
+ case IO_ADDRESS:
+ params->bases[num] = value & 0x0000fffe;
+ break;
+ default:
+ break;
+ }
+ }
+ return TP_BRIDGE_SUCCESS;
+}
diff --git a/src/drivers/generic/temp_pcie_bridge/bridge_rom.c b/src/drivers/generic/temp_pcie_bridge/bridge_rom.c
new file mode 100644
index 0000000..5e63b1f
--- /dev/null
+++ b/src/drivers/generic/temp_pcie_bridge/bridge_rom.c
@@ -0,0 +1,150 @@
+/*
+ * Temporary bridge/device programming for device access at romstage.
+ *
+ * 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 <device/temp_bridge.h>
+
+static int set_base(pci_devfn_t dev, uint8_t number, uint8_t use,
+ uint32_t *size, uint32_t start, uint32_t *base)
+{
+ int status = TP_BRIDGE_SUCCESS;
+ uint32_t value;
+ uint8_t command;
+
+ pci_write_config32(dev, TEMP_BASE(number), 0xffffffff);
+ value = pci_read_config32(dev, TEMP_BASE(number));
+ command = pci_read_config8(dev, PCI_COMMAND);
+ if (use == MEMORY_ADDRESS) {
+ if (value & 1)
+ status = TP_DEVICE_INVALID_TYPE;
+ value &= 0xfffffc00; /* At least 1K between addresses */
+ *size = 1 + ~value;
+ value &= start;
+ command |= PCI_COMMAND_MEMORY;
+ } else {
+ if ((value & 1) == 0)
+ status = TP_DEVICE_INVALID_TYPE;
+ value &= 0x0000ffc0; /* At least 64 bytes between addresses */
+ *size = 1 + ~value;
+ value &= start;
+ value |= 1;
+ command |= PCI_COMMAND_IO;
+ }
+ pci_write_config32(dev, TEMP_BASE(number), value);
+ command |= PCI_COMMAND_MASTER;
+ pci_write_config8(dev, PCI_COMMAND, command);
+ return status;
+}
+
+int set_bases(pci_devfn_t bridge, struct device_addresses *params)
+{
+ int ret_stat, status = TP_BRIDGE_SUCCESS;
+ uint32_t return_base, return_size;
+ uint32_t mem_start, next_mem, used_memory;
+ uint16_t io_start, next_io, used_io;
+ uint8_t num;
+ uint8_t byte = pci_read_config8(bridge, PCI_HEADER_TYPE);
+
+ if (byte == 0xff)
+ return TP_BRIDGE_NOT_FOUND;
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return TP_NOT_A_BRIDGE;
+
+ pci_write_config8(bridge, PCI_COMMAND, PCI_COMMAND_MASTER);
+ pci_write_config32(bridge, PCI_PRIMARY_BUS, BRIDGE_BUS_1);
+
+ if (params->memory_range)
+ next_mem = params->memory_range;
+ else
+ next_mem = TP_DEFAULT_MEM_START;
+ mem_start = next_mem;
+ if (params->io_range)
+ next_io = params->io_range;
+ else
+ next_io = TP_DEFAULT_IO_START;
+ io_start = next_io;
+ for (num = 0; num < 6; num++) {
+ return_base = 0;
+ return_size = 0;
+ switch (params->used[num]) {
+ case MEMORY_ADDRESS:
+ ret_stat = set_base(DEVICE_BUS_1, num, MEMORY_ADDRESS,
+ &return_base, next_mem, &return_size);
+ if (ret_stat)
+ status = ret_stat;
+ else {
+ next_mem += (return_base + return_size);
+ params->bases[num] = return_base;
+ }
+ break;
+ case IO_ADDRESS:
+ ret_stat = set_base(DEVICE_BUS_1, num, IO_ADDRESS,
+ &return_base, next_io, &return_size);
+ if (ret_stat)
+ status = ret_stat;
+ else {
+ next_io += (uint16_t)(return_base +
+ return_size);
+ params->bases[num] = return_base;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ used_memory = next_mem - mem_start;
+ used_io = next_io - io_start;
+ byte = pci_read_config8(bridge, PCI_COMMAND);
+ if (used_memory) {
+ /* create base/limit dword */
+ next_mem--;
+ next_mem &= 0xfff00000;
+ next_mem |= 0x0000fff0 & (mem_start >> 16);
+ pci_write_config32(bridge, PCI_MEMORY_BASE, next_mem);
+ byte |= PCI_COMMAND_MEMORY;
+ }
+ if (used_io) {
+ /* create base/limit word */
+ next_io--;
+ next_io &= 0xf000;
+ next_io |= 0x00f0 & (io_start >> 8);
+ pci_write_config16(bridge, PCI_IO_BASE, next_io);
+ byte |= PCI_COMMAND_IO;
+ }
+ pci_write_config8(bridge, PCI_COMMAND, byte);
+ return status;
+}
+
+/* This code assumes the bridge was programmed to have the devi on bus 1 */
+int release_bases(pci_devfn_t bridge)
+{
+ int status = TP_BRIDGE_SUCCESS;
+ uint8_t num;
+ uint8_t byte = pci_read_config8(bridge, PCI_HEADER_TYPE);
+
+ if (byte == 0xff)
+ return TP_BRIDGE_NOT_FOUND;
+ if ((byte & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return TP_NOT_A_BRIDGE;
+
+ for (num = 0; num < 6; num++)
+ pci_write_config32(DEVICE_BUS_1, TEMP_BASE(num), 0);
+ pci_write_config32(DEVICE_BUS_1, PCI_COMMAND, 0);
+ pci_write_config32(bridge, PCI_MEMORY_BASE, 0);
+ pci_write_config16(bridge, PCI_IO_BASE, 0);
+ pci_write_config8(bridge, PCI_COMMAND, 0);
+ return status;
+}
diff --git a/src/include/device/temp_bridge.h b/src/include/device/temp_bridge.h
new file mode 100644
index 0000000..52a19f5
--- /dev/null
+++ b/src/include/device/temp_bridge.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef __DRIVER_TEMP_BRIDGE_H__
+#define __DRIVER_TEMP_BRIDGE_H__
+
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci_def.h>
+
+#define NOT_USED 0
+#define MEMORY_ADDRESS 1
+#define IO_ADDRESS 2
+
+#define TP_BRIDGE_SUCCESS 0
+#define TP_BRIDGE_NOT_FOUND -1
+#define TP_DEVICE_INVALID_TYPE -2
+#define TP_NOT_A_BRIDGE -3
+#define TP_BRIDGE__OTHER -4
+
+#define BRIDGE_BUS_1 0x00010100
+#define DEVICE_BUS_1 PCI_DEV(1, 0, 0)
+
+#define TEMP_BASE(num) ((num * 4) + PCI_BASE_ADDRESS_0)
+#define TP_DEFAULT_MEM_START 0xf4000000
+#define TP_DEFAULT_IO_START 0xa000
+
+struct device_addresses {
+ uint8_t used[6]; /* If used, IO/memory for bases 0-5 */
+ uint16_t io_range; /* start address of range to use */
+ uint32_t memory_range; /* start address of range to use */
+ uint32_t bases[6]; /* return values programmed */
+};
+
+int set_bases(pci_devfn_t bridge, struct device_addresses *params);
+int release_bases(pci_devfn_t bridge);
+int get_bases(DEVTREE_CONST struct device *bridge,
+ struct device_addresses *params);
+#endif
--
To view, visit https://review.coreboot.org/c/coreboot/+/30215
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Iaec1fcc4f8db8c3b4cfd3786d3ff589dc9cb22f5
Gerrit-Change-Number: 30215
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel at silverbackltd.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181213/7d3c3c21/attachment-0001.html>
More information about the coreboot-gerrit
mailing list