[U-Boot] [PATCH 0/7] MIPS Boston Development Board Support

This series introduces initial support for the MIPS Boston, and FPGA based development board & successor to the older Malta board. Further peripheral work is needed but this introduces the basics.
This can be tested in a currently out-of-tree QEMU port if desired, which can be found in the boston branch of:
git://git.linux-mips.org/pub/scm/paul/qemu.git
QEMU can be used to run U-Boot like this:
./configure --target-list=mips64el-softmmu make ./mips64el-softmmu/qemu-system-mips64el -M boston -m 2G \ -bios u-boot.bin -serial stdio
Paul Burton (7): serial: ns16550: Support clocks via phandle dt-bindings: Add interrupt-controller/mips-gic.h header pci: xilinx: Add a driver for Xilinx AXI to PCIe bridge pci: Flip condition for detecting non-PCI parent devices net: pch_gbe: Use dm_pci_map_bar to discover MMIO base net: pch_gbe: Make 64 bit safe boston: Introduce support for the MIPS Boston development board
arch/mips/Kconfig | 16 ++ arch/mips/dts/Makefile | 1 + arch/mips/dts/img,boston.dts | 225 +++++++++++++++++++++ board/imgtec/boston/Kconfig | 16 ++ board/imgtec/boston/MAINTAINERS | 6 + board/imgtec/boston/Makefile | 10 + board/imgtec/boston/boston-lcd.h | 21 ++ board/imgtec/boston/boston-regs.h | 47 +++++ board/imgtec/boston/checkboard.c | 29 +++ board/imgtec/boston/ddr.c | 30 +++ board/imgtec/boston/early_init.c | 61 ++++++ board/imgtec/boston/lowlevel_init.S | 56 +++++ configs/boston_defconfig | 41 ++++ drivers/net/pch_gbe.c | 28 ++- drivers/pci/Kconfig | 7 + drivers/pci/Makefile | 1 + drivers/pci/pci-uclass.c | 2 +- drivers/pci/pcie_xilinx.c | 219 ++++++++++++++++++++ drivers/serial/ns16550.c | 14 +- include/configs/boston.h | 69 +++++++ .../dt-bindings/interrupt-controller/mips-gic.h | 9 + 21 files changed, 889 insertions(+), 19 deletions(-) create mode 100644 arch/mips/dts/img,boston.dts create mode 100644 board/imgtec/boston/Kconfig create mode 100644 board/imgtec/boston/MAINTAINERS create mode 100644 board/imgtec/boston/Makefile create mode 100644 board/imgtec/boston/boston-lcd.h create mode 100644 board/imgtec/boston/boston-regs.h create mode 100644 board/imgtec/boston/checkboard.c create mode 100644 board/imgtec/boston/ddr.c create mode 100644 board/imgtec/boston/early_init.c create mode 100644 board/imgtec/boston/lowlevel_init.S create mode 100644 configs/boston_defconfig create mode 100644 drivers/pci/pcie_xilinx.c create mode 100644 include/configs/boston.h create mode 100644 include/dt-bindings/interrupt-controller/mips-gic.h

