[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