Previously ns16550 compatible UARTs probed via device tree have needed their device tree nodes to contain a clock-frequency property. An alternative to this commonly used with Linux is to reference a clock via a phandle. This patch allows U-Boot to support that, retrieving the clock frequency by probing the appropriate clock device.
For example, a system might choose to provide the UART base clock as a reference to a clock common to multiple devices:
sys_clk: clock { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <10000000>; };
uart0: uart@10000000 { compatible = "ns16550a"; reg = <0x10000000 0x1000>; clocks = <&sys_clk>; };
uart1: uart@10000000 { compatible = "ns16550a"; reg = <0x10001000 0x1000>; clocks = <&sys_clk>; };
This removes the need for the frequency information to be duplicated in multiple nodes and allows the device tree to be more descriptive of the system.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
drivers/serial/ns16550.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 88fca15..53032dc 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -5,6 +5,7 @@ */
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> @@ -352,6 +353,8 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) { struct ns16550_platdata *plat = dev->platdata; fdt_addr_t addr; + struct clk clk; + int err;
/* try Processor Local Bus device first */ addr = dev_get_addr(dev); @@ -397,9 +400,14 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) "reg-offset", 0); plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg-shift", 0); - plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "clock-frequency", - CONFIG_SYS_NS16550_CLK); + + err = clk_get_by_index(dev, 0, &clk); + if (!err) + plat->clock = clk_get_rate(&clk); + if (!plat->clock) + plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", + CONFIG_SYS_NS16550_CLK); if (!plat->clock) { debug("ns16550 clock not defined\n"); return -EINVAL;

Hi Paul,
On 26 July 2016 at 16:24, Paul Burton paul.burton@imgtec.com wrote:
Previously ns16550 compatible UARTs probed via device tree have needed their device tree nodes to contain a clock-frequency property. An alternative to this commonly used with Linux is to reference a clock via a phandle. This patch allows U-Boot to support that, retrieving the clock frequency by probing the appropriate clock device.
For example, a system might choose to provide the UART base clock as a reference to a clock common to multiple devices:
sys_clk: clock { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <10000000>; };
uart0: uart@10000000 { compatible = "ns16550a"; reg = <0x10000000 0x1000>; clocks = <&sys_clk>; };
uart1: uart@10000000 { compatible = "ns16550a"; reg = <0x10001000 0x1000>; clocks = <&sys_clk>; };
This removes the need for the frequency information to be duplicated in multiple nodes and allows the device tree to be more descriptive of the system.
Signed-off-by: Paul Burton paul.burton@imgtec.com
drivers/serial/ns16550.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
Looks reasonable - but see below.
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 88fca15..53032dc 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -5,6 +5,7 @@ */
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> @@ -352,6 +353,8 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) { struct ns16550_platdata *plat = dev->platdata; fdt_addr_t addr;
struct clk clk;
int err; /* try Processor Local Bus device first */ addr = dev_get_addr(dev);
@@ -397,9 +400,14 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) "reg-offset", 0); plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg-shift", 0);
plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency",
CONFIG_SYS_NS16550_CLK);
err = clk_get_by_index(dev, 0, &clk);
if (!err)
plat->clock = clk_get_rate(&clk);
I think this should ignore -ENODEV perhaps (no clock device) but not any other error.
if (!plat->clock)
plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency",
CONFIG_SYS_NS16550_CLK); if (!plat->clock) { debug("ns16550 clock not defined\n"); return -EINVAL;
-- 2.9.0
Regards, Simon

Import a copy of the dt-bindings/interrupt-controller/mips-gic.h header from Linux, such that we can use device trees which include it without modification.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
include/dt-bindings/interrupt-controller/mips-gic.h | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 include/dt-bindings/interrupt-controller/mips-gic.h
diff --git a/include/dt-bindings/interrupt-controller/mips-gic.h b/include/dt-bindings/interrupt-controller/mips-gic.h new file mode 100644 index 0000000..cf35a57 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/mips-gic.h @@ -0,0 +1,9 @@ +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H + +#include <dt-bindings/interrupt-controller/irq.h> + +#define GIC_SHARED 0 +#define GIC_LOCAL 1 + +#endif

This patch adds a driver for the Xilinx AXI bridge for PCI express, an IP block which can be used on some generations of Xilinx FPGAs. This is mostly a case of implementing PCIe ECAM specification, but with some quirks about what devices are valid to access.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
drivers/pci/Kconfig | 7 ++ drivers/pci/Makefile | 1 + drivers/pci/pcie_xilinx.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 drivers/pci/pcie_xilinx.c
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0..1f9ea66 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -38,4 +38,11 @@ config PCI_TEGRA with a total of 5 lanes. Some boards require this for Ethernet support to work (e.g. beaver, jetson-tk1).
+config PCI_XILINX + bool "Xilinx AXI Bridge for PCI Express" + depends on DM_PCI + help + Enable support for the Xilinx AXI bridge for PCI express, an IP block + which can be used on some generations of Xilinx FPGAs. + endmenu diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index f8be9bf..9583e91 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o obj-$(CONFIG_WINBOND_83C553) += w83c553f.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o +obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c new file mode 100644 index 0000000..55c3454 --- /dev/null +++ b/drivers/pci/pcie_xilinx.c @@ -0,0 +1,219 @@ +/* + * Xilinx AXI Bridge for PCI Express Driver + * + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> + +#include <asm/io.h> + +/** + * struct xilinx_pcie - Xilinx PCIe controller state + * @hose: The parent classes PCI controller state + * @cfg_base: The base address of memory mapped configuration space + */ +struct xilinx_pcie { + struct pci_controller hose; + void *cfg_base; +}; + +/* Register definitions */ +#define XILINX_PCIE_REG_PSCR 0x144 +#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) + +/** + * pcie_xilinx_link_up() - Check whether the PCIe link is up + * @pcie: Pointer to the PCI controller state + * + * Checks whether the PCIe link for the given device is up or down. + * + * Return: true if the link is up, else false + */ +static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) +{ + uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR); + + return pscr & XILINX_PCIE_REG_PSCR_LNKUP; +} + +/** + * pcie_xilinx_config_address() - Calculate the address of a config access + * @pcie: Pointer to the PCI controller state + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @paddress: Pointer to the pointer to write the calculates address to + * + * Calculates the address that should be accessed to perform a PCIe + * configuration space access for a given device identified by the PCIe + * controller device @pcie and the bus, device & function numbers in @bdf. If + * access to the device is not valid then the function will return an error + * code. Otherwise the address to access will be written to the pointer pointed + * to by @paddress. + * + * Return: 0 on success, else -ERRNO + */ +static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf, + uint offset, void **paddress) +{ + unsigned int bus = PCI_BUS(bdf); + unsigned int dev = PCI_DEV(bdf); + unsigned int func = PCI_FUNC(bdf); + void *addr; + + if ((bus > 0) && !pcie_xilinx_link_up(pcie)) + return -ENODEV; + + /* + * Busses 0 (host-PCIe bridge) & 1 (its immediate child) are + * limited to a single device each. + */ + if ((bus < 2) && (dev > 0)) + return -ENODEV; + + addr = pcie->cfg_base; + addr += bus << 20; + addr += dev << 15; + addr += func << 12; + addr += offset; + *paddress = addr; + + return 0; +} + +/** + * pcie_xilinx_read_config() - Read from configuration space + * @pcie: Pointer to the PCI controller state + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @valuep: A pointer at which to store the read value + * @size: Indicates the size of access to perform + * + * Read a value of size @size from offset @offset within the configuration + * space of the device identified by the bus, device & function numbers in @bdf + * on the PCI bus @bus. + * + * Return: 0 on success, else -ERRNO + */ +static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct xilinx_pcie *pcie = dev_get_priv(bus); + void *address; + int err; + + err = pcie_xilinx_config_address(pcie, bdf, offset, &address); + if (err < 0) { + *valuep = pci_get_ff(size); + return 0; + } + + switch (size) { + case PCI_SIZE_8: + *valuep = __raw_readb(address); + return 0; + case PCI_SIZE_16: + *valuep = __raw_readw(address); + return 0; + case PCI_SIZE_32: + *valuep = __raw_readl(address); + return 0; + default: + return -EINVAL; + } +} + +/** + * pcie_xilinx_write_config() - Write to configuration space + * @pcie: Pointer to the PCI controller state + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @value: The value to write + * @size: Indicates the size of access to perform + * + * Write the value @value of size @size from offset @offset within the + * configuration space of the device identified by the bus, device & function + * numbers in @bdf on the PCI bus @bus. + * + * Return: 0 on success, else -ERRNO + */ +static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct xilinx_pcie *pcie = dev_get_priv(bus); + void *address; + int err; + + err = pcie_xilinx_config_address(pcie, bdf, offset, &address); + if (err < 0) + return 0; + + switch (size) { + case PCI_SIZE_8: + __raw_writeb(value, address); + return 0; + case PCI_SIZE_16: + __raw_writew(value, address); + return 0; + case PCI_SIZE_32: + __raw_writel(value, address); + return 0; + default: + return -EINVAL; + } +} + +/** + * pcie_xilinx_ofdata_to_platdata() - Translate from DT to device state + * @dev: A pointer to the device being operated on + * + * Translate relevant data from the device tree pertaining to device @dev into + * state that the driver will later make use of. This state is stored in the + * device's private data structure. + * + * Return: 0 on success, else -ERRNO + */ +static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev) +{ + struct xilinx_pcie *pcie = dev_get_priv(dev); + struct fdt_resource reg_res; + DECLARE_GLOBAL_DATA_PTR; + int err; + + err = fdt_get_resource(gd->fdt_blob, dev->of_offset, "reg", + 0, ®_res); + if (err < 0) { + error(""reg" resource not found\n"); + return -EINVAL; + } + + pcie->cfg_base = ioremap_nocache(reg_res.start, + fdt_resource_size(®_res)); + + return 0; +} + +static const struct dm_pci_ops pcie_xilinx_ops = { + .read_config = pcie_xilinx_read_config, + .write_config = pcie_xilinx_write_config, +}; + +static const struct udevice_id pcie_xilinx_ids[] = { + { .compatible = "xlnx,axi-pcie-host-1.00.a" }, + { } +}; + +U_BOOT_DRIVER(pcie_xilinx) = { + .name = "pcie_xilinx", + .id = UCLASS_PCI, + .of_match = pcie_xilinx_ids, + .ops = &pcie_xilinx_ops, + .ofdata_to_platdata = pcie_xilinx_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct xilinx_pcie), +};

Hi Paul,
On 26 July 2016 at 16:24, Paul Burton paul.burton@imgtec.com wrote:
This patch adds a driver for the Xilinx AXI bridge for PCI express, an IP block which can be used on some generations of Xilinx FPGAs. This is mostly a case of implementing PCIe ECAM specification, but with some quirks about what devices are valid to access.
Signed-off-by: Paul Burton paul.burton@imgtec.com
drivers/pci/Kconfig | 7 ++ drivers/pci/Makefile | 1 + drivers/pci/pcie_xilinx.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 drivers/pci/pcie_xilinx.c
Reviewed-by: Simon Glass sjg@chromium.org
Nits below.
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0..1f9ea66 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -38,4 +38,11 @@ config PCI_TEGRA with a total of 5 lanes. Some boards require this for Ethernet support to work (e.g. beaver, jetson-tk1).
+config PCI_XILINX
bool "Xilinx AXI Bridge for PCI Express"
depends on DM_PCI
help
Enable support for the Xilinx AXI bridge for PCI express, an IP block
which can be used on some generations of Xilinx FPGAs.
endmenu diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index f8be9bf..9583e91 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o obj-$(CONFIG_WINBOND_83C553) += w83c553f.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o +obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c new file mode 100644 index 0000000..55c3454 --- /dev/null +++ b/drivers/pci/pcie_xilinx.c @@ -0,0 +1,219 @@ +/*
- Xilinx AXI Bridge for PCI Express Driver
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h> +#include <dm.h> +#include <pci.h>
+#include <asm/io.h>
+/**
- struct xilinx_pcie - Xilinx PCIe controller state
- @hose: The parent classes PCI controller state
- @cfg_base: The base address of memory mapped configuration space
- */
+struct xilinx_pcie {
struct pci_controller hose;
void *cfg_base;
+};
+/* Register definitions */ +#define XILINX_PCIE_REG_PSCR 0x144 +#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
+/**
- pcie_xilinx_link_up() - Check whether the PCIe link is up
- @pcie: Pointer to the PCI controller state
- Checks whether the PCIe link for the given device is up or down.
- Return: true if the link is up, else false
- */
+static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) +{
uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR);
return pscr & XILINX_PCIE_REG_PSCR_LNKUP;
+}
+/**
- pcie_xilinx_config_address() - Calculate the address of a config access
- @pcie: Pointer to the PCI controller state
- @bdf: Identifies the PCIe device to access
- @offset: The offset into the device's configuration space
- @paddress: Pointer to the pointer to write the calculates address to
- Calculates the address that should be accessed to perform a PCIe
- configuration space access for a given device identified by the PCIe
- controller device @pcie and the bus, device & function numbers in @bdf. If
- access to the device is not valid then the function will return an error
- code. Otherwise the address to access will be written to the pointer pointed
- to by @paddress.
- Return: 0 on success, else -ERRNO
-EINVAL or something
- */
+static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf,
uint offset, void **paddress)
+{
unsigned int bus = PCI_BUS(bdf);
unsigned int dev = PCI_DEV(bdf);
unsigned int func = PCI_FUNC(bdf);
void *addr;
if ((bus > 0) && !pcie_xilinx_link_up(pcie))
return -ENODEV;
There is a device, so perhaps -EINVAL would be better?
/*
* Busses 0 (host-PCIe bridge) & 1 (its immediate child) are
* limited to a single device each.
*/
if ((bus < 2) && (dev > 0))
return -ENODEV;
Same here.
addr = pcie->cfg_base;
addr += bus << 20;
addr += dev << 15;
addr += func << 12;
addr += offset;
*paddress = addr;
return 0;
+}
+/**
- pcie_xilinx_read_config() - Read from configuration space
- @pcie: Pointer to the PCI controller state
- @bdf: Identifies the PCIe device to access
- @offset: The offset into the device's configuration space
- @valuep: A pointer at which to store the read value
- @size: Indicates the size of access to perform
- Read a value of size @size from offset @offset within the configuration
- space of the device identified by the bus, device & function numbers in @bdf
- on the PCI bus @bus.
- Return: 0 on success, else -ERRNO
- */
+static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
+{
struct xilinx_pcie *pcie = dev_get_priv(bus);
void *address;
int err;
err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
if (err < 0) {
*valuep = pci_get_ff(size);
return 0;
}
switch (size) {
case PCI_SIZE_8:
*valuep = __raw_readb(address);
return 0;
case PCI_SIZE_16:
*valuep = __raw_readw(address);
return 0;
case PCI_SIZE_32:
*valuep = __raw_readl(address);
return 0;
default:
return -EINVAL;
}
+}
+/**
- pcie_xilinx_write_config() - Write to configuration space
- @pcie: Pointer to the PCI controller state
- @bdf: Identifies the PCIe device to access
- @offset: The offset into the device's configuration space
- @value: The value to write
- @size: Indicates the size of access to perform
- Write the value @value of size @size from offset @offset within the
- configuration space of the device identified by the bus, device & function
- numbers in @bdf on the PCI bus @bus.
- Return: 0 on success, else -ERRNO
- */
+static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
+{
struct xilinx_pcie *pcie = dev_get_priv(bus);
void *address;
int err;
err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
if (err < 0)
return 0;
Why squash the error?
switch (size) {
case PCI_SIZE_8:
__raw_writeb(value, address);
return 0;
case PCI_SIZE_16:
__raw_writew(value, address);
return 0;
case PCI_SIZE_32:
__raw_writel(value, address);
return 0;
default:
return -EINVAL;
}
+}
+/**
- pcie_xilinx_ofdata_to_platdata() - Translate from DT to device state
- @dev: A pointer to the device being operated on
- Translate relevant data from the device tree pertaining to device @dev into
- state that the driver will later make use of. This state is stored in the
- device's private data structure.
- Return: 0 on success, else -ERRNO
- */
+static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev) +{
struct xilinx_pcie *pcie = dev_get_priv(dev);
struct fdt_resource reg_res;
DECLARE_GLOBAL_DATA_PTR;
int err;
err = fdt_get_resource(gd->fdt_blob, dev->of_offset, "reg",
0, ®_res);
if (err < 0) {
error("\"reg\" resource not found\n");
return -EINVAL;
return ret?
}
pcie->cfg_base = ioremap_nocache(reg_res.start,
fdt_resource_size(®_res));
return 0;
+}
+static const struct dm_pci_ops pcie_xilinx_ops = {
.read_config = pcie_xilinx_read_config,
.write_config = pcie_xilinx_write_config,
+};
+static const struct udevice_id pcie_xilinx_ids[] = {
{ .compatible = "xlnx,axi-pcie-host-1.00.a" },
{ }
+};
+U_BOOT_DRIVER(pcie_xilinx) = {
.name = "pcie_xilinx",
.id = UCLASS_PCI,
.of_match = pcie_xilinx_ids,
.ops = &pcie_xilinx_ops,
.ofdata_to_platdata = pcie_xilinx_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct xilinx_pcie),
+};
2.9.0
Regards, Simon

On 27/07/16 00:43, Simon Glass wrote:
Hi Paul,
On 26 July 2016 at 16:24, Paul Burton paul.burton@imgtec.com wrote:
This patch adds a driver for the Xilinx AXI bridge for PCI express, an IP block which can be used on some generations of Xilinx FPGAs. This is mostly a case of implementing PCIe ECAM specification, but with some quirks about what devices are valid to access.
Signed-off-by: Paul Burton paul.burton@imgtec.com
drivers/pci/Kconfig | 7 ++ drivers/pci/Makefile | 1 + drivers/pci/pcie_xilinx.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 drivers/pci/pcie_xilinx.c
Reviewed-by: Simon Glass sjg@chromium.org
Hi Simon,
Thanks :)
Nits below.
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0..1f9ea66 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -38,4 +38,11 @@ config PCI_TEGRA with a total of 5 lanes. Some boards require this for Ethernet support to work (e.g. beaver, jetson-tk1).
+config PCI_XILINX
bool "Xilinx AXI Bridge for PCI Express"
depends on DM_PCI
help
Enable support for the Xilinx AXI bridge for PCI express, an IP block
which can be used on some generations of Xilinx FPGAs.
endmenu diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index f8be9bf..9583e91 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o obj-$(CONFIG_WINBOND_83C553) += w83c553f.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o +obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c new file mode 100644 index 0000000..55c3454 --- /dev/null +++ b/drivers/pci/pcie_xilinx.c @@ -0,0 +1,219 @@ +/*
- Xilinx AXI Bridge for PCI Express Driver
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h> +#include <dm.h> +#include <pci.h>
+#include <asm/io.h>
+/**
- struct xilinx_pcie - Xilinx PCIe controller state
- @hose: The parent classes PCI controller state
- @cfg_base: The base address of memory mapped configuration space
- */
+struct xilinx_pcie {
struct pci_controller hose;
void *cfg_base;
+};
+/* Register definitions */ +#define XILINX_PCIE_REG_PSCR 0x144 +#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
+/**
- pcie_xilinx_link_up() - Check whether the PCIe link is up
- @pcie: Pointer to the PCI controller state
- Checks whether the PCIe link for the given device is up or down.
- Return: true if the link is up, else false
- */
+static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) +{
uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR);
return pscr & XILINX_PCIE_REG_PSCR_LNKUP;
+}
+/**
- pcie_xilinx_config_address() - Calculate the address of a config access
- @pcie: Pointer to the PCI controller state
- @bdf: Identifies the PCIe device to access
- @offset: The offset into the device's configuration space
- @paddress: Pointer to the pointer to write the calculates address to
- Calculates the address that should be accessed to perform a PCIe
- configuration space access for a given device identified by the PCIe
- controller device @pcie and the bus, device & function numbers in @bdf. If
- access to the device is not valid then the function will return an error
- code. Otherwise the address to access will be written to the pointer pointed
- to by @paddress.
- Return: 0 on success, else -ERRNO
-EINVAL or something
I'll make it -ENODEV as that's the only error returned.
- */
+static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf,
uint offset, void **paddress)
+{
unsigned int bus = PCI_BUS(bdf);
unsigned int dev = PCI_DEV(bdf);
unsigned int func = PCI_FUNC(bdf);
void *addr;
if ((bus > 0) && !pcie_xilinx_link_up(pcie))
return -ENODEV;
There is a device, so perhaps -EINVAL would be better?
It depends what device we're talking about. There's a PCIE controller, but there's no device accessible at the address encoded by bdf, and that's what I'm trying to communicate back to the caller here.
/*
* Busses 0 (host-PCIe bridge) & 1 (its immediate child) are
* limited to a single device each.
*/
if ((bus < 2) && (dev > 0))
return -ENODEV;
Same here.
Likewise.
addr = pcie->cfg_base;
addr += bus << 20;
addr += dev << 15;
addr += func << 12;
addr += offset;
*paddress = addr;
return 0;
+}
+/**
- pcie_xilinx_read_config() - Read from configuration space
- @pcie: Pointer to the PCI controller state
- @bdf: Identifies the PCIe device to access
- @offset: The offset into the device's configuration space
- @valuep: A pointer at which to store the read value
- @size: Indicates the size of access to perform
- Read a value of size @size from offset @offset within the configuration
- space of the device identified by the bus, device & function numbers in @bdf
- on the PCI bus @bus.
- Return: 0 on success, else -ERRNO
- */
+static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
+{
struct xilinx_pcie *pcie = dev_get_priv(bus);
void *address;
int err;
err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
if (err < 0) {
*valuep = pci_get_ff(size);
return 0;
}
switch (size) {
case PCI_SIZE_8:
*valuep = __raw_readb(address);
return 0;
case PCI_SIZE_16:
*valuep = __raw_readw(address);
return 0;
case PCI_SIZE_32:
*valuep = __raw_readl(address);
return 0;
default:
return -EINVAL;
}
+}
+/**
- pcie_xilinx_write_config() - Write to configuration space
- @pcie: Pointer to the PCI controller state
- @bdf: Identifies the PCIe device to access
- @offset: The offset into the device's configuration space
- @value: The value to write
- @size: Indicates the size of access to perform
- Write the value @value of size @size from offset @offset within the
- configuration space of the device identified by the bus, device & function
- numbers in @bdf on the PCI bus @bus.
- Return: 0 on success, else -ERRNO
- */
+static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
+{
struct xilinx_pcie *pcie = dev_get_priv(bus);
void *address;
int err;
err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
if (err < 0)
return 0;
Why squash the error?
The pci_bind_bus_devices function in pci-uclass.c expects to be able to loop through each possible PCI device & attempt a read from it, regardless of whether that device actually exists.
pcie_xilinx_config_address return -ENODEV where it knows that a device is not allowed to exist or be accessed due to limitations of the PCIE controller, and if we propogate that up to pci_bind_bus_devices then it gets unhappy & fails with a "Cannot read bus configuration: -19" message. As far as I can tell U-Boot expects accesses to non-existant devices to "succeed" and for reads to just return all-Fs, which is what happens here.
switch (size) {
case PCI_SIZE_8:
__raw_writeb(value, address);
return 0;
case PCI_SIZE_16:
__raw_writew(value, address);
return 0;
case PCI_SIZE_32:
__raw_writel(value, address);
return 0;
default:
return -EINVAL;
}
+}
+/**
- pcie_xilinx_ofdata_to_platdata() - Translate from DT to device state
- @dev: A pointer to the device being operated on
- Translate relevant data from the device tree pertaining to device @dev into
- state that the driver will later make use of. This state is stored in the
- device's private data structure.
- Return: 0 on success, else -ERRNO
- */
+static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev) +{
struct xilinx_pcie *pcie = dev_get_priv(dev);
struct fdt_resource reg_res;
DECLARE_GLOBAL_DATA_PTR;
int err;
err = fdt_get_resource(gd->fdt_blob, dev->of_offset, "reg",
0, ®_res);
if (err < 0) {
error("\"reg\" resource not found\n");
return -EINVAL;
return ret?
Yup, thanks.
Paul
}
pcie->cfg_base = ioremap_nocache(reg_res.start,
fdt_resource_size(®_res));
return 0;
+}
+static const struct dm_pci_ops pcie_xilinx_ops = {
.read_config = pcie_xilinx_read_config,
.write_config = pcie_xilinx_write_config,
+};
+static const struct udevice_id pcie_xilinx_ids[] = {
{ .compatible = "xlnx,axi-pcie-host-1.00.a" },
{ }
+};
+U_BOOT_DRIVER(pcie_xilinx) = {
.name = "pcie_xilinx",
.id = UCLASS_PCI,
.of_match = pcie_xilinx_ids,
.ops = &pcie_xilinx_ops,
.ofdata_to_platdata = pcie_xilinx_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct xilinx_pcie),
+};
2.9.0
Regards, Simon

In pci_uclass_pre_probe an attempt is made to detect whether the parent of a device is a PCI device and that the device is thus a bridge. This was being done by checking whether the parent of the device is of the UCLASS_ROOT class. This causes problems if the PCI controller is a child of some other non-PCI node, for example a simple-bus node.
For example, if the device tree contains something like the following then pci_uclass_pre_probe would incorrectly believe that the PCI controller is a bridge, with a PCI parent:
/ { some_child { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <>;
pci_controller: pci@10000000 { compatible = "my-pci-controller"; device_type = "pci"; reg = <0x10000000 0x2000000>; }; }; };
Avoid this incorrect detection of bridges by instead checking whether the parent devices class is UCLASS_PCI and treating a device as a bridge when this is true.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
drivers/pci/pci-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 32590ce..ca277f3 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -859,7 +859,7 @@ static int pci_uclass_pre_probe(struct udevice *bus) hose = bus->uclass_priv;
/* For bridges, use the top-level PCI controller */ - if (device_get_uclass_id(bus->parent) == UCLASS_ROOT) { + if (device_get_uclass_id(bus->parent) != UCLASS_PCI) { hose->ctlr = bus; ret = decode_regions(hose, gd->fdt_blob, bus->parent->of_offset, bus->of_offset);

On 26 July 2016 at 16:24, Paul Burton paul.burton@imgtec.com wrote:
In pci_uclass_pre_probe an attempt is made to detect whether the parent of a device is a PCI device and that the device is thus a bridge. This was being done by checking whether the parent of the device is of the UCLASS_ROOT class. This causes problems if the PCI controller is a child of some other non-PCI node, for example a simple-bus node.
For example, if the device tree contains something like the following then pci_uclass_pre_probe would incorrectly believe that the PCI controller is a bridge, with a PCI parent:
/ { some_child { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <>;
pci_controller: pci@10000000 { compatible = "my-pci-controller"; device_type = "pci"; reg = <0x10000000 0x2000000>; }; };
};
Avoid this incorrect detection of bridges by instead checking whether the parent devices class is UCLASS_PCI and treating a device as a bridge when this is true.
Signed-off-by: Paul Burton paul.burton@imgtec.com
drivers/pci/pci-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

Reading the PCI BAR & converting the result to a physical address is not safe across all architectures. For example on MIPS the virtual:physical mapping is not 1:1, so we cannot directly make use of the physical address.
Use the more generic BAR-mapping function dm_pci_map_bar to discover the MMIO base address, which should work across architectures.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
drivers/net/pch_gbe.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c index 137818b..2d0a700 100644 --- a/drivers/net/pch_gbe.c +++ b/drivers/net/pch_gbe.c @@ -421,7 +421,7 @@ int pch_gbe_probe(struct udevice *dev) { struct pch_gbe_priv *priv; struct eth_pdata *plat = dev_get_platdata(dev); - u32 iobase; + void *iobase;
/* * The priv structure contains the descriptors and frame buffers which @@ -432,11 +432,9 @@ int pch_gbe_probe(struct udevice *dev)
priv->dev = dev;
- dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase); - iobase &= PCI_BASE_ADDRESS_MEM_MASK; - iobase = dm_pci_mem_to_phys(dev, iobase); + iobase = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_1, PCI_REGION_MEM);
- plat->iobase = iobase; + plat->iobase = (ulong)iobase; priv->mac_regs = (struct pch_gbe_regs *)iobase;
/* Read MAC address from SROM and initialize dev->enetaddr with it */

The pch_gbe driver previously casted pointers to & from unsigned 32 bit integers in many locations. This breaks the driver on 64 bit systems, producing streams of compiler warnings about mismatched pointer & integer sizes and then failing to keep track of addresses correctly at runtime.
Fix the driver for 64 bit systems by using unsigned longs in place of the previously used 32 bit integers.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
drivers/net/pch_gbe.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c index 2d0a700..d40fff0 100644 --- a/drivers/net/pch_gbe.c +++ b/drivers/net/pch_gbe.c @@ -118,14 +118,14 @@ static void pch_gbe_rx_descs_init(struct udevice *dev) memset(rx_desc, 0, sizeof(struct pch_gbe_rx_desc) * PCH_GBE_DESC_NUM); for (i = 0; i < PCH_GBE_DESC_NUM; i++) rx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, - (u32)(priv->rx_buff[i])); + (ulong)(priv->rx_buff[i]));
- writel(dm_pci_phys_to_mem(priv->dev, (u32)rx_desc), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)rx_desc), &mac_regs->rx_dsc_base); writel(sizeof(struct pch_gbe_rx_desc) * (PCH_GBE_DESC_NUM - 1), &mac_regs->rx_dsc_size);
- writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_desc + 1)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(rx_desc + 1)), &mac_regs->rx_dsc_sw_p); }
@@ -137,11 +137,11 @@ static void pch_gbe_tx_descs_init(struct udevice *dev)
memset(tx_desc, 0, sizeof(struct pch_gbe_tx_desc) * PCH_GBE_DESC_NUM);
- writel(dm_pci_phys_to_mem(priv->dev, (u32)tx_desc), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)tx_desc), &mac_regs->tx_dsc_base); writel(sizeof(struct pch_gbe_tx_desc) * (PCH_GBE_DESC_NUM - 1), &mac_regs->tx_dsc_size); - writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_desc + 1)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(tx_desc + 1)), &mac_regs->tx_dsc_sw_p); }
@@ -251,7 +251,7 @@ static int pch_gbe_send(struct udevice *dev, void *packet, int length) if (length < 64) frame_ctrl |= PCH_GBE_TXD_CTRL_APAD;
- tx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (u32)packet); + tx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (ulong)packet); tx_desc->length = length; tx_desc->tx_words_eob = length + 3; tx_desc->tx_frame_ctrl = frame_ctrl; @@ -262,7 +262,7 @@ static int pch_gbe_send(struct udevice *dev, void *packet, int length) if (++priv->tx_idx >= PCH_GBE_DESC_NUM) priv->tx_idx = 0;
- writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_head + priv->tx_idx)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(tx_head + priv->tx_idx)), &mac_regs->tx_dsc_sw_p);
start = get_timer(0); @@ -283,7 +283,7 @@ static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp) struct pch_gbe_priv *priv = dev_get_priv(dev); struct pch_gbe_regs *mac_regs = priv->mac_regs; struct pch_gbe_rx_desc *rx_desc; - u32 hw_desc, buffer_addr, length; + ulong hw_desc, buffer_addr, length;
rx_desc = &priv->rx_desc[priv->rx_idx];
@@ -291,7 +291,7 @@ static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp) hw_desc = readl(&mac_regs->rx_dsc_hw_p_hld);
/* Just return if not receiving any packet */ - if ((u32)rx_desc == hw_desc) + if ((ulong)rx_desc == hw_desc) return -EAGAIN;
buffer_addr = dm_pci_mem_to_phys(priv->dev, rx_desc->buffer_addr); @@ -315,7 +315,7 @@ static int pch_gbe_free_pkt(struct udevice *dev, uchar *packet, int length) if (++rx_swp >= PCH_GBE_DESC_NUM) rx_swp = 0;
- writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_head + rx_swp)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(rx_head + rx_swp)), &mac_regs->rx_dsc_sw_p);
return 0;

This patch introduces support for building U-Boot to run on the MIPS Boston development board. This is a board built around an FPGA & an Intel EG20T Platform Controller Hub, used largely as part of the development of new CPUs and their software support. It is essentially the successor to the older MIPS Malta board.
Signed-off-by: Paul Burton paul.burton@imgtec.com
---
arch/mips/Kconfig | 16 +++ arch/mips/dts/Makefile | 1 + arch/mips/dts/img,boston.dts | 225 ++++++++++++++++++++++++++++++++++++ board/imgtec/boston/Kconfig | 16 +++ board/imgtec/boston/MAINTAINERS | 6 + board/imgtec/boston/Makefile | 10 ++ board/imgtec/boston/boston-lcd.h | 21 ++++ board/imgtec/boston/boston-regs.h | 47 ++++++++ board/imgtec/boston/checkboard.c | 29 +++++ board/imgtec/boston/ddr.c | 30 +++++ board/imgtec/boston/early_init.c | 61 ++++++++++ board/imgtec/boston/lowlevel_init.S | 56 +++++++++ configs/boston_defconfig | 41 +++++++ include/configs/boston.h | 69 +++++++++++ 14 files changed, 628 insertions(+) create mode 100644 arch/mips/dts/img,boston.dts create mode 100644 board/imgtec/boston/Kconfig create mode 100644 board/imgtec/boston/MAINTAINERS create mode 100644 board/imgtec/boston/Makefile create mode 100644 board/imgtec/boston/boston-lcd.h create mode 100644 board/imgtec/boston/boston-regs.h create mode 100644 board/imgtec/boston/checkboard.c create mode 100644 board/imgtec/boston/ddr.c create mode 100644 board/imgtec/boston/early_init.c create mode 100644 board/imgtec/boston/lowlevel_init.S create mode 100644 configs/boston_defconfig create mode 100644 include/configs/boston.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 21066f0..7ba0ef2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -73,9 +73,25 @@ config MACH_PIC32 select OF_CONTROL select DM
+config TARGET_BOSTON + bool "Support Boston" + select DM + select DM_SERIAL + select OF_CONTROL + select MIPS_L1_CACHE_SHIFT_6 + select SUPPORTS_BIG_ENDIAN + select SUPPORTS_LITTLE_ENDIAN + select SUPPORTS_CPU_MIPS32_R1 + select SUPPORTS_CPU_MIPS32_R2 + select SUPPORTS_CPU_MIPS32_R6 + select SUPPORTS_CPU_MIPS64_R1 + select SUPPORTS_CPU_MIPS64_R2 + select SUPPORTS_CPU_MIPS64_R6 + endchoice
source "board/dbau1x00/Kconfig" +source "board/imgtec/boston/Kconfig" source "board/imgtec/malta/Kconfig" source "board/micronas/vct/Kconfig" source "board/pb1x00/Kconfig" diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index 2f04d73..6a5e43e 100644 --- a/arch/mips/dts/Makefile +++ b/arch/mips/dts/Makefile @@ -4,6 +4,7 @@
dtb-$(CONFIG_TARGET_AP121) += ap121.dtb dtb-$(CONFIG_TARGET_AP143) += ap143.dtb +dtb-$(CONFIG_TARGET_BOSTON) += img,boston.dtb dtb-$(CONFIG_TARGET_MALTA) += mti,malta.dtb dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb diff --git a/arch/mips/dts/img,boston.dts b/arch/mips/dts/img,boston.dts new file mode 100644 index 0000000..e4e0f28 --- /dev/null +++ b/arch/mips/dts/img,boston.dts @@ -0,0 +1,225 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/mips-gic.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "img,boston"; + + chosen { + stdout-path = &uart0; + }; + + aliases { + clk_sys = &clk_sys; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "img,mips"; + reg = <0>; + clocks = <&clk_sys>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + clk_sys: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <10000000>; + u-boot,dm-pre-reloc; + }; + + axi4 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <>; + + gic: interrupt-controller { + compatible = "mti,gic"; + + interrupt-controller; + #interrupt-cells = <3>; + + timer { + compatible = "mti,gic-timer"; + interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>; + clocks = <&clk_sys>; + }; + }; + + plat_regs: system-controller@17ffd000 { + compatible = "img,boston-platform-regs", "syscon"; + reg = <0x17ffd000 0x1000>; + }; + + reboot: syscon-reboot { + compatible = "syscon-reboot"; + regmap = <&plat_regs>; + offset = <0x10>; + mask = <0x10>; + }; + + uart0: uart@17ffe000 { + compatible = "ns16550a"; + reg = <0x17ffe000 0x1000>; + reg-shift = <2>; + reg-io-width = <4>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&clk_sys>; + + u-boot,dm-pre-reloc; + }; + + lcd: lcd@17fff000 { + compatible = "img,boston-lcd"; + reg = <0x17fff000 0x8>; + }; + + pci0: pci@10000000 { + status = "disabled"; + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x10000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>; + + ranges = <0x02000000 0 0x40000000 + 0x40000000 0 0x40000000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci0_intc 0>, + <0 0 0 2 &pci0_intc 1>, + <0 0 0 3 &pci0_intc 2>, + <0 0 0 4 &pci0_intc 3>; + + pci0_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pci1: pci@12000000 { + status = "disabled"; + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x12000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 1 IRQ_TYPE_LEVEL_HIGH>; + + ranges = <0x02000000 0 0x20000000 + 0x20000000 0 0x20000000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci1_intc 0>, + <0 0 0 2 &pci1_intc 1>, + <0 0 0 3 &pci1_intc 2>, + <0 0 0 4 &pci1_intc 3>; + + pci1_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pci2: pci@14000000 { + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x14000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 0 IRQ_TYPE_LEVEL_HIGH>; + + ranges = <0x02000000 0 0x16000000 + 0x16000000 0 0x100000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci2_intc 0>, + <0 0 0 2 &pci2_intc 1>, + <0 0 0 3 &pci2_intc 2>, + <0 0 0 4 &pci2_intc 3>; + + pci2_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + pci2_root@0,0,0 { + compatible = "pci10ee,7021"; + reg = <0x00000000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + eg20t_bridge@1,0,0 { + compatible = "pci8086,8800"; + reg = <0x00010000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + eg20t_mac@2,0,1 { + compatible = "pci8086,8802"; + reg = <0x00020100 0 0 0 0>; + phy-reset-gpios = <&eg20t_gpio 6 GPIO_ACTIVE_LOW>; + }; + + eg20t_gpio: eg20t_gpio@2,0,2 { + compatible = "pci8086,8803"; + reg = <0x00020200 0 0 0 0>; + + gpio-controller; + #gpio-cells = <2>; + }; + + eg20t_i2c@2,12,2 { + compatible = "pci8086,8817"; + reg = <0x00026200 0 0 0 0>; + + #address-cells = <1>; + #size-cells = <0>; + + rtc@0x68 { + compatible = "st,m41t81s"; + reg = <0x68>; + }; + }; + }; + }; + }; + }; +}; diff --git a/board/imgtec/boston/Kconfig b/board/imgtec/boston/Kconfig new file mode 100644 index 0000000..ab76a3c --- /dev/null +++ b/board/imgtec/boston/Kconfig @@ -0,0 +1,16 @@ +if TARGET_BOSTON + +config SYS_BOARD + default "boston" + +config SYS_VENDOR + default "imgtec" + +config SYS_CONFIG_NAME + default "boston" + +config SYS_TEXT_BASE + default 0x9fc00000 if 32BIT + default 0xffffffff9fc00000 if 64BIT + +endif diff --git a/board/imgtec/boston/MAINTAINERS b/board/imgtec/boston/MAINTAINERS new file mode 100644 index 0000000..30dd481 --- /dev/null +++ b/board/imgtec/boston/MAINTAINERS @@ -0,0 +1,6 @@ +BOSTON BOARD +M: Paul Burton paul.burton@imgtec.com +S: Maintained +F: board/imgtec/boston/ +F: include/configs/boston.h +F: configs/boston_defconfig diff --git a/board/imgtec/boston/Makefile b/board/imgtec/boston/Makefile new file mode 100644 index 0000000..b7125b5 --- /dev/null +++ b/board/imgtec/boston/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (C) 2016 Imagination Technologies +# +# SPDX-License-Identifier: GPL-2.0 +# + +obj-y += checkboard.o +obj-y += ddr.o +obj-y += early_init.o +obj-y += lowlevel_init.o diff --git a/board/imgtec/boston/boston-lcd.h b/board/imgtec/boston/boston-lcd.h new file mode 100644 index 0000000..9f5c1b9 --- /dev/null +++ b/board/imgtec/boston/boston-lcd.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __BOARD_BOSTON_LCD_H__ +#define __BOARD_BOSTON_LCD_H__ + +/** + * lowlevel_display() - Display a message on Boston's LCD + * @msg: The string to display + * + * Display the string @msg on the 7 character LCD display of the Boston board. + * This is typically used for debug or to present some form of status + * indication to the user, allowing faults to be identified when things go + * wrong early enough that the UART isn't up. + */ +void lowlevel_display(const char msg[static 8]); + +#endif /* __BOARD_BOSTON_LCD_H__ */ diff --git a/board/imgtec/boston/boston-regs.h b/board/imgtec/boston/boston-regs.h new file mode 100644 index 0000000..c33535e --- /dev/null +++ b/board/imgtec/boston/boston-regs.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __BOARD_BOSTON_REGS_H__ +#define __BOARD_BOSTON_REGS_H__ + +#define BOSTON_PLAT_BASE 0x17ffd000 +#define BOSTON_LCD_BASE 0x17fff000 + +/* + * Platform Register Definitions + */ +#define BOSTON_PLAT_CORE_CL 0x04 + +#define BOSTON_PLAT_DDR3STAT 0x14 +# define BOSTON_PLAT_DDR3STAT_CALIB (1 << 2) + +#define BOSTON_PLAT_MMCMDIV 0x30 +# define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0) +# define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8) +# define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16) +# define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24) + +#define BOSTON_PLAT_DDRCONF0 0x38 +# define BOSTON_PLAT_DDRCONF0_SIZE (0xf << 0) + +#ifndef __ASSEMBLY__ + +#include <asm/io.h> + +#define BUILD_PLAT_ACCESSORS(offset, name) \ +static inline uint32_t read_boston_##name(void) \ +{ \ + uint32_t *reg = (void *)CKSEG1ADDR(BOSTON_PLAT_BASE) + (offset);\ + return __raw_readl(reg); \ +} + +BUILD_PLAT_ACCESSORS(BOSTON_PLAT_CORE_CL, core_cl) +BUILD_PLAT_ACCESSORS(BOSTON_PLAT_MMCMDIV, mmcmdiv) +BUILD_PLAT_ACCESSORS(BOSTON_PLAT_DDRCONF0, ddrconf0) + +#endif /* !__ASSEMBLY__ */ + +#endif /* __BOARD_BOSTON_REGS_H__ */ diff --git a/board/imgtec/boston/checkboard.c b/board/imgtec/boston/checkboard.c new file mode 100644 index 0000000..417ac4e --- /dev/null +++ b/board/imgtec/boston/checkboard.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> + +#include <asm/mipsregs.h> + +#include "boston-lcd.h" +#include "boston-regs.h" + +int checkboard(void) +{ + u32 changelist; + + lowlevel_display("U-boot "); + + printf("Board: MIPS Boston\n"); + + printf("CPU: 0x%08x", read_c0_prid()); + changelist = read_boston_core_cl(); + if (changelist > 1) + printf(" cl%x", changelist); + putc('\n'); + + return 0; +} diff --git a/board/imgtec/boston/ddr.c b/board/imgtec/boston/ddr.c new file mode 100644 index 0000000..7caed4b --- /dev/null +++ b/board/imgtec/boston/ddr.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> + +#include <asm/addrspace.h> + +#include "boston-regs.h" + +phys_size_t initdram(int board_type) +{ + u32 ddrconf0 = read_boston_ddrconf0(); + + return (phys_size_t)(ddrconf0 & BOSTON_PLAT_DDRCONF0_SIZE) << 30; +} + +ulong board_get_usable_ram_top(ulong total_size) +{ + DECLARE_GLOBAL_DATA_PTR; + + if (gd->ram_top < CONFIG_SYS_SDRAM_BASE) { + /* 2GB wrapped around to 0 */ + return CKSEG0ADDR(256 << 20); + } + + return min_t(unsigned long, gd->ram_top, CKSEG0ADDR(256 << 20)); +} diff --git a/board/imgtec/boston/early_init.c b/board/imgtec/boston/early_init.c new file mode 100644 index 0000000..eac56d6 --- /dev/null +++ b/board/imgtec/boston/early_init.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <libfdt.h> + +#include "boston-regs.h" + +/** + * fixup_dt_clock() - Fixup the system clock frequency in the DT + * @fdt: Pointer to the Flattened Device Tree + * + * Calculate the system clock frequency from the Boston platform registers and + * update the clocks representation in the FDT to report the correct frequency. + */ +static void fixup_dt_clock(void *fdt) +{ + uint32_t mmcmdiv = read_boston_mmcmdiv(); + uint32_t in_rate, mul, clk0_div, clk0_rate; + const char *clk_path; + int clk_off, err; + + clk_path = fdt_get_alias(fdt, "clk_sys"); + if (!clk_path) { + printf("%s: failed to find clk_sys path\n", __func__); + return; + } + + clk_off = fdt_path_offset(fdt, clk_path); + if (clk_off < 0) { + printf("%s: failed to find clk_sys offset\n", __func__); + return; + } + +#define EXT(field) ((mmcmdiv & field) >> (ffs(field) - 1)) + + in_rate = EXT(BOSTON_PLAT_MMCMDIV_INPUT); + mul = EXT(BOSTON_PLAT_MMCMDIV_MUL); + clk0_div = EXT(BOSTON_PLAT_MMCMDIV_CLK0DIV); + +#undef EXT + + clk0_rate = (in_rate * mul * 1000000) / clk0_div; + + err = fdt_setprop_inplace_u32(fdt, clk_off, "clock-frequency", + clk0_rate); + if (err) + printf("%s: failed to set clock-frequency\n", __func__); +} + +int board_early_init_f(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + fixup_dt_clock((void *)gd->fdt_blob); + + return 0; +} diff --git a/board/imgtec/boston/lowlevel_init.S b/board/imgtec/boston/lowlevel_init.S new file mode 100644 index 0000000..b77e9b2 --- /dev/null +++ b/board/imgtec/boston/lowlevel_init.S @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <config.h> + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> + +#include "boston-regs.h" + +.data + +msg_ddr_cal: .ascii "DDR Cal " +msg_ddr_ok: .ascii "DDR OK " + +.text + +LEAF(lowlevel_init) + move s0, ra + + PTR_LA a0, msg_ddr_cal + bal lowlevel_display + + PTR_LI t0, CKSEG1ADDR(BOSTON_PLAT_BASE) +1: lw t1, BOSTON_PLAT_DDR3STAT(t0) + andi t1, t1, BOSTON_PLAT_DDR3STAT_CALIB + beqz t1, 1b + + PTR_LA a0, msg_ddr_ok + bal lowlevel_display + + move v0, zero + jr s0 + END(lowlevel_init) + +LEAF(lowlevel_display) + .set push + .set noat + PTR_LI $1, CKSEG1ADDR(BOSTON_LCD_BASE) +#ifdef CONFIG_64BIT + ld k1, 0(a0) + sd k1, 0($1) +#else + lw k1, 0(a0) + sw k1, 0($1) + lw k1, 4(a0) + sw k1, 4($1) +#endif + .set pop +1: jr ra + END(lowlevel_display) diff --git a/configs/boston_defconfig b/configs/boston_defconfig new file mode 100644 index 0000000..381203a --- /dev/null +++ b/configs/boston_defconfig @@ -0,0 +1,41 @@ +CONFIG_MIPS=y +CONFIG_TARGET_BOSTON=y +CONFIG_SYS_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS64_R6=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="img,boston" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_SYS_NO_FLASH=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="boston # " +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_CLK=y +CONFIG_DM_ETH=y +CONFIG_PCH_GBE=y +CONFIG_DM_PCI=y +CONFIG_PCI_XILINX=y +CONFIG_SYS_NS16550=y +CONFIG_LZ4=y diff --git a/include/configs/boston.h b/include/configs/boston.h new file mode 100644 index 0000000..b9cc1b9 --- /dev/null +++ b/include/configs/boston.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __CONFIGS_BOSTON_H__ +#define __CONFIGS_BOSTON_H__ + +/* + * General board configuration + */ +#define CONFIG_BOARD_EARLY_INIT_F +#define CONFIG_DISPLAY_BOARDINFO + +/* + * CPU + */ +#define CONFIG_SYS_MIPS_TIMER_FREQ 30000000 + +/* + * PCI + */ +#define CONFIG_PCI +#define CONFIG_PCI_PNP +#define CONFIG_CMD_PCI + +/* + * Environment + */ +#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SIZE 1024 + +/* + * Memory map + */ +#ifdef CONFIG_64BIT +# define CONFIG_SYS_SDRAM_BASE 0xffffffff80000000 +#else +# define CONFIG_SYS_SDRAM_BASE 0x80000000 +#endif + +#define CONFIG_SYS_INIT_SP_OFFSET 0x400000 + +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x100000) + +#define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + 0) +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x10000000) + +#define CONFIG_SYS_MALLOC_LEN (256 * 1024) + +/* + * Console + */ +#define CONFIG_SYS_MAXARGS 16 +#define CONFIG_SYS_CBSIZE 256 +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT) + 16) +#define CONFIG_SYS_LONGHELP +#define CONFIG_BAUDRATE 115200 + +/* + * Flash + */ +#define CONFIG_SYS_MAX_FLASH_BANKS 1 + +#endif /* __CONFIGS_BOSTON_H__ */

Am 27.07.2016 um 00:24 schrieb Paul Burton:
This patch introduces support for building U-Boot to run on the MIPS Boston development board. This is a board built around an FPGA & an Intel EG20T Platform Controller Hub, used largely as part of the development of new CPUs and their software support. It is essentially the successor to the older MIPS Malta board.
Signed-off-by: Paul Burton paul.burton@imgtec.com
arch/mips/Kconfig | 16 +++ arch/mips/dts/Makefile | 1 + arch/mips/dts/img,boston.dts | 225 ++++++++++++++++++++++++++++++++++++ board/imgtec/boston/Kconfig | 16 +++ board/imgtec/boston/MAINTAINERS | 6 + board/imgtec/boston/Makefile | 10 ++ board/imgtec/boston/boston-lcd.h | 21 ++++ board/imgtec/boston/boston-regs.h | 47 ++++++++ board/imgtec/boston/checkboard.c | 29 +++++ board/imgtec/boston/ddr.c | 30 +++++ board/imgtec/boston/early_init.c | 61 ++++++++++ board/imgtec/boston/lowlevel_init.S | 56 +++++++++ configs/boston_defconfig | 41 +++++++ include/configs/boston.h | 69 +++++++++++ 14 files changed, 628 insertions(+) create mode 100644 arch/mips/dts/img,boston.dts create mode 100644 board/imgtec/boston/Kconfig create mode 100644 board/imgtec/boston/MAINTAINERS create mode 100644 board/imgtec/boston/Makefile create mode 100644 board/imgtec/boston/boston-lcd.h create mode 100644 board/imgtec/boston/boston-regs.h create mode 100644 board/imgtec/boston/checkboard.c create mode 100644 board/imgtec/boston/ddr.c create mode 100644 board/imgtec/boston/early_init.c create mode 100644 board/imgtec/boston/lowlevel_init.S create mode 100644 configs/boston_defconfig create mode 100644 include/configs/boston.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 21066f0..7ba0ef2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -73,9 +73,25 @@ config MACH_PIC32 select OF_CONTROL select DM
+config TARGET_BOSTON
- bool "Support Boston"
- select DM
- select DM_SERIAL
- select OF_CONTROL
- select MIPS_L1_CACHE_SHIFT_6
- select SUPPORTS_BIG_ENDIAN
- select SUPPORTS_LITTLE_ENDIAN
- select SUPPORTS_CPU_MIPS32_R1
- select SUPPORTS_CPU_MIPS32_R2
- select SUPPORTS_CPU_MIPS32_R6
- select SUPPORTS_CPU_MIPS64_R1
- select SUPPORTS_CPU_MIPS64_R2
- select SUPPORTS_CPU_MIPS64_R6
endchoice
source "board/dbau1x00/Kconfig" +source "board/imgtec/boston/Kconfig" source "board/imgtec/malta/Kconfig" source "board/micronas/vct/Kconfig" source "board/pb1x00/Kconfig" diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index 2f04d73..6a5e43e 100644 --- a/arch/mips/dts/Makefile +++ b/arch/mips/dts/Makefile @@ -4,6 +4,7 @@
dtb-$(CONFIG_TARGET_AP121) += ap121.dtb dtb-$(CONFIG_TARGET_AP143) += ap143.dtb +dtb-$(CONFIG_TARGET_BOSTON) += img,boston.dtb dtb-$(CONFIG_TARGET_MALTA) += mti,malta.dtb dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb diff --git a/arch/mips/dts/img,boston.dts b/arch/mips/dts/img,boston.dts new file mode 100644 index 0000000..e4e0f28 --- /dev/null +++ b/arch/mips/dts/img,boston.dts @@ -0,0 +1,225 @@ +/dts-v1/;
+#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/mips-gic.h>
+/ {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "img,boston";
- chosen {
stdout-path = &uart0;
- };
- aliases {
clk_sys = &clk_sys;
- };
- cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "img,mips";
reg = <0>;
clocks = <&clk_sys>;
};
- };
- memory@0 {
device_type = "memory";
reg = <0x00000000 0x10000000>;
- };
- clk_sys: clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <10000000>;
u-boot,dm-pre-reloc;
- };
- axi4 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
gic: interrupt-controller {
compatible = "mti,gic";
interrupt-controller;
#interrupt-cells = <3>;
timer {
compatible = "mti,gic-timer";
interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
clocks = <&clk_sys>;
};
};
plat_regs: system-controller@17ffd000 {
compatible = "img,boston-platform-regs", "syscon";
reg = <0x17ffd000 0x1000>;
};
reboot: syscon-reboot {
compatible = "syscon-reboot";
regmap = <&plat_regs>;
offset = <0x10>;
mask = <0x10>;
};
uart0: uart@17ffe000 {
compatible = "ns16550a";
reg = <0x17ffe000 0x1000>;
reg-shift = <2>;
reg-io-width = <4>;
interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_sys>;
u-boot,dm-pre-reloc;
};
lcd: lcd@17fff000 {
compatible = "img,boston-lcd";
reg = <0x17fff000 0x8>;
};
pci0: pci@10000000 {
status = "disabled";
compatible = "xlnx,axi-pcie-host-1.00.a";
device_type = "pci";
reg = <0x10000000 0x2000000>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>;
ranges = <0x02000000 0 0x40000000
0x40000000 0 0x40000000>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pci0_intc 0>,
<0 0 0 2 &pci0_intc 1>,
<0 0 0 3 &pci0_intc 2>,
<0 0 0 4 &pci0_intc 3>;
pci0_intc: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
pci1: pci@12000000 {
status = "disabled";
compatible = "xlnx,axi-pcie-host-1.00.a";
device_type = "pci";
reg = <0x12000000 0x2000000>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 1 IRQ_TYPE_LEVEL_HIGH>;
ranges = <0x02000000 0 0x20000000
0x20000000 0 0x20000000>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pci1_intc 0>,
<0 0 0 2 &pci1_intc 1>,
<0 0 0 3 &pci1_intc 2>,
<0 0 0 4 &pci1_intc 3>;
pci1_intc: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
pci2: pci@14000000 {
compatible = "xlnx,axi-pcie-host-1.00.a";
device_type = "pci";
reg = <0x14000000 0x2000000>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 0 IRQ_TYPE_LEVEL_HIGH>;
ranges = <0x02000000 0 0x16000000
0x16000000 0 0x100000>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pci2_intc 0>,
<0 0 0 2 &pci2_intc 1>,
<0 0 0 3 &pci2_intc 2>,
<0 0 0 4 &pci2_intc 3>;
pci2_intc: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
pci2_root@0,0,0 {
compatible = "pci10ee,7021";
reg = <0x00000000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
eg20t_bridge@1,0,0 {
compatible = "pci8086,8800";
reg = <0x00010000 0 0 0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
eg20t_mac@2,0,1 {
compatible = "pci8086,8802";
reg = <0x00020100 0 0 0 0>;
phy-reset-gpios = <&eg20t_gpio 6 GPIO_ACTIVE_LOW>;
};
eg20t_gpio: eg20t_gpio@2,0,2 {
compatible = "pci8086,8803";
reg = <0x00020200 0 0 0 0>;
gpio-controller;
#gpio-cells = <2>;
};
eg20t_i2c@2,12,2 {
compatible = "pci8086,8817";
reg = <0x00026200 0 0 0 0>;
#address-cells = <1>;
#size-cells = <0>;
rtc@0x68 {
compatible = "st,m41t81s";
reg = <0x68>;
};
};
};
};
};
- };
+}; diff --git a/board/imgtec/boston/Kconfig b/board/imgtec/boston/Kconfig new file mode 100644 index 0000000..ab76a3c --- /dev/null +++ b/board/imgtec/boston/Kconfig @@ -0,0 +1,16 @@ +if TARGET_BOSTON
+config SYS_BOARD
- default "boston"
+config SYS_VENDOR
- default "imgtec"
+config SYS_CONFIG_NAME
- default "boston"
+config SYS_TEXT_BASE
- default 0x9fc00000 if 32BIT
- default 0xffffffff9fc00000 if 64BIT
+endif diff --git a/board/imgtec/boston/MAINTAINERS b/board/imgtec/boston/MAINTAINERS new file mode 100644 index 0000000..30dd481 --- /dev/null +++ b/board/imgtec/boston/MAINTAINERS @@ -0,0 +1,6 @@ +BOSTON BOARD +M: Paul Burton paul.burton@imgtec.com +S: Maintained +F: board/imgtec/boston/ +F: include/configs/boston.h +F: configs/boston_defconfig diff --git a/board/imgtec/boston/Makefile b/board/imgtec/boston/Makefile new file mode 100644 index 0000000..b7125b5 --- /dev/null +++ b/board/imgtec/boston/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (C) 2016 Imagination Technologies +# +# SPDX-License-Identifier: GPL-2.0 +#
+obj-y += checkboard.o +obj-y += ddr.o +obj-y += early_init.o +obj-y += lowlevel_init.o diff --git a/board/imgtec/boston/boston-lcd.h b/board/imgtec/boston/boston-lcd.h new file mode 100644 index 0000000..9f5c1b9 --- /dev/null +++ b/board/imgtec/boston/boston-lcd.h @@ -0,0 +1,21 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#ifndef __BOARD_BOSTON_LCD_H__ +#define __BOARD_BOSTON_LCD_H__
+/**
- lowlevel_display() - Display a message on Boston's LCD
- @msg: The string to display
- Display the string @msg on the 7 character LCD display of the Boston board.
- This is typically used for debug or to present some form of status
- indication to the user, allowing faults to be identified when things go
- wrong early enough that the UART isn't up.
- */
+void lowlevel_display(const char msg[static 8]);
+#endif /* __BOARD_BOSTON_LCD_H__ */ diff --git a/board/imgtec/boston/boston-regs.h b/board/imgtec/boston/boston-regs.h new file mode 100644 index 0000000..c33535e --- /dev/null +++ b/board/imgtec/boston/boston-regs.h @@ -0,0 +1,47 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#ifndef __BOARD_BOSTON_REGS_H__ +#define __BOARD_BOSTON_REGS_H__
+#define BOSTON_PLAT_BASE 0x17ffd000 +#define BOSTON_LCD_BASE 0x17fff000
+/*
- Platform Register Definitions
- */
+#define BOSTON_PLAT_CORE_CL 0x04
+#define BOSTON_PLAT_DDR3STAT 0x14 +# define BOSTON_PLAT_DDR3STAT_CALIB (1 << 2)
+#define BOSTON_PLAT_MMCMDIV 0x30 +# define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0) +# define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8) +# define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16) +# define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24)
+#define BOSTON_PLAT_DDRCONF0 0x38 +# define BOSTON_PLAT_DDRCONF0_SIZE (0xf << 0)
+#ifndef __ASSEMBLY__
+#include <asm/io.h>
+#define BUILD_PLAT_ACCESSORS(offset, name) \ +static inline uint32_t read_boston_##name(void) \ +{ \
- uint32_t *reg = (void *)CKSEG1ADDR(BOSTON_PLAT_BASE) + (offset);\
- return __raw_readl(reg); \
+}
+BUILD_PLAT_ACCESSORS(BOSTON_PLAT_CORE_CL, core_cl) +BUILD_PLAT_ACCESSORS(BOSTON_PLAT_MMCMDIV, mmcmdiv) +BUILD_PLAT_ACCESSORS(BOSTON_PLAT_DDRCONF0, ddrconf0)
+#endif /* !__ASSEMBLY__ */
+#endif /* __BOARD_BOSTON_REGS_H__ */ diff --git a/board/imgtec/boston/checkboard.c b/board/imgtec/boston/checkboard.c new file mode 100644 index 0000000..417ac4e --- /dev/null +++ b/board/imgtec/boston/checkboard.c @@ -0,0 +1,29 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h>
+#include <asm/mipsregs.h>
+#include "boston-lcd.h" +#include "boston-regs.h"
+int checkboard(void) +{
- u32 changelist;
- lowlevel_display("U-boot ");
- printf("Board: MIPS Boston\n");
- printf("CPU: 0x%08x", read_c0_prid());
- changelist = read_boston_core_cl();
- if (changelist > 1)
printf(" cl%x", changelist);
- putc('\n');
- return 0;
+} diff --git a/board/imgtec/boston/ddr.c b/board/imgtec/boston/ddr.c new file mode 100644 index 0000000..7caed4b --- /dev/null +++ b/board/imgtec/boston/ddr.c @@ -0,0 +1,30 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h>
+#include <asm/addrspace.h>
+#include "boston-regs.h"
+phys_size_t initdram(int board_type) +{
- u32 ddrconf0 = read_boston_ddrconf0();
- return (phys_size_t)(ddrconf0 & BOSTON_PLAT_DDRCONF0_SIZE) << 30;
+}
+ulong board_get_usable_ram_top(ulong total_size) +{
- DECLARE_GLOBAL_DATA_PTR;
- if (gd->ram_top < CONFIG_SYS_SDRAM_BASE) {
/* 2GB wrapped around to 0 */
return CKSEG0ADDR(256 << 20);
- }
- return min_t(unsigned long, gd->ram_top, CKSEG0ADDR(256 << 20));
+} diff --git a/board/imgtec/boston/early_init.c b/board/imgtec/boston/early_init.c new file mode 100644 index 0000000..eac56d6 --- /dev/null +++ b/board/imgtec/boston/early_init.c @@ -0,0 +1,61 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#include <common.h> +#include <libfdt.h>
+#include "boston-regs.h"
+/**
- fixup_dt_clock() - Fixup the system clock frequency in the DT
- @fdt: Pointer to the Flattened Device Tree
- Calculate the system clock frequency from the Boston platform registers and
- update the clocks representation in the FDT to report the correct frequency.
- */
+static void fixup_dt_clock(void *fdt) +{
- uint32_t mmcmdiv = read_boston_mmcmdiv();
- uint32_t in_rate, mul, clk0_div, clk0_rate;
- const char *clk_path;
- int clk_off, err;
- clk_path = fdt_get_alias(fdt, "clk_sys");
- if (!clk_path) {
printf("%s: failed to find clk_sys path\n", __func__);
return;
- }
- clk_off = fdt_path_offset(fdt, clk_path);
- if (clk_off < 0) {
printf("%s: failed to find clk_sys offset\n", __func__);
return;
- }
+#define EXT(field) ((mmcmdiv & field) >> (ffs(field) - 1))
- in_rate = EXT(BOSTON_PLAT_MMCMDIV_INPUT);
- mul = EXT(BOSTON_PLAT_MMCMDIV_MUL);
- clk0_div = EXT(BOSTON_PLAT_MMCMDIV_CLK0DIV);
+#undef EXT
- clk0_rate = (in_rate * mul * 1000000) / clk0_div;
- err = fdt_setprop_inplace_u32(fdt, clk_off, "clock-frequency",
clk0_rate);
- if (err)
printf("%s: failed to set clock-frequency\n", __func__);
+}
Couldn't you create a simple clk driver with this code and use that as clock source? Using the fixed-clk driver and patching the DT properties seems a little bit strange.
+int board_early_init_f(void) +{
- DECLARE_GLOBAL_DATA_PTR;
- fixup_dt_clock((void *)gd->fdt_blob);
- return 0;
+} diff --git a/board/imgtec/boston/lowlevel_init.S b/board/imgtec/boston/lowlevel_init.S new file mode 100644 index 0000000..b77e9b2 --- /dev/null +++ b/board/imgtec/boston/lowlevel_init.S @@ -0,0 +1,56 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#include <config.h>
+#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h>
+#include "boston-regs.h"
+.data
+msg_ddr_cal: .ascii "DDR Cal " +msg_ddr_ok: .ascii "DDR OK "
+.text
+LEAF(lowlevel_init)
- move s0, ra
- PTR_LA a0, msg_ddr_cal
- bal lowlevel_display
- PTR_LI t0, CKSEG1ADDR(BOSTON_PLAT_BASE)
+1: lw t1, BOSTON_PLAT_DDR3STAT(t0)
- andi t1, t1, BOSTON_PLAT_DDR3STAT_CALIB
- beqz t1, 1b
- PTR_LA a0, msg_ddr_ok
- bal lowlevel_display
- move v0, zero
- jr s0
- END(lowlevel_init)
+LEAF(lowlevel_display)
- .set push
- .set noat
- PTR_LI $1, CKSEG1ADDR(BOSTON_LCD_BASE)
isn't it better to use the symbolic name AT from asm/regdef.h instead of $1?
+#ifdef CONFIG_64BIT
- ld k1, 0(a0)
- sd k1, 0($1)
+#else
- lw k1, 0(a0)
- sw k1, 0($1)
- lw k1, 4(a0)
- sw k1, 4($1)
+#endif
- .set pop
+1: jr ra
- END(lowlevel_display)
diff --git a/configs/boston_defconfig b/configs/boston_defconfig new file mode 100644 index 0000000..381203a --- /dev/null +++ b/configs/boston_defconfig @@ -0,0 +1,41 @@ +CONFIG_MIPS=y +CONFIG_TARGET_BOSTON=y +CONFIG_SYS_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS64_R6=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="img,boston" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_SYS_NO_FLASH=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="boston # " +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_CLK=y +CONFIG_DM_ETH=y +CONFIG_PCH_GBE=y +CONFIG_DM_PCI=y +CONFIG_PCI_XILINX=y +CONFIG_SYS_NS16550=y +CONFIG_LZ4=y diff --git a/include/configs/boston.h b/include/configs/boston.h new file mode 100644 index 0000000..b9cc1b9 --- /dev/null +++ b/include/configs/boston.h @@ -0,0 +1,69 @@ +/*
- Copyright (C) 2016 Imagination Technologies
- SPDX-License-Identifier: GPL-2.0
- */
+#ifndef __CONFIGS_BOSTON_H__ +#define __CONFIGS_BOSTON_H__
+/*
- General board configuration
- */
+#define CONFIG_BOARD_EARLY_INIT_F +#define CONFIG_DISPLAY_BOARDINFO
+/*
- CPU
- */
+#define CONFIG_SYS_MIPS_TIMER_FREQ 30000000
+/*
- PCI
- */
+#define CONFIG_PCI +#define CONFIG_PCI_PNP +#define CONFIG_CMD_PCI
+/*
- Environment
- */
+#define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_SIZE 1024
+/*
- Memory map
- */
+#ifdef CONFIG_64BIT +# define CONFIG_SYS_SDRAM_BASE 0xffffffff80000000 +#else +# define CONFIG_SYS_SDRAM_BASE 0x80000000 +#endif
+#define CONFIG_SYS_INIT_SP_OFFSET 0x400000
+#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x100000)
+#define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + 0) +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x10000000)
+#define CONFIG_SYS_MALLOC_LEN (256 * 1024)
+/*
- Console
- */
+#define CONFIG_SYS_MAXARGS 16 +#define CONFIG_SYS_CBSIZE 256 +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP +#define CONFIG_BAUDRATE 115200
+/*
- Flash
- */
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#endif /* __CONFIGS_BOSTON_H__ */

On 27/07/16 12:37, Daniel Schwierzeck wrote:
+#define EXT(field) ((mmcmdiv & field) >> (ffs(field) - 1))
- in_rate = EXT(BOSTON_PLAT_MMCMDIV_INPUT);
- mul = EXT(BOSTON_PLAT_MMCMDIV_MUL);
- clk0_div = EXT(BOSTON_PLAT_MMCMDIV_CLK0DIV);
+#undef EXT
- clk0_rate = (in_rate * mul * 1000000) / clk0_div;
- err = fdt_setprop_inplace_u32(fdt, clk_off, "clock-frequency",
clk0_rate);
- if (err)
printf("%s: failed to set clock-frequency\n", __func__);
+}
Couldn't you create a simple clk driver with this code and use that as clock source? Using the fixed-clk driver and patching the DT properties seems a little bit strange.
Hi Daniel,
What the system provides is just a fixed rate clock, whose rate is determined by the bitfile programmed on the FPGA. I guess I could model it with its own clock driver.
+LEAF(lowlevel_display)
- .set push
- .set noat
- PTR_LI $1, CKSEG1ADDR(BOSTON_LCD_BASE)
isn't it better to use the symbolic name AT from asm/regdef.h instead of $1?
OK, will do.
Thanks, Paul
participants (3)
-
Daniel Schwierzeck
-
Paul Burton
-
Simon Glass