arm: mvebu: Add gdsys ControlCenter-Compact board
Subsystems (9)
cover arm: mvebu: Add gdsys ControlCenter-Compact board
This patch series adds support for the Guntermann & Drunck ControlCenter-Compact board.
To this extent, some bugs in the mvebu PCI driver are fixed, a GPIO driver is added, support for the Marvell 88E1680 is added, the TPM library is extended, the kwbimage generation is streamlined, a board function for manipulating the device tree is added, and secure boot for the mvebu architecture is implemented.
Dirk Eibach (4):
pci: mvebu: Fix Armada 38x support
arm: mvebu: Add gpio support
net: phy: Support Marvell 88E1680
arm: mvebu: Add gdsys ControlCenter-Compact board
Mario Six (12):
mvebu: Add board_pex_config()
dm: Add callback to modify the device tree
lib: tpm: Add command to flush resources
tools: kwbimage: Fix dest addr
tools: kwbimage: Fix style violations
tools: kwbimage: Fix arithmetic with void pointers
tools: kwbimage: Reduce scope of variables
tools: kwbimage: Remove unused parameter
tools: kwbimage: Factor out add_binary_header_v1
tools: kwbimage: Refactor line parsing and fix error
arm: mvebu: Implement secure boot
controlcenterdc: Make secure boot available
Reinhard Pfau (1):
arm: mvebu: spl.c: Remove useless gd declaration
Makefile | 3 +- arch/arm/Kconfig | 1 + arch/arm/dts/Makefile | 3 +- arch/arm/dts/controlcenterdc.dts | 629 ++++++++++++++++ arch/arm/mach-mvebu/Kconfig | 24 + arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/efuse.c | 293 ++++++++ arch/arm/mach-mvebu/include/mach/cpu.h | 2 + arch/arm/mach-mvebu/include/mach/efuse.h | 71 ++ arch/arm/mach-mvebu/include/mach/gpio.h | 41 +- arch/arm/mach-mvebu/include/mach/soc.h | 1 + arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 10 + arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 2 + arch/arm/mach-mvebu/spl.c | 2 - board/gdsys/38x/.gitignore | 1 + board/gdsys/38x/Kconfig | 51 ++ board/gdsys/38x/MAINTAINERS | 7 + board/gdsys/38x/Makefile | 45 ++ board/gdsys/38x/README | 18 + board/gdsys/38x/controlcenterdc.c | 717 ++++++++++++++++++ board/gdsys/38x/dt_helpers.c | 60 ++ board/gdsys/38x/dt_helpers.h | 16 + board/gdsys/38x/hre.c | 517 +++++++++++++ board/gdsys/38x/hre.h | 38 + board/gdsys/38x/keyprogram.c | 158 ++++ board/gdsys/38x/keyprogram.h | 14 + board/gdsys/38x/kwbimage.cfg.in | 40 + board/gdsys/38x/spl.c | 21 + board/gdsys/p1022/controlcenterd-id.c | 9 - common/board_f.c | 3 + configs/controlcenterdc_defconfig | 54 ++ drivers/net/phy/marvell.c | 51 ++ drivers/pci/pci_mvebu.c | 25 +- dts/Kconfig | 10 + include/asm-generic/global_data.h | 4 + include/common.h | 1 + include/configs/controlcenterdc.h | 244 +++++++ include/tpm.h | 45 ++ lib/tpm.c | 28 + tools/Makefile | 6 +- tools/kwbimage.c | 1091 ++++++++++++++++++++++++---- tools/kwbimage.h | 37 + 42 files changed, 4216 insertions(+), 178 deletions(-) create mode 100644 arch/arm/dts/controlcenterdc.dts create mode 100644 arch/arm/mach-mvebu/efuse.c create mode 100644 arch/arm/mach-mvebu/include/mach/efuse.h create mode 100644 board/gdsys/38x/.gitignore create mode 100644 board/gdsys/38x/Kconfig create mode 100644 board/gdsys/38x/MAINTAINERS create mode 100644 board/gdsys/38x/Makefile create mode 100644 board/gdsys/38x/README create mode 100644 board/gdsys/38x/controlcenterdc.c create mode 100644 board/gdsys/38x/dt_helpers.c create mode 100644 board/gdsys/38x/dt_helpers.h create mode 100644 board/gdsys/38x/hre.c create mode 100644 board/gdsys/38x/hre.h create mode 100644 board/gdsys/38x/keyprogram.c create mode 100644 board/gdsys/38x/keyprogram.h create mode 100644 board/gdsys/38x/kwbimage.cfg.in create mode 100644 board/gdsys/38x/spl.c create mode 100644 configs/controlcenterdc_defconfig create mode 100644 include/configs/controlcenterdc.h
--
2.9.0
PATCH 1/17 pci: mvebu: Fix Armada 38x support
From: Dirk Eibach <[email protected]>
Armada 38x has four PCI ports, not three.
The optimization in pci_init_board() seems to assume that every port has three lanes. This is obviously wrong, and breaks support for Armada 38x.
--- arch/arm/mach-mvebu/include/mach/soc.h | 1 + drivers/pci/pci_mvebu.c | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-)
arch/arm/mach-mvebu/include/mach/soc.h +1 -0
@@ -70,6 +70,7 @@#define MVEBU_REG_PCIE_BASE (MVEBU_REGISTER(0x40000))#define MVEBU_AXP_USB_BASE (MVEBU_REGISTER(0x50000))#define MVEBU_USB20_BASE (MVEBU_REGISTER(0x58000)) +#define MVEBU_REG_PCIE0_BASE (MVEBU_REGISTER(0x80000))#define MVEBU_AXP_SATA_BASE (MVEBU_REGISTER(0xa0000))#define MVEBU_SATA0_BASE (MVEBU_REGISTER(0xa8000))#define MVEBU_NAND_BASE (MVEBU_REGISTER(0xd0000))
drivers/pci/pci_mvebu.c +13 -12
@@ -91,25 +91,26 @@ static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;#if defined(CONFIG_ARMADA_38X )#define PCIE_BASE (if) \ ((if) == 0 ? \ - MVEBU_REG_PCIE_BASE + 0x40000 : \ - MVEBU_REG_PCIE_BASE + 0x4000 * (if)) + MVEBU_REG_PCIE0_BASE : \ + (MVEBU_REG_PCIE_BASE + 0x4000 * (if - 1)))/* * On A38x MV6820 these PEX ports are supported: * 0 - Port 0.0 -* 1 - Port 0.1 -* 2 - Port 0.2 +* 1 - Port 1.0 +* 2 - Port 2.0 +* 3 - Port 3.0 */ -#define MAX_PEX 3 +#define MAX_PEX 4static struct mvebu_pcie pcie_bus[MAX_PEX ];static void mvebu_get_port_lane (struct mvebu_pcie *pcie,int pex_idx,int *mem_target,int *mem_attr) { -u8 port[] = {0 ,1 ,2 }; -u8 lane[] = {0 ,0 ,0 }; -u8 target[] = {8 ,4 ,4 }; -u8 attr[] = {0xe8 ,0xe8 ,0xd8 }; +u8 port[] = {0 ,1 ,2 ,3 }; +u8 lane[] = {0 ,0 ,0 ,0 }; +u8 target[] = {8 ,4 ,4 ,4 }; +u8 attr[] = {0xe8 ,0xe8 ,0xd8 ,0xb8 }; pcie->port = port[pex_idx]; pcie->lane = lane[pex_idx];
@@ -351,9 +352,9 @@ void pci_init_board(void)mvebu_get_port_lane (pcie, i, &mem_target, &mem_attr);/* Don't read at all from pci registers if port power is down */ -if (pcie->lane ==0 &&SELECT (soc_ctrl, pcie->port) ==0 ) { - i +=3 ; -debug ("%s: skipping port %d\n" , __func__, pcie->port); +if (SELECT (soc_ctrl, pcie->port) ==0 ) { +if (pcie->lane ==0 ) +debug ("%s: skipping port %d\n" , __func__, pcie->port);continue ; }
Signature · 1 line
2.9.0
PATCH 2/17 arm: mvebu: Add gpio support
In reply to Mario SixFrom: Dirk Eibach <[email protected]>
Add driver interface functions for the GPIO controller on the mvebu architecture (based on kirkwood).
--- arch/arm/mach-mvebu/include/mach/gpio.h | 41 +++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-)
arch/arm/mach-mvebu/include/mach/gpio.h +39 -2
@@ -1,10 +1,47 @@/* -* SPDX-License-Identifier: GPL-2.0+ +* SPDX-License-Identifier: GPL-2.0+ +*/ + +/* +* Based on (mostly copied from) plat-orion based Linux 2.6 kernel driver. +* Removed kernel level irq handling. Took some macros from kernel to +* allow build. +* +* Dieter Kiermaier dk-arm-linux at gmx.de */ #ifndef __MACH_MVEBU_GPIO_H#define __MACH_MVEBU_GPIO_H -/* Empty file - sdhci requires this. */ +/* got from kernel include/linux/bitops.h */ +#define BITS_PER_BYTE 8 +#define BITS_TO_LONGS (nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) + +#define GPIO_MAX 59 +#define GPIO_OFF (pin) (((pin) >> 5) ? 0x0040 : 0x0000) +#define GPIO_OUT (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x00) +#define GPIO_IO_CONF (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x04) +#define GPIO_BLINK_EN (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x08) +#define GPIO_IN_POL (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x0c) +#define GPIO_DATA_IN (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x10) +#define GPIO_EDGE_CAUSE (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x14) +#define GPIO_EDGE_MASK (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x18) +#define GPIO_LEVEL_MASK (pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x1c) + +/* +* Kirkwood-specific GPIO API +*/ + +void kw_gpio_set_valid (unsigned pin,int mode); +int kw_gpio_is_valid (unsigned pin,int mode); +int kw_gpio_direction_input (unsigned pin); +int kw_gpio_direction_output (unsigned pin,int value); +int kw_gpio_get_value (unsigned pin); +void kw_gpio_set_value (unsigned pin,int value); +void kw_gpio_set_blink (unsigned pin,int blink); +void kw_gpio_set_unused (unsigned pin); + +#define GPIO_INPUT_OK (1 << 0) +#define GPIO_OUTPUT_OK (1 << 1)#endif
Signature · 1 line
2.9.0
PATCH 2/17 arm: mvebu: Add gpio support
Hi Mario,
sorry for the late review. A few comments now to the patch series...
Quoted 9 lines · Mario Six
From: Dirk Eibach <[email protected]>
Add driver interface functions for the GPIO controller on the mvebu architecture (based on kirkwood).
Signed-off-by Dirk Eibach <[email protected]>--- arch/arm/mach-mvebu/include/mach/gpio.h | 41 +++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-)
This is no "real" GPIO driver but only adds to the old GPIO infrastructure. I've added a DM based GPIO driver for MVEBU quite a while ago:
drivers/gpio/mvebu_gpio.c
Could you please try to use this driver instead? If something is missing in this driver then please extend this DM driver.
Thanks,
Stefan
PATCH 3/17 net: phy: Support Marvell 88E1680
In reply to Mario SixFrom: Dirk Eibach <[email protected]>
Add support for Marvell 88E1680 Integrated Octal 10/100/1000 Mbps Energy Efficient Ethernet Transceiver.
--- drivers/net/phy/marvell.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
drivers/net/phy/marvell.c +51 -0
@@ -480,6 +480,46 @@ static int m88e1310_config(struct phy_device *phydev)return genphy_config_aneg (phydev); } +static int m88e1680_config (struct phy_device *phydev) +{ +/* +* As per Marvell Release Notes - Alaska V 88E1680 Rev A2 +* Errata Section 4.1 +*/ +u16 reg; + +/* Matrix LED mode (not neede if single LED mode is used */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0004 ); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,27 ); + reg |= (1 <<5 ); +phy_write (phydev,MDIO_DEVAD_NONE ,27 , reg); + +/* QSGMII TX amplitude change */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00fd ); +phy_write (phydev,MDIO_DEVAD_NONE ,8 ,0x0b53 ); +phy_write (phydev,MDIO_DEVAD_NONE ,7 ,0x200d ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); + +/* EEE initialization */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00ff ); +phy_write (phydev,MDIO_DEVAD_NONE ,17 ,0xb030 ); +phy_write (phydev,MDIO_DEVAD_NONE ,16 ,0x215c ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00fc ); +phy_write (phydev,MDIO_DEVAD_NONE ,24 ,0x888c ); +phy_write (phydev,MDIO_DEVAD_NONE ,25 ,0x888c ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); +phy_write (phydev,MDIO_DEVAD_NONE ,0 ,0x9140 ); + +genphy_config_aneg (phydev); + +/* soft reset */ + reg =phy_read (phydev,MDIO_DEVAD_NONE ,MII_BMCR ); + reg |=BMCR_RESET ; +phy_write (phydev,MDIO_DEVAD_NONE ,MII_BMCR , reg); + +return 0 ; +} +static struct phy_driver M88E1011S_driver = { .name ="Marvell 88E1011S" , .uid =0x1410c60 ,
@@ -580,6 +620,16 @@ static struct phy_driver M88E1310_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1680_driver = { + .name ="Marvell 88E1680" , + .uid =0x1410ed0 , + .mask =0xffffff0 , + .features =PHY_GBIT_FEATURES , + .config = &m88e1680_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; +int phy_marvell_init (void ) {phy_register (&M88E1310_driver);
@@ -592,6 +642,7 @@ int phy_marvell_init(void)phy_register (&M88E1011S_driver);phy_register (&M88E1510_driver);phy_register (&M88E1518_driver); +phy_register (&M88E1680_driver);return 0 ; }
Signature · 1 line
2.9.0
PATCH 3/17 net: phy: Support Marvell 88E1680
Quoted 18 lines · Mario Six
From: Dirk Eibach <[email protected]>
Add support for Marvell 88E1680 Integrated Octal 10/100/1000 Mbps Energy Efficient Ethernet Transceiver.
Signed-off-by Dirk Eibach <[email protected]>--- drivers/net/phy/marvell.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)drivers/net/phy/marvell.c +0
-0@@ -480,6 +480,46 @@ static int m88e1310_config(struct phy_device *phydev)return genphy_config_aneg (phydev); }
drivers/net/phy/marvell.c static int m88e1310_config(struct phy_device *phydev) · line 492
Quoted 10 lines
drivers/net/phy/marvell.c +10
-0+static int m88e1680_config (struct phy_device *phydev) +{ +/* +* As per Marvell Release Notes - Alaska V 88E1680 Rev A2 +* Errata Section 4.1 +*/ +u16 reg; + +/* Matrix LED mode (not neede if single LED mode is used */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0004 );
I realize the 88e151* driver went in without my ack (35fa0dda: "net:
phy: marvell: add errata w/a for 88E151* chips"), and is loaded with magic numbers, but let's not proliferate the problem. Please define register offsets or use already-defined register offsets. If reasonable, use defined field values to build values from defines and something like bitfield_replace() from bitfield.h or clrsetbits_le32() from asm/io.h. When it is a constant that represents an encoded physical value that will never be used elsewhere, it's ok to just keep the hard-coded number in the write, but it should be preceeded with a comment that describes the actual meaning in engineering units and prefereably the equation used to come up with the constant. If you have the information to improve the 151* implementation as well, that would be very welcome.
Quoted 11 lines
drivers/net/phy/marvell.c +11
-0+ reg =phy_read (phydev,MDIO_DEVAD_NONE ,27 ); + reg |= (1 <<5 ); +phy_write (phydev,MDIO_DEVAD_NONE ,27 , reg); + +/* QSGMII TX amplitude change */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00fd ); +phy_write (phydev,MDIO_DEVAD_NONE ,8 ,0x0b53 ); +phy_write (phydev,MDIO_DEVAD_NONE ,7 ,0x200d ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); + +/* EEE initialization */
drivers/net/phy/marvell.c static int m88e1310_config(struct phy_device *phydev) · line 513
Quoted 10 lines
drivers/net/phy/marvell.c +10
-0+phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00ff ); +phy_write (phydev,MDIO_DEVAD_NONE ,17 ,0xb030 ); +phy_write (phydev,MDIO_DEVAD_NONE ,16 ,0x215c ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00fc ); +phy_write (phydev,MDIO_DEVAD_NONE ,24 ,0x888c ); +phy_write (phydev,MDIO_DEVAD_NONE ,25 ,0x888c ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); +phy_write (phydev,MDIO_DEVAD_NONE ,0 ,0x9140 ); + +genphy_config_aneg (phydev);
This should check the return code and return it if negative.
drivers/net/phy/marvell.c static int m88e1310_config(struct phy_device *phydev) · line 521
Quoted 8 lines
drivers/net/phy/marvell.c +8
-0+ +/* soft reset */ + reg =phy_read (phydev,MDIO_DEVAD_NONE ,MII_BMCR ); + reg |=BMCR_RESET ; +phy_write (phydev,MDIO_DEVAD_NONE ,MII_BMCR , reg); + +return 0 ; +}
Thanks,
-Joe
PATCH 3/17 net: phy: Support Marvell 88E1680
2016-11-30 0:00 GMT+01:00 Joe Hershberger <[email protected]>:
Quoted 35 lines · Mario Six
Quoted 18 lines
From: Dirk Eibach <[email protected]>
Add support for Marvell 88E1680 Integrated Octal 10/100/1000 Mbps Energy Efficient Ethernet Transceiver.
Signed-off-by Dirk Eibach <[email protected]>--- drivers/net/phy/marvell.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)drivers/net/phy/marvell.c +0
-0@@ -480,6 +480,46 @@ static int m88e1310_config(struct phy_device *phydev)return genphy_config_aneg (phydev); }drivers/net/phy/marvell.c static int m88e1310_config(struct phy_device *phydev) · line 492
Quoted 10 lines
drivers/net/phy/marvell.c +10
-0+static int m88e1680_config (struct phy_device *phydev) +{ +/* +* As per Marvell Release Notes - Alaska V 88E1680 Rev A2 +* Errata Section 4.1 +*/ +u16 reg; + +/* Matrix LED mode (not neede if single LED mode is used */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0004 );I realize the 88e151* driver went in without my ack (
35fa0dda: "net:
phy: marvell: add errata w/a for 88E151* chips"), and is loaded with magic numbers, but let's not proliferate the problem. Please define register offsets or use already-defined register offsets. If reasonable, use defined field values to build values from defines and
Quoted 8 lines
something like
bitfield_replace()frombitfield.horclrsetbits_le32()fromasm/io.h. When it is a constant that represents an encoded physical value that will never be used elsewhere, it's ok to just keep the hard-coded number in the write, but it should be preceeded with a comment that describes the actual meaning in engineering units and prefereably the equation used to come up with the constant. If you have the information to improve the 151* implementation as well, that would be very welcome.
Problem is that the initialization sequence from the Marvell Release Notes is writing undocumented values to undocumented registers. It should be considered a binary blob to get this chip up and running. All the information that is available is added as comments.
Quoted 16 lines
Quoted 16 lines
drivers/net/phy/marvell.c +15
-0+ reg =phy_read (phydev,MDIO_DEVAD_NONE ,27 ); + reg |= (1 <<5 ); +phy_write (phydev,MDIO_DEVAD_NONE ,27 , reg); + +/* QSGMII TX amplitude change */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00fd ); +phy_write (phydev,MDIO_DEVAD_NONE ,8 ,0x0b53 ); +phy_write (phydev,MDIO_DEVAD_NONE ,7 ,0x200d ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); + +/* EEE initialization */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00ff ); +phy_write (phydev,MDIO_DEVAD_NONE ,17 ,0xb030 ); +phy_write (phydev,MDIO_DEVAD_NONE ,16 ,0x215c ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x00fc );
Quoted 8 lines
drivers/net/phy/marvell.c static int m88e1310_config(struct phy_device *phydev) · line 513
Quoted 6 lines
drivers/net/phy/marvell.c +6
-0+phy_write (phydev,MDIO_DEVAD_NONE ,24 ,0x888c ); +phy_write (phydev,MDIO_DEVAD_NONE ,25 ,0x888c ); +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); +phy_write (phydev,MDIO_DEVAD_NONE ,0 ,0x9140 ); + +genphy_config_aneg (phydev);This should check the return code and return it if negative.
Mario, would you take care of this in V2?
Cheers
Dirk
PATCH 4/17 mvebu: Add board_pex_config()
In reply to Mario SixAllow boards to do some initialization when PCIe comes up.
--- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 10 ++++++++++ arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 2 ++ 2 files changed, 12 insertions(+)
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +10 -0
@@ -13,6 +13,13 @@#include "ctrl_pex.h" #include "sys_env_lib.h" +void __board_pex_config (void ) +{ +/* nothing in this weak default implementation */ +} +void board_pex_config (void ) + __attribute__((weak,alias ("__board_pex_config" ))); +int hws_pex_config (const struct serdes_map *serdes_map,u8 count) { u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg,
@@ -77,6 +84,9 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count)/* Support gen1/gen2 */ DEBUG_INIT_FULL_S ("Support gen1/gen2\n" ); + +board_pex_config (); + next_busno =0 ;mdelay (150 );
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +2 -0
@@ -83,4 +83,6 @@ int pex_local_bus_num_set(u32 pex_if, u32 bus_num);int pex_local_dev_num_set (u32 pex_if,u32 dev_num);u32 pex_config_read (u32 pex_if,u32 bus,u32 dev,u32 func,u32 reg_off); +void board_pex_config (void ); +#endif
Signature · 1 line
2.9.0
PATCH 4/17 mvebu: Add board_pex_config()
Quoted 1 line · Mario Six
Allow boards to do some initialization when PCIe comes up.
What is it that your boards needs to do when PCIe comes up? Could you please give me an example here?
Quoted 11 lines
Signed-off-by Dirk Eibach <[email protected]>--- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 10 ++++++++++ arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 2 ++ 2 files changed, 12 insertions(+)arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +0
-0
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c line 22
Quoted 10 lines
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +7
-0@@ -13,6 +13,13 @@#include "ctrl_pex.h" #include "sys_env_lib.h" +void __board_pex_config (void ) +{ +/* nothing in this weak default implementation */ +} +void board_pex_config (void ) + __attribute__((weak,alias ("__board_pex_config" ))); +
Its easier to use this syntax instead:
__weak board_pex_config(void)
...
You don't need to add the __attribute this way.
Thanks,
Stefan
PATCH 4/17 mvebu: Add board_pex_config()
2016-12-01 9:30 GMT+01:00 Stefan Roese <[email protected]>:
Quoted 7 lines · Mario Six
Quoted 2 lines
Allow boards to do some initialization when PCIe comes up.
What is it that your boards needs to do when PCIe comes up? Could you please give me an example here?
You might have a look at Patch 00 of this series. We have a quirky FPGA as a PCIe device that needs some special treamtment when PCIe is is coming up.
Quoted 12 lines
...
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c line 22
Quoted 7 lines
arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +7
-0+void __board_pex_config (void ) +{ +/* nothing in this weak default implementation */ +} +void board_pex_config (void ) + __attribute__((weak,alias ("__board_pex_config" ))); +Its easier to use this syntax instead:
Quoted 4 lines
__weakboard_pex_config(void)
...You don't need to add the
__attributethis way.
Mario could you take car of this in V2?
Cheers
Dirk
PATCH 5/17 arm: mvebu: spl.c: Remove useless gd declaration
In reply to Mario SixFrom: Reinhard Pfau <[email protected]>
ddaa905 ("arm: mvebu: Add DM (driver model) support") removed the assignment of the gd pointer, but kept the (now superfluous) declaration of the gd pointer.
Remove this declaration.
--- arch/arm/mach-mvebu/spl.c | 2 -- 1 file changed, 2 deletions(-)
arch/arm/mach-mvebu/spl.c +0 -2
@@ -13,8 +13,6 @@#include <asm/arch/cpu.h> #include <asm/arch/soc.h> -DECLARE_GLOBAL_DATA_PTR ; -static u32 get_boot_device (void ) {u32 val;
Signature · 1 line
2.9.0
PATCH 6/17 dm: Add callback to modify the device tree
In reply to Mario SixCertain boards come in different variations by way of utilizing daughter boards, for example. These boards might contain additional chips, which are added to the main board's busses, e.g. I2C.
The device tree support for such boards would either, quite naturally, employ the overlay mechanism to add such chips to the tree, or would use one large default device tree, and delete the devices that are actually not present.
Regardless of approach, even on the U-Boot level, a modification of the device tree is a prerequisite to have such modular families of boards supported properly.
Therefore, we add an option to make the U-Boot device tree (the actual copy later used by the driver model) writeable, and add a callback method that allows boards to modify the device tree at an early stage, at which, hopefully, also the application of device tree overlays will be possible.
--- common/board_f.c | 3 +++ dts/Kconfig | 10 ++++++++++ include/asm-generic/global_data.h | 4 ++++ include/common.h | 1 + 4 files changed, 18 insertions(+)
common/board_f.c +3 -0
@@ -1034,6 +1034,9 @@ static init_fnc_t init_sequence_f[] = {#ifdef CONFIG_SYS_EXTBDINFO setup_board_extra,#endif +#ifdef CONFIG_OF_BOARD_FIXUP + board_fix_fdt, +#endif INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc,
dts/Kconfig +10 -0
@@ -14,6 +14,16 @@ config OF_CONTROL This feature provides for run-time configuration of U-Boot via a flattened device tree. +config OF_BOARD_FIXUP + bool "Board-specific manipulation of Device Tree" + help + In certain circumstances it is necessary to be able to modify + U-Boot's device tree (e.g. to delete device from it). This option + make the Device Tree writeable and provides a board-specific + "board_fix_fdt" callback (called during pre-relocation time), which + enables the board initialization to modifiy the Device Tree. The + modified copy is subsequently used by U-Boot after relocation. + config SPL_OF_CONTROL bool "Enable run-time configuration via Device Tree in SPL" depends on SPL && OF_CONTROL
include/asm-generic/global_data.h +4 -0
@@ -69,7 +69,11 @@ typedef struct global_data {struct udevice *timer;/* Timer instance for Driver Model */ #endif +#ifdef CONFIG_OF_BOARD_FIXUP +void *fdt_blob;/* Our device tree, NULL if none */ +#else const void *fdt_blob;/* Our device tree, NULL if none */ +#endif void *new_fdt;/* Relocated FDT */ unsigned long fdt_size;/* Space reserved for relocated FDT */ struct jt_funcs *jt;/* jump table */
include/common.h +1 -0
@@ -502,6 +502,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);/* $(BOARD)/$(BOARD).c */ int board_early_init_f (void ); +int board_fix_fdt (void );int board_late_init (void );int board_postclk_init (void );/* after clocks/timebase, before env/serial */ int board_early_init_r (void );
Signature · 1 line
2.9.0
PATCH 6/17 dm: Add callback to modify the device tree
(Adding Simon and Maxim to Cc)
Quoted 13 lines · Mario Six
Certain boards come in different variations by way of utilizing daughter boards, for example. These boards might contain additional chips, which are added to the main board's busses, e.g. I2C.
The device tree support for such boards would either, quite naturally, employ the overlay mechanism to add such chips to the tree, or would use one large default device tree, and delete the devices that are actually not present.
Regardless of approach, even on the U-Boot level, a modification of the device tree is a prerequisite to have such modular families of boards supported properly.
Quoted 7 lines
Therefore, we add an option to make the U-Boot device tree (the actual copy later used by the driver model) writeable, and add a callback method that allows boards to modify the device tree at an early stage, at which, hopefully, also the application of device tree overlays will be possible.
Signed-off-by Mario Six <[email protected]>
I didn't follow DT overlay lately closely especially not in U-Boot. Simon, Maxim could you please take a look at this patch and comment on its necessity?
Quoted 64 lines
--- common/board_f.c | 3 +++ dts/Kconfig | 10 ++++++++++ include/asm-generic/global_data.h | 4 ++++ include/common.h | 1 + 4 files changed, 18 insertions(+)common/board_f.c +3
-0@@ -1034,6 +1034,9 @@ static init_fnc_t init_sequence_f[] = {#ifdef CONFIG_SYS_EXTBDINFO setup_board_extra,#endif +#ifdef CONFIG_OF_BOARD_FIXUP + board_fix_fdt, +#endif INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc,dts/Kconfig +10
-0@@ -14,6 +14,16 @@ config OF_CONTROL This feature provides for run-time configuration of U-Boot via a flattened device tree. +config OF_BOARD_FIXUP + bool "Board-specific manipulation of Device Tree" + help + In certain circumstances it is necessary to be able to modify + U-Boot's device tree (e.g. to delete device from it). This option + make the Device Tree writeable and provides a board-specific + "board_fix_fdt" callback (called during pre-relocation time), which + enables the board initialization to modifiy the Device Tree. The + modified copy is subsequently used by U-Boot after relocation. + config SPL_OF_CONTROL bool "Enable run-time configuration via Device Tree in SPL" depends on SPL && OF_CONTROLinclude/asm-generic/global_data.h +4
-0@@ -69,7 +69,11 @@ typedef struct global_data {struct udevice *timer;/* Timer instance for Driver Model */ #endif +#ifdef CONFIG_OF_BOARD_FIXUP +void *fdt_blob;/* Our device tree, NULL if none */ +#else const void *fdt_blob;/* Our device tree, NULL if none */ +#endif void *new_fdt;/* Relocated FDT */ unsigned long fdt_size;/* Space reserved for relocated FDT */ struct jt_funcs *jt;/* jump table */ include/common.h +0
-0
include/common.h extern ssize_t spi_write (uchar *, int, uchar *, int); · line 508
Quoted 7 lines
include/common.h +1
-0@@ -502,6 +502,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);/* $(BOARD)/$(BOARD).c */ int board_early_init_f (void ); +int board_fix_fdt (void );int board_late_init (void );int board_postclk_init (void );/* after clocks/timebase, before env/serial */ int board_early_init_r (void );
Thanks,
Stefan
PATCH 6/17 dm: Add callback to modify the device tree
Hi,
Quoted 38 lines · Stefan Roese
(Adding Simon and Maxim to Cc)
Quoted 14 lines · Mario Six
Certain boards come in different variations by way of utilizing daughter boards, for example. These boards might contain additional chips, which are added to the main board's busses, e.g. I2C.
The device tree support for such boards would either, quite naturally, employ the overlay mechanism to add such chips to the tree, or would use one large default device tree, and delete the devices that are actually not present.
Regardless of approach, even on the U-Boot level, a modification of the device tree is a prerequisite to have such modular families of boards supported properly.
Quoted 7 lines
Therefore, we add an option to make the U-Boot device tree (the actual copy later used by the driver model) writeable, and add a callback method that allows boards to modify the device tree at an early stage, at which, hopefully, also the application of device tree overlays will be possible.
Signed-off-by Mario Six <[email protected]>I didn't follow DT overlay lately closely especially not in U-Boot. Simon, Maxim could you please take a look at this patch and comment on its necessity?
Quoted 7 lines
--- common/board_f.c | 3 +++ dts/Kconfig | 10 ++++++++++ include/asm-generic/global_data.h | 4 ++++ include/common.h | 1 + 4 files changed, 18 insertions(+)
Quoted 11 lines
common/board_f.c static init_fnc_t init_sequence_f[] = { · line 1039
Quoted 11 lines
common/board_f.c +3
-0@@ -1034,6 +1034,9 @@ static init_fnc_t init_sequence_f[] = {#ifdef CONFIG_SYS_EXTBDINFO setup_board_extra,#endif +#ifdef CONFIG_OF_BOARD_FIXUP + board_fix_fdt, +#endif
Can you add documentation for this somewhere? E.g. in the driver model readme?
Quoted 36 lines
Quoted 36 lines
common/board_f.c +0
-0INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc,dts/Kconfig +5
-0@@ -14,6 +14,16 @@ config OF_CONTROL This feature provides for run-time configuration of U-Boot via a flattened device tree. +config OF_BOARD_FIXUP + bool "Board-specific manipulation of Device Tree" + help + In certain circumstances it is necessary to be able to modify + U-Boot's device tree (e.g. to delete device from it). Thisoption
dts/Kconfig +2
-0+ make the Device Tree writeable and provides a board-specific + "board_fix_fdt" callback (called during pre-relocation time),which
dts/Kconfig +3
-0+ enables the board initialization to modifiy the Device Tree. The + modified copy is subsequently used by U-Boot after relocation. + config SPL_OF_CONTROL bool "Enable run-time configuration via Device Tree in SPL" depends on SPL && OF_CONTROLinclude/asm-generic/global_data.h +0
-0@@ -69,7 +69,11 @@ typedef struct global_data {struct udevice *timer;/* Timer instance for Driver Model */ #endif
Quoted 7 lines
include/asm-generic/global_data.h typedef struct global_data { · line 79
Quoted 7 lines
include/asm-generic/global_data.h +4
-0+#ifdef CONFIG_OF_BOARD_FIXUP +void *fdt_blob;/* Our device tree, NULL if none */ +#else const void *fdt_blob;/* Our device tree, NULL if none */ +#endif
Can we keep it as const and just use a cast when it needs to change? You could add a function which returns a writable pointer.
Quoted 10 lines
Quoted 10 lines
void
*new_fdt; /* Relocated FDT */
unsigned longfdt_size; /* Space reserved for relocated
FDT */
structjt_funcs*jt; /* jump table */include/common.h +0
-0@@ -502,6 +502,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);
Quoted 3 lines
include/common.h extern ssize_t spi_write (uchar *, int, uchar *, int); · line 505
Quoted 3 lines
include/common.h +1
-0/* $(BOARD)/$(BOARD).c */ int board_early_init_f (void ); +int board_fix_fdt (void );
Comment please. Perhaps it should pass a writable fdt pointer?
Quoted 4 lines
Quoted 4 lines
include/common.h +0
-0int board_late_init (void );int board_postclk_init (void );/* after clocks/timebase, before env/serial */
intboard_early_init_r(void);
There have been discussions about moving to a live tree (hierarchical format) in U-Boot post-relocation. What do you think? It might make these changes easier or more efficient.
Regards,
Simon
PATCH 6/17 dm: Add callback to modify the device tree
Hi Simon,
Quoted 41 lines · Simon Glass
Hi,
Quoted 38 lines · Stefan Roese
(Adding Simon and Maxim to Cc)
Quoted 14 lines · Mario Six
Certain boards come in different variations by way of utilizing daughter boards, for example. These boards might contain additional chips, which are added to the main board's busses, e.g. I2C.
The device tree support for such boards would either, quite naturally, employ the overlay mechanism to add such chips to the tree, or would use one large default device tree, and delete the devices that are actually not present.
Regardless of approach, even on the U-Boot level, a modification of the device tree is a prerequisite to have such modular families of boards supported properly.
Quoted 7 lines
Therefore, we add an option to make the U-Boot device tree (the actual copy later used by the driver model) writeable, and add a callback method that allows boards to modify the device tree at an early stage, at which, hopefully, also the application of device tree overlays will be possible.
Signed-off-by Mario Six <[email protected]>I didn't follow DT overlay lately closely especially not in U-Boot. Simon, Maxim could you please take a look at this patch and comment on its necessity?
Quoted 7 lines
--- common/board_f.c | 3 +++ dts/Kconfig | 10 ++++++++++ include/asm-generic/global_data.h | 4 ++++ include/common.h | 1 + 4 files changed, 18 insertions(+)
Quoted 14 lines
Quoted 11 lines
common/board_f.c static init_fnc_t init_sequence_f[] = { · line 1039
Quoted 11 lines
common/board_f.c +3
-0@@ -1034,6 +1034,9 @@ static init_fnc_t init_sequence_f[] = {#ifdef CONFIG_SYS_EXTBDINFO setup_board_extra,#endif +#ifdef CONFIG_OF_BOARD_FIXUP + board_fix_fdt, +#endif Can you add documentation for this somewhere? E.g. in the driver model readme?
OK, I'll document the feature in v2.
Quoted 36 lines
Quoted 36 lines
Quoted 36 lines
common/board_f.c +0
-0INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc,dts/Kconfig +5
-0@@ -14,6 +14,16 @@ config OF_CONTROL This feature provides for run-time configuration of U-Boot via a flattened device tree. +config OF_BOARD_FIXUP + bool "Board-specific manipulation of Device Tree" + help + In certain circumstances it is necessary to be able to modify + U-Boot's device tree (e.g. to delete device from it). Thisoption
dts/Kconfig +2
-0+ make the Device Tree writeable and provides a board-specific + "board_fix_fdt" callback (called during pre-relocation time),which
dts/Kconfig +3
-0+ enables the board initialization to modifiy the Device Tree. The + modified copy is subsequently used by U-Boot after relocation. + config SPL_OF_CONTROL bool "Enable run-time configuration via Device Tree in SPL" depends on SPL && OF_CONTROLinclude/asm-generic/global_data.h +0
-0@@ -69,7 +69,11 @@ typedef struct global_data {struct udevice *timer;/* Timer instance for Driver Model */ #endif
Quoted 11 lines
Quoted 7 lines
include/asm-generic/global_data.h typedef struct global_data { · line 79
Quoted 7 lines
include/asm-generic/global_data.h +4
-0+#ifdef CONFIG_OF_BOARD_FIXUP +void *fdt_blob;/* Our device tree, NULL if none */ +#else const void *fdt_blob;/* Our device tree, NULL if none */ +#endif Can we keep it as const and just use a cast when it needs to change? You could add a function which returns a writable pointer.
Having the pointer globally writable has the advantage that you can get a writable pointer wherever you need it and don't have to pass it around, but separating the parts where the pointer is writable from the ones where it is not is probably a good idea. Will fix in v2.
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
void
*new_fdt; /* Relocated FDT */
unsigned longfdt_size; /* Space reserved for relocated
FDT */
structjt_funcs*jt; /* jump table */include/common.h +0
-0@@ -502,6 +502,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);
Quoted 6 lines
Quoted 3 lines
include/common.h extern ssize_t spi_write (uchar *, int, uchar *, int); · line 505
Quoted 3 lines
include/common.h +1
-0/* $(BOARD)/$(BOARD).c */ int board_early_init_f (void ); +int board_fix_fdt (void );Comment please. Perhaps it should pass a writable fdt pointer?
I'll add a comment in v2.
Quoted 9 lines
Quoted 4 lines
Quoted 4 lines
include/common.h +0
-0int board_late_init (void );int board_postclk_init (void );/* after clocks/timebase, before env/serial */
intboard_early_init_r(void);There have been discussions about moving to a live tree (hierarchical format) in U-Boot post-relocation. What do you think? It might make these changes easier or more efficient.
Yes, that would definitely make things easier. The approach of modifying the tree before the main U-Boot "sees it" that I'm taking here seems a bit hacky. The other approach I've been experimenting with consisted of starting the board with a base device tree, which only has the devices in it that are guaranteed to exists, gather all needed data to decide which overlays to apply, then tear down the DM (using dm_uninit), make the modifications to the tree, and restart the DM (with dm_init_and_scan). While this worked more or less fine, it seems very wasteful, and a genuinely modifiable tree would be a much nicer solution.
Also, we need a solution to this problem one way or another; the way our hardware is constructed, we need to check which devices actually exist and which do not by querying the hardware itself. And the most natural thing to do here would be to have a modifiable device tree.
Quoted 3 lines
Regards,
Simon
PATCH 6/17 dm: Add callback to modify the device tree
Hi Mario,
Quoted 153 lines · Mario Six
Hi Simon,
Quoted 41 lines · Simon Glass
Hi,
Quoted 38 lines · Stefan Roese
(Adding Simon and Maxim to Cc)
Quoted 14 lines · Mario Six
Certain boards come in different variations by way of utilizing daughter boards, for example. These boards might contain additional chips, which are added to the main board's busses, e.g. I2C.
The device tree support for such boards would either, quite naturally, employ the overlay mechanism to add such chips to the tree, or would use one large default device tree, and delete the devices that are actually not present.
Regardless of approach, even on the U-Boot level, a modification of the device tree is a prerequisite to have such modular families of boards supported properly.
Quoted 7 lines
Therefore, we add an option to make the U-Boot device tree (the actual copy later used by the driver model) writeable, and add a callback method that allows boards to modify the device tree at an early stage, at which, hopefully, also the application of device tree overlays will be possible.
Signed-off-by Mario Six <[email protected]>I didn't follow DT overlay lately closely especially not in U-Boot. Simon, Maxim could you please take a look at this patch and comment on its necessity?
Quoted 7 lines
--- common/board_f.c | 3 +++ dts/Kconfig | 10 ++++++++++ include/asm-generic/global_data.h | 4 ++++ include/common.h | 1 + 4 files changed, 18 insertions(+)Quoted 14 lines
Quoted 11 lines
common/board_f.c static init_fnc_t init_sequence_f[] = { · line 1039
Quoted 11 lines
common/board_f.c +3
-0@@ -1034,6 +1034,9 @@ static init_fnc_t init_sequence_f[] = {#ifdef CONFIG_SYS_EXTBDINFO setup_board_extra,#endif +#ifdef CONFIG_OF_BOARD_FIXUP + board_fix_fdt, +#endif Can you add documentation for this somewhere? E.g. in the driver model readme?
OK, I'll document the feature in v2.
Quoted 36 lines
Quoted 36 lines
Quoted 36 lines
common/board_f.c +0
-0INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc,dts/Kconfig +5
-0@@ -14,6 +14,16 @@ config OF_CONTROL This feature provides for run-time configuration of U-Boot via a flattened device tree. +config OF_BOARD_FIXUP + bool "Board-specific manipulation of Device Tree" + help + In certain circumstances it is necessary to be able to modify + U-Boot's device tree (e.g. to delete device from it). Thisoption
dts/Kconfig +2
-0+ make the Device Tree writeable and provides a board-specific + "board_fix_fdt" callback (called during pre-relocation time),which
dts/Kconfig +3
-0+ enables the board initialization to modifiy the Device Tree. The + modified copy is subsequently used by U-Boot after relocation. + config SPL_OF_CONTROL bool "Enable run-time configuration via Device Tree in SPL" depends on SPL && OF_CONTROLinclude/asm-generic/global_data.h +0
-0@@ -69,7 +69,11 @@ typedef struct global_data {struct udevice *timer;/* Timer instance for Driver Model */ #endif Quoted 11 lines
Quoted 7 lines
include/asm-generic/global_data.h typedef struct global_data { · line 79
Quoted 7 lines
include/asm-generic/global_data.h +4
-0+#ifdef CONFIG_OF_BOARD_FIXUP +void *fdt_blob;/* Our device tree, NULL if none */ +#else const void *fdt_blob;/* Our device tree, NULL if none */ +#endif Can we keep it as const and just use a cast when it needs to change? You could add a function which returns a writable pointer.
Having the pointer globally writable has the advantage that you can get a writable pointer wherever you need it and don't have to pass it around, but separating the parts where the pointer is writable from the ones where it is not is probably a good idea. Will fix in v2.
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
void
*new_fdt; /* Relocated FDT */
unsigned longfdt_size; /* Space reserved for relocated
FDT */
structjt_funcs*jt; /* jump table */include/common.h +0
-0@@ -502,6 +502,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);Quoted 6 lines
Quoted 3 lines
include/common.h extern ssize_t spi_write (uchar *, int, uchar *, int); · line 505
Quoted 3 lines
include/common.h +1
-0/* $(BOARD)/$(BOARD).c */ int board_early_init_f (void ); +int board_fix_fdt (void );Comment please. Perhaps it should pass a writable fdt pointer?
I'll add a comment in v2.
Quoted 9 lines
Quoted 4 lines
Quoted 4 lines
include/common.h +0
-0int board_late_init (void );int board_postclk_init (void );/* after clocks/timebase, before env/serial */
intboard_early_init_r(void);There have been discussions about moving to a live tree (hierarchical format) in U-Boot post-relocation. What do you think? It might make these changes easier or more efficient.
Yes, that would definitely make things easier. The approach of modifying the tree before the main U-Boot "sees it" that I'm taking here seems a bit hacky. The other approach I've been experimenting with consisted of starting the board with a base device tree, which only has the devices in it that are guaranteed to exists, gather all needed data to decide which overlays to apply, then tear down the DM (using
dm_uninit), make the modifications to the tree, and restart the DM (withdm_init_and_scan). While this worked more or less fine, it seems very wasteful, and a genuinely modifiable tree would be a much nicer solution.
Quoted 4 lines
Also, we need a solution to this problem one way or another; the way our hardware is constructed, we need to check which devices actually exist and which do not by querying the hardware itself. And the most natural thing to do here would be to have a modifiable device tree.
Creating a live tree is pretty easy - perhaps 500 lines of code.
Trickier is to adjust the existing fdtdec API so that you can pass a node pointer instead of a blob and offset. I suppose we need to support the existing API for a while.
I think ideally we should have a flat tree before relocation (to save time and space) and a live tree afterwards. So your approach of making the flip just before relocation seems right to me.
Regards,
Simon
PATCH 6/17 dm: Add callback to modify the device tree
In reply to Stefan RoeseQuoted 57 lines · Stefan Roese
(Adding Simon and Maxim to Cc)
Quoted 13 lines · Mario Six
Certain boards come in different variations by way of utilizing daughter boards, for example. These boards might contain additional chips, which are added to the main board's busses, e.g. I2C.
The device tree support for such boards would either, quite naturally, employ the overlay mechanism to add such chips to the tree, or would use one large default device tree, and delete the devices that are actually not present.
Regardless of approach, even on the U-Boot level, a modification of the device tree is a prerequisite to have such modular families of boards supported properly.
Quoted 7 lines
Therefore, we add an option to make the U-Boot device tree (the actual copy later used by the driver model) writeable, and add a callback method that allows boards to modify the device tree at an early stage, at which, hopefully, also the application of device tree overlays will be possible.
Signed-off-by Mario Six <[email protected]>I didn't follow DT overlay lately closely especially not in U-Boot. Simon, Maxim could you please take a look at this patch and comment on its necessity?
Quoted 29 lines
--- common/board_f.c | 3 +++ dts/Kconfig | 10 ++++++++++ include/asm-generic/global_data.h | 4 ++++ include/common.h | 1 + 4 files changed, 18 insertions(+)common/board_f.c +3
-0@@ -1034,6 +1034,9 @@ static init_fnc_t init_sequence_f[] = {#ifdef CONFIG_SYS_EXTBDINFO setup_board_extra,#endif +#ifdef CONFIG_OF_BOARD_FIXUP + board_fix_fdt, +#endif INIT_FUNC_WATCHDOG_RESET reloc_fdt, setup_reloc,dts/Kconfig +0
-0@@ -14,6 +14,16 @@ config OF_CONTROL This feature provides for run-time configuration of U-Boot via a flattened device tree.
Quoted 10 lines
dts/Kconfig config OF_CONTROL · line 26
Quoted 10 lines
dts/Kconfig +10
-0+config OF_BOARD_FIXUP + bool "Board-specific manipulation of Device Tree" + help + In certain circumstances it is necessary to be able to modify + U-Boot's device tree (e.g. to delete device from it). This option + make the Device Tree writeable and provides a board-specific + "board_fix_fdt" callback (called during pre-relocation time), which + enables the board initialization to modifiy the Device Tree. The + modified copy is subsequently used by U-Boot after relocation. +
Judging from the help, I guess this is going to be applied even before the device model initialization. Since our plan is to eventually switch to the device model, and you'll probably need someway to detect which adjustments you need to make (using a GPIO, some bus, etc.) which is probably going to be backed by a device model driver. Wouldn't that introduce a chicken and egg issue?
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 801 bytes Desc: not available URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161205/7d6cfdcd/attachment.sig>
PATCH 7/17 lib: tpm: Add command to flush resources
In reply to Mario SixThis patch adds a function to the TPM library, which allows U-Boot to flush resources, e.g. keys, from the TPM.
--- board/gdsys/p1022/controlcenterd-id.c | 9 ------- include/tpm.h | 45 +++++++++++++++++++++++++++++++++++ lib/tpm.c | 28 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-)
board/gdsys/p1022/controlcenterd-id.c +0 -9
@@ -43,15 +43,6 @@#define CCDM_AUTO_FIRST_STAGE #endif -/* enums from TCG specs */ -enum { -/* capability areas */ -TPM_CAP_NV_INDEX =0x00000011 , -TPM_CAP_HANDLE =0x00000014 , -/* resource types */ -TPM_RT_KEY =0x00000001 , -}; -/* CCDM specific contants */ enum {/* NV indices */
include/tpm.h +45 -0
55 lines not on this page · raw message
lib/tpm.c +28 -0
@@ -645,6 +645,34 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)return 0 ; } +uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type) +{ +const uint8_t command[18 ] = { +0x00 ,0xc1 ,/* TPM_TAG */ +0x00 ,0x00 ,0x00 ,0x12 ,/* parameter size */ +0x00 ,0x00 ,0x00 ,0xba ,/* TPM_COMMAND_CODE */ +0x00 ,0x00 ,0x00 ,0x00 ,/* key handle */ +0x00 ,0x00 ,0x00 ,0x00 ,/* resource type */ + }; +const size_t key_handle_offset =10 ; +const size_t resource_type_offset =14 ; + +uint8_t buf[COMMAND_BUFFER_SIZE ], response[COMMAND_BUFFER_SIZE ]; +size_t response_length =sizeof (response); +uint32_t err; + +if (pack_byte_string (buf,sizeof (buf),"sdd" , +0 , command,sizeof (command), + key_handle_offset, key_handle, + resource_type_offset, resource_type)) +return TPM_LIB_ERROR ; + + err =tpm_sendrecv_command (buf, response, &response_length); +if (err) +return err; +return 0 ; +} +#ifdef CONFIG_TPM_AUTH_SESSIONS /**
Signature · 1 line
2.9.0
PATCH 7/17 lib: tpm: Add command to flush resources
(Adding Simon to Cc)
Quoted 4 lines · Mario Six
This patch adds a function to the TPM library, which allows U-Boot to flush resources, e.g. keys, from the TPM.
Signed-off-by Mario Six <[email protected]>
Simon, do you have any comments on this patch please?
Quoted 117 lines
--- board/gdsys/p1022/controlcenterd-id.c | 9 ------- include/tpm.h | 45 +++++++++++++++++++++++++++++++++++ lib/tpm.c | 28 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-)board/gdsys/p1022/controlcenterd-id.c +0
-9@@ -43,15 +43,6 @@#define CCDM_AUTO_FIRST_STAGE #endif -/* enums from TCG specs */ -enum { -/* capability areas */ -TPM_CAP_NV_INDEX =0x00000011 , -TPM_CAP_HANDLE =0x00000014 , -/* resource types */ -TPM_RT_KEY =0x00000001 , -}; -/* CCDM specific contants */ enum {/* NV indices */ include/tpm.h +45
-0@@ -47,6 +47,42 @@ enum tpm_nv_index { TPM_NV_INDEX_DIR = 0x10000001, }; +enum tpm_resource_type { +TPM_RT_KEY =0x00000001 , +TPM_RT_AUTH =0x00000002 , +TPM_RT_HASH =0x00000003 , +TPM_RT_TRANS =0x00000004 , +TPM_RT_CONTEXT =0x00000005 , +TPM_RT_COUNTER =0x00000006 , +TPM_RT_DELEGATE =0x00000007 , +TPM_RT_DAA_TPM =0x00000008 , +TPM_RT_DAA_V0 =0x00000009 , +TPM_RT_DAA_V1 =0x0000000A , +}; + +enum tpm_capability_areas { +TPM_CAP_ORD =0x00000001 , +TPM_CAP_ALG =0x00000002 , +TPM_CAP_PID =0x00000003 , +TPM_CAP_FLAG =0x00000004 , +TPM_CAP_PROPERTY =0x00000005 , +TPM_CAP_VERSION =0x00000006 , +TPM_CAP_KEY_HANDLE =0x00000007 , +TPM_CAP_CHECK_LOADED =0x00000008 , +TPM_CAP_SYM_MODE =0x00000009 , +TPM_CAP_KEY_STATUS =0x0000000C , +TPM_CAP_NV_LIST =0x0000000D , +TPM_CAP_MFR =0x00000010 , +TPM_CAP_NV_INDEX =0x00000011 , +TPM_CAP_TRANS_ALG =0x00000012 , +TPM_CAP_HANDLE =0x00000014 , +TPM_CAP_TRANS_ES =0x00000015 , +TPM_CAP_AUTH_ENCRYPT =0x00000017 , +TPM_CAP_SELECT_SIZE =0x00000018 , +TPM_CAP_DA_LOGIC =0x00000019 , +TPM_CAP_VERSION_VAL =0x0000001A , +}; +#define TPM_NV_PER_GLOBALLOCK (1U << 15)#define TPM_NV_PER_PPWRITE (1U << 0)#define TPM_NV_PER_READ_STCLEAR (1U << 31)@@ -594,4 +630,13 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags);*/ uint32_t tpm_get_permissions (uint32_t index,uint32_t *perm); +/** +* Flush a resource with a given handle and type from the TPM +* +* @param key_handle handle of the resource +* @param resource_type type of the resource +* @return return code of the operation +*/ +uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type); +#endif /* __TPM_H */ lib/tpm.c +21
-0@@ -645,6 +645,34 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)return 0 ; } +uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type) +{ +const uint8_t command[18 ] = { +0x00 ,0xc1 ,/* TPM_TAG */ +0x00 ,0x00 ,0x00 ,0x12 ,/* parameter size */ +0x00 ,0x00 ,0x00 ,0xba ,/* TPM_COMMAND_CODE */ +0x00 ,0x00 ,0x00 ,0x00 ,/* key handle */ +0x00 ,0x00 ,0x00 ,0x00 ,/* resource type */ + }; +const size_t key_handle_offset =10 ; +const size_t resource_type_offset =14 ; + +uint8_t buf[COMMAND_BUFFER_SIZE ], response[COMMAND_BUFFER_SIZE ]; +size_t response_length =sizeof (response); +uint32_t err; + +if (pack_byte_string (buf,sizeof (buf),"sdd" , +0 , command,sizeof (command), + key_handle_offset, key_handle, + resource_type_offset, resource_type)) +return TPM_LIB_ERROR ;
lib/tpm.c uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) · line 678
Quoted 10 lines
lib/tpm.c +7
-0+ + err =tpm_sendrecv_command (buf, response, &response_length); +if (err) +return err; +return 0 ; +} +#ifdef CONFIG_TPM_AUTH_SESSIONS /**
Thanks,
Stefan
PATCH 7/17 lib: tpm: Add command to flush resources
Quoted 11 lines · Stefan Roese
(Adding Simon to Cc)
Quoted 5 lines · Mario Six
This patch adds a function to the TPM library, which allows U-Boot to flush resources, e.g. keys, from the TPM.
Signed-off-by Mario Six <[email protected]>Simon, do you have any comments on this patch please?
Is it possible to add a new tpm subcommand for this?
Quoted 101 lines
Quoted 101 lines
--- board/gdsys/p1022/controlcenterd-id.c | 9 ------- include/tpm.h | 45 +++++++++++++++++++++++++++++++++++ lib/tpm.c | 28 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-)board/gdsys/p1022/controlcenterd-id.c +0
-9@@ -43,15 +43,6 @@#define CCDM_AUTO_FIRST_STAGE #endif -/* enums from TCG specs */ -enum { -/* capability areas */ -TPM_CAP_NV_INDEX =0x00000011 , -TPM_CAP_HANDLE =0x00000014 , -/* resource types */ -TPM_RT_KEY =0x00000001 , -}; -/* CCDM specific contants */ enum {/* NV indices */ include/tpm.h +45
-0@@ -47,6 +47,42 @@ enum tpm_nv_index { TPM_NV_INDEX_DIR = 0x10000001, }; +enum tpm_resource_type { +TPM_RT_KEY =0x00000001 , +TPM_RT_AUTH =0x00000002 , +TPM_RT_HASH =0x00000003 , +TPM_RT_TRANS =0x00000004 , +TPM_RT_CONTEXT =0x00000005 , +TPM_RT_COUNTER =0x00000006 , +TPM_RT_DELEGATE =0x00000007 , +TPM_RT_DAA_TPM =0x00000008 , +TPM_RT_DAA_V0 =0x00000009 , +TPM_RT_DAA_V1 =0x0000000A , +}; + +enum tpm_capability_areas { +TPM_CAP_ORD =0x00000001 , +TPM_CAP_ALG =0x00000002 , +TPM_CAP_PID =0x00000003 , +TPM_CAP_FLAG =0x00000004 , +TPM_CAP_PROPERTY =0x00000005 , +TPM_CAP_VERSION =0x00000006 , +TPM_CAP_KEY_HANDLE =0x00000007 , +TPM_CAP_CHECK_LOADED =0x00000008 , +TPM_CAP_SYM_MODE =0x00000009 , +TPM_CAP_KEY_STATUS =0x0000000C , +TPM_CAP_NV_LIST =0x0000000D , +TPM_CAP_MFR =0x00000010 , +TPM_CAP_NV_INDEX =0x00000011 , +TPM_CAP_TRANS_ALG =0x00000012 , +TPM_CAP_HANDLE =0x00000014 , +TPM_CAP_TRANS_ES =0x00000015 , +TPM_CAP_AUTH_ENCRYPT =0x00000017 , +TPM_CAP_SELECT_SIZE =0x00000018 , +TPM_CAP_DA_LOGIC =0x00000019 , +TPM_CAP_VERSION_VAL =0x0000001A , +}; +#define TPM_NV_PER_GLOBALLOCK (1U << 15)#define TPM_NV_PER_PPWRITE (1U << 0)#define TPM_NV_PER_READ_STCLEAR (1U << 31)@@ -594,4 +630,13 @@ uint32_t tpm_get_permanent_flags(structtpm_permanent_flags *pflags); */ uint32_t tpm_get_permissions (uint32_t index,uint32_t *perm); +/** +* Flush a resource with a given handle and type from the TPM +* +* @param key_handle handle of the resource +* @param resource_type type of the resource +* @return return code of the operation +*/ +uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type); +#endif /*
__TPM_H*/lib/tpm.c +0
-0@@ -645,6 +645,34 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)return 0 ; }
Quoted 12 lines
lib/tpm.c uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) · line 659
Quoted 12 lines
lib/tpm.c +12
-0+uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type) +{ +const uint8_t command[18 ] = { +0x00 ,0xc1 ,/* TPM_TAG */ +0x00 ,0x00 ,0x00 ,0x12 ,/* parameter size */ +0x00 ,0x00 ,0x00 ,0xba ,/* TPM_COMMAND_CODE */ +0x00 ,0x00 ,0x00 ,0x00 ,/* key handle */ +0x00 ,0x00 ,0x00 ,0x00 ,/* resource type */ + }; +const size_t key_handle_offset =10 ; +const size_t resource_type_offset =14 ; +
Drop blank line
Quoted 18 lines
Quoted 18 lines
lib/tpm.c +16
-0+uint8_t buf[COMMAND_BUFFER_SIZE ], response[COMMAND_BUFFER_SIZE ]; +size_t response_length =sizeof (response); +uint32_t err; + +if (pack_byte_string (buf,sizeof (buf),"sdd" , +0 , command,sizeof (command), + key_handle_offset, key_handle, + resource_type_offset, resource_type)) +return TPM_LIB_ERROR ; + + err =tpm_sendrecv_command (buf, response, &response_length); +if (err) +return err; +return 0 ; +} +#ifdef CONFIG_TPM_AUTH_SESSIONS
Quoted 5 lines
Quoted 2 lines
/**
Thanks,
Stefan
Regards,
Simon
PATCH 7/17 lib: tpm: Add command to flush resources
Hi Simon,
Quoted 8 lines · Simon Glass
Quoted 7 lines · Stefan Roese
(Adding Simon to Cc)
Quoted 4 lines · Mario Six
This patch adds a function to the TPM library, which allows U-Boot to flush resources, e.g. keys, from the TPM.
Quoted 9 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Mario Six <[email protected]>Simon, do you have any comments on this patch please?
Reviewed-by Simon Glass <[email protected]>Is it possible to add a new tpm subcommand for this?
OK, I'll add a "tpm flush" command in v2.
Quoted 101 lines
Quoted 101 lines
Quoted 101 lines
--- board/gdsys/p1022/controlcenterd-id.c | 9 ------- include/tpm.h | 45 +++++++++++++++++++++++++++++++++++ lib/tpm.c | 28 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-)board/gdsys/p1022/controlcenterd-id.c +0
-9@@ -43,15 +43,6 @@#define CCDM_AUTO_FIRST_STAGE #endif -/* enums from TCG specs */ -enum { -/* capability areas */ -TPM_CAP_NV_INDEX =0x00000011 , -TPM_CAP_HANDLE =0x00000014 , -/* resource types */ -TPM_RT_KEY =0x00000001 , -}; -/* CCDM specific contants */ enum {/* NV indices */ include/tpm.h +45
-0@@ -47,6 +47,42 @@ enum tpm_nv_index { TPM_NV_INDEX_DIR = 0x10000001, }; +enum tpm_resource_type { +TPM_RT_KEY =0x00000001 , +TPM_RT_AUTH =0x00000002 , +TPM_RT_HASH =0x00000003 , +TPM_RT_TRANS =0x00000004 , +TPM_RT_CONTEXT =0x00000005 , +TPM_RT_COUNTER =0x00000006 , +TPM_RT_DELEGATE =0x00000007 , +TPM_RT_DAA_TPM =0x00000008 , +TPM_RT_DAA_V0 =0x00000009 , +TPM_RT_DAA_V1 =0x0000000A , +}; + +enum tpm_capability_areas { +TPM_CAP_ORD =0x00000001 , +TPM_CAP_ALG =0x00000002 , +TPM_CAP_PID =0x00000003 , +TPM_CAP_FLAG =0x00000004 , +TPM_CAP_PROPERTY =0x00000005 , +TPM_CAP_VERSION =0x00000006 , +TPM_CAP_KEY_HANDLE =0x00000007 , +TPM_CAP_CHECK_LOADED =0x00000008 , +TPM_CAP_SYM_MODE =0x00000009 , +TPM_CAP_KEY_STATUS =0x0000000C , +TPM_CAP_NV_LIST =0x0000000D , +TPM_CAP_MFR =0x00000010 , +TPM_CAP_NV_INDEX =0x00000011 , +TPM_CAP_TRANS_ALG =0x00000012 , +TPM_CAP_HANDLE =0x00000014 , +TPM_CAP_TRANS_ES =0x00000015 , +TPM_CAP_AUTH_ENCRYPT =0x00000017 , +TPM_CAP_SELECT_SIZE =0x00000018 , +TPM_CAP_DA_LOGIC =0x00000019 , +TPM_CAP_VERSION_VAL =0x0000001A , +}; +#define TPM_NV_PER_GLOBALLOCK (1U << 15)#define TPM_NV_PER_PPWRITE (1U << 0)#define TPM_NV_PER_READ_STCLEAR (1U << 31)@@ -594,4 +630,13 @@ uint32_t tpm_get_permanent_flags(structtpm_permanent_flags *pflags); */ uint32_t tpm_get_permissions (uint32_t index,uint32_t *perm); +/** +* Flush a resource with a given handle and type from the TPM +* +* @param key_handle handle of the resource +* @param resource_type type of the resource +* @return return code of the operation +*/ +uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type); +#endif /*
__TPM_H*/lib/tpm.c +0
-0@@ -645,6 +645,34 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)return 0 ; }
Quoted 15 lines
Quoted 4 lines
Quoted 4 lines
lib/tpm.c +4
-0+uint32_t tpm_flush_specific (uint32_t key_handle,uint32_t resource_type) +{ +const uint8_t command[18 ] = { +0x00 ,0xc1 ,/* TPM_TAG */ Quoted 8 lines
lib/tpm.c uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) · line 659
Quoted 8 lines
lib/tpm.c +8
-0+0x00 ,0x00 ,0x00 ,0x12 ,/* parameter size */ +0x00 ,0x00 ,0x00 ,0xba ,/* TPM_COMMAND_CODE */ +0x00 ,0x00 ,0x00 ,0x00 ,/* key handle */ + 0x00, 0x00, 0x00, 0x00, /* resource type */ + }; +const size_t key_handle_offset =10 ; +const size_t resource_type_offset =14 ; +Drop blank line
Will be fixed in v2.
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
lib/tpm.c +16
-0+uint8_t buf[COMMAND_BUFFER_SIZE ], response[COMMAND_BUFFER_SIZE ]; +size_t response_length =sizeof (response); +uint32_t err; + +if (pack_byte_string (buf,sizeof (buf),"sdd" , +0 , command,sizeof (command), + key_handle_offset, key_handle, + resource_type_offset, resource_type)) +return TPM_LIB_ERROR ; + + err =tpm_sendrecv_command (buf, response, &response_length); +if (err) +return err; +return 0 ; +} +#ifdef CONFIG_TPM_AUTH_SESSIONS
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
/**
Thanks,
StefanRegards,
Simon
Thanks for the review!
Best regards,
Mario
PATCH 8/17 tools: kwbimage: Fix dest addr
In reply to Mario SixTo enable secure boot, we need to jump back into the BootROM to continue the SoC's boot process instead of letting the SPL load and run the main U-Boot image.
But, since the u-boot-spl.img (including the 64 byte header) is loaded by the SoC as the main image, we need to compensate for the header length to get a correct entry point.
Thus, we subtract the header size from the destination address, so that the execution address points at the actual entry point of the image.
Other boards ignore both parameters anyway, so this change shouldn't concern them.
--- tools/kwbimage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/kwbimage.c +2 -1
@@ -384,7 +384,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,cpu_to_le32 (payloadsz - headersz +sizeof (uint32_t )); main_hdr->headersz_lsb =cpu_to_le16 (headersz &0xFFFF ); main_hdr->headersz_msb = (headersz &0xFFFF0000 ) >>16 ; - main_hdr->destaddr =cpu_to_le32 (params->addr); + main_hdr->destaddr =cpu_to_le32 (params->addr) + -sizeof (image_header_t); main_hdr->execaddr =cpu_to_le32 (params->ep); main_hdr->srcaddr =cpu_to_le32 (headersz); main_hdr->ext = hasext;
Signature · 1 line
2.9.0
PATCH 9/17 tools: kwbimage: Fix style violations
In reply to Mario SixFix some style violations:
- nine instances of missing blank lines after declarations
- one overly long line
- one split string (which also rewords an error message more concisely)
- two superfluous else
--- tools/kwbimage.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
tools/kwbimage.c +17 -8
@@ -99,6 +99,7 @@ struct image_cfg_element {static const char *image_boot_mode_name (unsigned int id) {int i; +for (i =0 ; boot_modes[i].name; i++)if (boot_modes[i].id == id)return boot_modes[i].name;
@@ -108,6 +109,7 @@ static const char *image_boot_mode_name(unsigned int id)int image_boot_mode_id (const char *boot_mode_name) {int i; +for (i =0 ; boot_modes[i].name; i++)if (!strcmp (boot_modes[i].name, boot_mode_name))return boot_modes[i].id;
@@ -118,6 +120,7 @@ int image_boot_mode_id(const char *boot_mode_name)int image_nand_ecc_mode_id (const char *nand_ecc_mode_name) {int i; +for (i =0 ; nand_ecc_modes[i].name; i++)if (!strcmp (nand_ecc_modes[i].name, nand_ecc_mode_name))return nand_ecc_modes[i].id;
@@ -333,14 +336,14 @@ static size_t image_headersz_v1(struct image_tool_params *params,#if defined(CONFIG_SYS_U_BOOT_OFFS )if (headersz >CONFIG_SYS_U_BOOT_OFFS ) { -fprintf (stderr,"Error: Image header (incl. SPL image) too big!\n" ); +fprintf (stderr, +"Error: Image header (incl. SPL image) too big!\n" );fprintf (stderr,"header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n" , (int )headersz,CONFIG_SYS_U_BOOT_OFFS );fprintf (stderr,"Increase CONFIG_SYS_U_BOOT_OFFS!\n" );return 0 ; - }else { - headersz =CONFIG_SYS_U_BOOT_OFFS ; } + headersz =CONFIG_SYS_U_BOOT_OFFS ;#endif /*
@@ -482,11 +485,13 @@ static int image_create_config_parse_oneline(char *line, keyword =strtok_r (line, deliminiters, &saveptr);if (!strcmp (keyword,"VERSION" )) {char *value =strtok_r (NULL , deliminiters, &saveptr); + el->type =IMAGE_CFG_VERSION ; el->version =atoi (value); }else if (!strcmp (keyword,"BOOT_FROM" )) {char *value =strtok_r (NULL , deliminiters, &saveptr);int ret =image_boot_mode_id (value); +if (ret <0 ) {fprintf (stderr,"Invalid boot media '%s'\n" , value);
@@ -496,16 +501,19 @@ static int image_create_config_parse_oneline(char *line, el->bootfrom = ret; }else if (!strcmp (keyword,"NAND_BLKSZ" )) {char *value =strtok_r (NULL , deliminiters, &saveptr); + el->type =IMAGE_CFG_NAND_BLKSZ ; el->nandblksz =strtoul (value,NULL ,16 ); }else if (!strcmp (keyword,"NAND_BADBLK_LOCATION" )) {char *value =strtok_r (NULL , deliminiters, &saveptr); + el->type =IMAGE_CFG_NAND_BADBLK_LOCATION ; el->nandbadblklocation =strtoul (value,NULL ,16 ); }else if (!strcmp (keyword,"NAND_ECC_MODE" )) {char *value =strtok_r (NULL , deliminiters, &saveptr);int ret =image_nand_ecc_mode_id (value); +if (ret <0 ) {fprintf (stderr,"Invalid NAND ECC mode '%s'\n" , value);
@@ -515,6 +523,7 @@ static int image_create_config_parse_oneline(char *line, el->nandeccmode = ret; }else if (!strcmp (keyword,"NAND_PAGE_SIZE" )) {char *value =strtok_r (NULL , deliminiters, &saveptr); + el->type =IMAGE_CFG_NAND_PAGESZ ; el->nandpagesz =strtoul (value,NULL ,16 ); }else if (!strcmp (keyword,"BINARY" )) {
@@ -760,8 +769,8 @@ static int kwbimage_check_image_types(uint8_t type) {if (type ==IH_TYPE_KWBIMAGE )return EXIT_SUCCESS ; -else -return EXIT_FAILURE ; + +return EXIT_FAILURE ; } static int kwbimage_verify_header(unsigned char *ptr, int image_size,
@@ -834,9 +843,9 @@ static int kwbimage_generate(struct image_tool_params *params,static int kwbimage_check_params (struct image_tool_params *params) {if (!strlen (params->imagename)) { -fprintf (stderr,"Error:%s - Configuration file not specified, " -"it is needed for kwbimage generation\n" , - params->cmdname); +char *msg ="Configuration file for kwbimage creation omitted" ; + +fprintf (stderr,"Error:%s - %s\n" , params->cmdname, msg);return CFG_INVALID ; }
Signature · 1 line
2.9.0
PATCH 10/17 tools: kwbimage: Fix arithmetic with void pointers
In reply to Mario SixArithmetic with void pointers, e.g. a - b where both a and b are void pointers, is undefined in the C standard. Since we are operating with byte data here, we switch the void pointers to uint8_t pointers, and add the necessary casts.
--- tools/kwbimage.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
tools/kwbimage.c +12 -10
@@ -205,7 +205,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,size_t headersz;struct main_hdr_v0 *main_hdr;struct ext_hdr_v0 *ext_hdr; -void *image; +uint8_t *image;int has_ext =0 ;/*
@@ -232,7 +232,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,memset (image,0 , headersz); - main_hdr = image; + main_hdr = (struct main_hdr_v0 *)image;/* Fill in the main header */ main_hdr->blocksize =
@@ -258,7 +258,8 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,if (has_ext) {int cfgi, datai; - ext_hdr = image +sizeof (struct main_hdr_v0 ); + ext_hdr = (struct ext_hdr_v0 *) + (image +sizeof (struct main_hdr_v0 )); ext_hdr->offset =cpu_to_le32 (0x40 );for (cfgi =0 , datai =0 ; cfgi < cfgn; cfgi++) {
@@ -359,7 +360,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,struct image_cfg_element *e, *binarye;struct main_hdr_v1 *main_hdr;size_t headersz; -void *image, *cur; +uint8_t *image, *cur;int hasext =0 ;int ret;
@@ -379,8 +380,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,memset (image,0 , headersz); - cur = main_hdr = image; - cur +=sizeof (struct main_hdr_v1 ); + main_hdr = (struct main_hdr_v1 *)image; + cur = image +sizeof (struct main_hdr_v1 );/* Fill the main header */ main_hdr->blocksize =
@@ -405,7 +406,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, binarye =image_find_option (IMAGE_CFG_BINARY );if (binarye) { -struct opt_hdr_v1 *hdr = cur; +struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;uint32_t *args;size_t binhdrsz;struct stat s;
@@ -438,7 +439,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, cur +=sizeof (struct opt_hdr_v1 ); - args = cur; + args = (uint32_t *)cur; *args =cpu_to_le32 (binarye->binary.nargs); args++;for (argi =0 ; argi < binarye->binary.nargs; argi++)
@@ -780,7 +781,7 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,struct ext_hdr_v0 *ext_hdr;uint8_t checksum; - main_hdr = (void *)ptr; + main_hdr = (struct main_hdr_v0 *)ptr; checksum =image_checksum8 (ptr,sizeof (struct main_hdr_v0 ) -sizeof (uint8_t ));
@@ -789,7 +790,8 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,/* Only version 0 extended header has checksum */ if (image_version ((void *)ptr) ==0 ) { - ext_hdr = (void *)ptr +sizeof (struct main_hdr_v0 ); + ext_hdr = (struct ext_hdr_v0 *) + (ptr +sizeof (struct main_hdr_v0 )); checksum =image_checksum8 (ext_hdr,sizeof (struct ext_hdr_v0 ) -sizeof (uint8_t ));
Signature · 1 line
2.9.0
PATCH 11/17 tools: kwbimage: Reduce scope of variables
In reply to Mario SixThis patch reduces the scope of some variables.
--- tools/kwbimage.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
tools/kwbimage.c +5 -4
@@ -204,7 +204,6 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,struct image_cfg_element *e;size_t headersz;struct main_hdr_v0 *main_hdr; -struct ext_hdr_v0 *ext_hdr;uint8_t *image;int has_ext =0 ;
@@ -256,6 +255,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,/* Generate the ext header */ if (has_ext) { +struct ext_hdr_v0 *ext_hdr;int cfgi, datai; ext_hdr = (struct ext_hdr_v0 *)
@@ -287,7 +287,6 @@ static size_t image_headersz_v1(struct image_tool_params *params, {struct image_cfg_element *binarye;size_t headersz; -int ret;/* * Calculate the size of the header and the size of the
@@ -307,6 +306,7 @@ static size_t image_headersz_v1(struct image_tool_params *params, binarye =image_find_option (IMAGE_CFG_BINARY );if (binarye) { +int ret;struct stat s; ret =stat (binarye->binary.file, &s);
@@ -362,7 +362,6 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,size_t headersz;uint8_t *image, *cur;int hasext =0 ; -int ret;/* * Calculate the size of the header and the size of the
@@ -412,6 +411,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,struct stat s;int argi;FILE *bin; +int ret; hdr->headertype =OPT_HDR_V1_BINARY_TYPE ;
@@ -778,7 +778,6 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) {struct main_hdr_v0 *main_hdr; -struct ext_hdr_v0 *ext_hdr;uint8_t checksum; main_hdr = (struct main_hdr_v0 *)ptr;
@@ -790,6 +789,8 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,/* Only version 0 extended header has checksum */ if (image_version ((void *)ptr) ==0 ) { +struct ext_hdr_v0 *ext_hdr; + ext_hdr = (struct ext_hdr_v0 *) (ptr +sizeof (struct main_hdr_v0 )); checksum = image_checksum8(ext_hdr,
Signature · 1 line
2.9.0
PATCH 12/17 tools: kwbimage: Remove unused parameter
In reply to Mario SixThe parameter 'params' of the image_headersz_v1 function is never used by the function.
Hence, remove it.
--- tools/kwbimage.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
tools/kwbimage.c +3 -4
@@ -282,8 +282,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,return image; } -static size_t image_headersz_v1 (struct image_tool_params *params, -int *hasext) +static size_t image_headersz_v1 (int *hasext) {struct image_cfg_element *binarye;size_t headersz;
@@ -367,7 +366,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,* Calculate the size of the header and the size of the * payload */ - headersz =image_headersz_v1 (params, &hasext); + headersz =image_headersz_v1 (&hasext);if (headersz ==0 )return NULL ;
@@ -815,7 +814,7 @@ static int kwbimage_generate(struct image_tool_params *params, alloc_len =sizeof (struct main_hdr_v0 ) +sizeof (struct ext_hdr_v0 ); }else { - alloc_len =image_headersz_v1 (params,NULL ); + alloc_len =image_headersz_v1 (NULL ); } hdr =malloc (alloc_len);
Signature · 1 line
2.9.0
PATCH 13/17 tools: kwbimage: Factor out add_binary_header_v1
In reply to Mario SixIn preparation of adding the creation of secure headers, we factor the add_binary_header_v1 function out of the image_create_v1 function.
--- tools/kwbimage.c | 146 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 67 deletions(-)
tools/kwbimage.c +79 -67
@@ -343,6 +343,7 @@ static size_t image_headersz_v1(int *hasext)fprintf (stderr,"Increase CONFIG_SYS_U_BOOT_OFFS!\n" ); return 0; } + headersz =CONFIG_SYS_U_BOOT_OFFS ;#endif
@@ -353,10 +354,85 @@ static size_t image_headersz_v1(int *hasext)return ALIGN_SUP (headersz,4096 ); } +int add_binary_header_v1 (uint8_t *cur) +{ +struct image_cfg_element *binarye; +struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur; +uint32_t *args; +size_t binhdrsz; +struct stat s; +int argi; +FILE *bin; +int ret; + + binarye =image_find_option (IMAGE_CFG_BINARY ); + +if (!binarye) +return 0 ; + + hdr->headertype =OPT_HDR_V1_BINARY_TYPE ; + + bin =fopen (binarye->binary.file,"r" ); +if (!bin) { +fprintf (stderr,"Cannot open binary file %s\n" , + binarye->binary.file); +return -1 ; + } + +fstat (fileno (bin), &s); + + binhdrsz =sizeof (struct opt_hdr_v1 ) + + (binarye->binary.nargs +2 ) *sizeof (uint32_t ) + + s.st_size; + +/* +* The size includes the binary image size, rounded +* up to a 4-byte boundary. Plus 4 bytes for the +* next-header byte and 3-byte alignment at the end. +*/ + binhdrsz =ALIGN_SUP (binhdrsz,4 ) +4 ; + hdr->headersz_lsb =cpu_to_le16 (binhdrsz &0xFFFF ); + hdr->headersz_msb = (binhdrsz &0xFFFF0000 ) >>16 ; + + cur +=sizeof (struct opt_hdr_v1 ); + + args = (uint32_t *)cur; + *args =cpu_to_le32 (binarye->binary.nargs); + args++; +for (argi =0 ; argi < binarye->binary.nargs; argi++) + args[argi] =cpu_to_le32 (binarye->binary.args[argi]); + + cur += (binarye->binary.nargs +1 ) *sizeof (uint32_t ); + + ret =fread (cur, s.st_size,1 , bin); +if (ret !=1 ) { +fprintf (stderr, +"Could not read binary image %s\n" , + binarye->binary.file); +return -1 ; + } + +fclose (bin); + + cur +=ALIGN_SUP (s.st_size,4 ); + +/* +* For now, we don't support more than one binary +* header, and no other header types are +* supported. So, the binary header is necessarily the +* last one +*/ + *((uint32_t *)cur) =0x00000000 ; + + cur +=sizeof (uint32_t ); + +return 0 ; +} +static void *image_create_v1 (size_t *imagesz,struct image_tool_params *params,int payloadsz) { -struct image_cfg_element *e, *binarye; +struct image_cfg_element *e;struct main_hdr_v1 *main_hdr;size_t headersz;uint8_t *image, *cur;
@@ -402,72 +478,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,if (e) main_hdr->nandbadblklocation = e->nandbadblklocation; - binarye =image_find_option (IMAGE_CFG_BINARY ); -if (binarye) { -struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur; -uint32_t *args; -size_t binhdrsz; -struct stat s; -int argi; -FILE *bin; -int ret; - - hdr->headertype =OPT_HDR_V1_BINARY_TYPE ; - - bin =fopen (binarye->binary.file,"r" ); -if (!bin) { -fprintf (stderr,"Cannot open binary file %s\n" , - binarye->binary.file); -return NULL ; - } - -fstat (fileno (bin), &s); - - binhdrsz =sizeof (struct opt_hdr_v1 ) + - (binarye->binary.nargs +2 ) *sizeof (uint32_t ) + - s.st_size; - -/* -* The size includes the binary image size, rounded -* up to a 4-byte boundary. Plus 4 bytes for the -* next-header byte and 3-byte alignment at the end. -*/ - binhdrsz =ALIGN_SUP (binhdrsz,4 ) +4 ; - hdr->headersz_lsb =cpu_to_le16 (binhdrsz &0xFFFF ); - hdr->headersz_msb = (binhdrsz &0xFFFF0000 ) >>16 ; - - cur +=sizeof (struct opt_hdr_v1 ); - - args = (uint32_t *)cur; - *args =cpu_to_le32 (binarye->binary.nargs); - args++; -for (argi =0 ; argi < binarye->binary.nargs; argi++) - args[argi] =cpu_to_le32 (binarye->binary.args[argi]); - - cur += (binarye->binary.nargs +1 ) *sizeof (uint32_t ); - - ret =fread (cur, s.st_size,1 , bin); -if (ret !=1 ) { -fprintf (stderr, -"Could not read binary image %s\n" , - binarye->binary.file); -return NULL ; - } - -fclose (bin); - - cur +=ALIGN_SUP (s.st_size,4 ); - -/* -* For now, we don't support more than one binary -* header, and no other header types are -* supported. So, the binary header is necessarily the -* last one -*/ - *((uint32_t *)cur) =0x00000000 ; - - cur +=sizeof (uint32_t ); - } +if (add_binary_header_v1 (cur)) +return NULL ;/* Calculate and set the header checksum */ main_hdr->checksum =image_checksum8 (main_hdr, headersz);
Signature · 1 line
2.9.0
PATCH 14/17 tools: kwbimage: Refactor line parsing and fix error
In reply to Mario SixThe function image_create_config_parse_oneline is pretty complex, and since more parameters will be added to support secure booting, we refactor the function to make it more readable.
Also, when a line contained just a keyword without any parameters, strtok_r returned NULL, which was then indiscriminately fed into atoi, causing a segfault. To correct this, we add a NULL check before feeding the extracted token to atoi, and print an error message in case the token is NULL.
--- tools/kwbimage.c | 157 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 96 insertions(+), 61 deletions(-)
tools/kwbimage.c +96 -61
@@ -55,20 +55,39 @@ struct nand_ecc_mode nand_ecc_modes[] = {#define BINARY_MAX_ARGS 8/* In-memory representation of a line of the configuration file */ + +enum image_cfg_type { +IMAGE_CFG_VERSION =0x1 , +IMAGE_CFG_BOOT_FROM , +IMAGE_CFG_DEST_ADDR , +IMAGE_CFG_EXEC_ADDR , +IMAGE_CFG_NAND_BLKSZ , +IMAGE_CFG_NAND_BADBLK_LOCATION , +IMAGE_CFG_NAND_ECC_MODE , +IMAGE_CFG_NAND_PAGESZ , +IMAGE_CFG_BINARY , +IMAGE_CFG_PAYLOAD , +IMAGE_CFG_DATA , + +IMAGE_CFG_COUNT +} type; + +static const char *const id_strs[] = { + [IMAGE_CFG_VERSION ] ="VERSION" , + [IMAGE_CFG_BOOT_FROM ] ="BOOT_FROM" , + [IMAGE_CFG_DEST_ADDR ] ="DEST_ADDR" , + [IMAGE_CFG_EXEC_ADDR ] ="EXEC_ADDR" , + [IMAGE_CFG_NAND_BLKSZ ] ="NAND_BLKSZ" , + [IMAGE_CFG_NAND_BADBLK_LOCATION ] ="NAND_BADBLK_LOCATION" , + [IMAGE_CFG_NAND_ECC_MODE ] ="NAND_ECC_MODE" , + [IMAGE_CFG_NAND_PAGESZ ] ="NAND_PAGE_SIZE" , + [IMAGE_CFG_BINARY ] ="BINARY" , + [IMAGE_CFG_PAYLOAD ] ="PAYLOAD" , + [IMAGE_CFG_DATA ] ="DATA" , +}; +struct image_cfg_element { -enum { -IMAGE_CFG_VERSION =0x1 , -IMAGE_CFG_BOOT_FROM , -IMAGE_CFG_DEST_ADDR , -IMAGE_CFG_EXEC_ADDR , -IMAGE_CFG_NAND_BLKSZ , -IMAGE_CFG_NAND_BADBLK_LOCATION , -IMAGE_CFG_NAND_ECC_MODE , -IMAGE_CFG_NAND_PAGESZ , -IMAGE_CFG_BINARY , -IMAGE_CFG_PAYLOAD , -IMAGE_CFG_DATA , - } type; +enum image_cfg_type type;union {unsigned int version;unsigned int bootfrom;
@@ -488,78 +507,94 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,return image; } +int recognize_keyword (char *keyword) +{ +int kw_id; + +for (kw_id =1 ; kw_id <IMAGE_CFG_COUNT ; ++kw_id) +if (!strcmp (keyword, id_strs[kw_id])) +return kw_id; + +return 0 ; +} +static int image_create_config_parse_oneline (char *line,struct image_cfg_element *el) { -char *keyword, *saveptr; -char deliminiters[] =" \t" ; +char *keyword, *saveptr, *value1, *value2; +char delimiters[] =" \t" ; +int keyword_id, ret, argi; +char *unknown_msg ="Ignoring unknown line '%s'\n" ; - keyword =strtok_r (line, deliminiters, &saveptr); -if (!strcmp (keyword,"VERSION" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); + keyword =strtok_r (line, delimiters, &saveptr); + keyword_id =recognize_keyword (keyword); - el->type =IMAGE_CFG_VERSION ; - el->version =atoi (value); - }else if (!strcmp (keyword,"BOOT_FROM" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); -int ret =image_boot_mode_id (value); +if (!keyword_id) { +fprintf (stderr, unknown_msg, line); +return 0 ; + } + + el->type = keyword_id; + + value1 =strtok_r (NULL , delimiters, &saveptr); + +if (!value1) { +fprintf (stderr,"Parameter missing in line '%s'\n" , line); +return -1 ; + } + +switch (keyword_id) { +case IMAGE_CFG_VERSION : + el->version =atoi (value1); +break ; +case IMAGE_CFG_BOOT_FROM : + ret =image_boot_mode_id (value1);if (ret <0 ) { -fprintf (stderr, -"Invalid boot media '%s'\n" , value); +fprintf (stderr,"Invalid boot media '%s'\n" , value1);return -1 ; } - el->type =IMAGE_CFG_BOOT_FROM ; el->bootfrom = ret; - }else if (!strcmp (keyword,"NAND_BLKSZ" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); - - el->type =IMAGE_CFG_NAND_BLKSZ ; - el->nandblksz =strtoul (value,NULL ,16 ); - }else if (!strcmp (keyword,"NAND_BADBLK_LOCATION" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); - - el->type =IMAGE_CFG_NAND_BADBLK_LOCATION ; - el->nandbadblklocation = -strtoul (value,NULL ,16 ); - }else if (!strcmp (keyword,"NAND_ECC_MODE" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); -int ret =image_nand_ecc_mode_id (value); +break ; +case IMAGE_CFG_NAND_BLKSZ : + el->nandblksz =strtoul (value1,NULL ,16 ); +break ; +case IMAGE_CFG_NAND_BADBLK_LOCATION : + el->nandbadblklocation =strtoul (value1,NULL ,16 ); +break ; +case IMAGE_CFG_NAND_ECC_MODE : + ret =image_nand_ecc_mode_id (value1);if (ret <0 ) { -fprintf (stderr, -"Invalid NAND ECC mode '%s'\n" , value); +fprintf (stderr,"Invalid NAND ECC mode '%s'\n" , value1);return -1 ; } - el->type =IMAGE_CFG_NAND_ECC_MODE ; el->nandeccmode = ret; - }else if (!strcmp (keyword,"NAND_PAGE_SIZE" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); - - el->type =IMAGE_CFG_NAND_PAGESZ ; - el->nandpagesz =strtoul (value,NULL ,16 ); - }else if (!strcmp (keyword,"BINARY" )) { -char *value =strtok_r (NULL , deliminiters, &saveptr); -int argi =0 ; +break ; +case IMAGE_CFG_NAND_PAGESZ : + el->nandpagesz =strtoul (value1,NULL ,16 ); +break ; +case IMAGE_CFG_BINARY : + argi =0 ; - el->type =IMAGE_CFG_BINARY ; - el->binary.file =strdup (value); + el->binary.file =strdup (value1);while (1 ) { - value =strtok_r (NULL , deliminiters, &saveptr); +char *value =strtok_r (NULL , delimiters, &saveptr); +if (!value)break ; el->binary.args[argi] =strtoul (value,NULL ,16 ); argi++;if (argi >=BINARY_MAX_ARGS ) {fprintf (stderr, -"Too many argument for binary\n" ); +"Too many arguments for BINARY\n" );return -1 ; } } el->binary.nargs = argi; - }else if (!strcmp (keyword,"DATA" )) { -char *value1 =strtok_r (NULL , deliminiters, &saveptr); -char *value2 =strtok_r (NULL , deliminiters, &saveptr); +break ; +case IMAGE_CFG_DATA : + value2 =strtok_r (NULL , delimiters, &saveptr);if (!value1 || !value2) { fprintf(stderr,
@@ -567,11 +602,11 @@ static int image_create_config_parse_oneline(char *line,return -1 ; } - el->type =IMAGE_CFG_DATA ; el->regdata.raddr =strtoul (value1,NULL ,16 ); el->regdata.rdata =strtoul (value2,NULL ,16 ); - }else { -fprintf (stderr,"Ignoring unknown line '%s'\n" , line); +break ; +default : +fprintf (stderr, unknown_msg, line); }return 0 ;
Signature · 1 line
2.9.0
PATCH 15/17 arm: mvebu: Implement secure boot
In reply to Mario SixThe patch implements secure booting for the mvebu architecture.
This includes:
- The addition of secure headers and all needed signatures and keys in mkimage
- Commands capable of writing the board's efuses to both write the needed cryptographic data and enable the secure booting mechanism
- The creation of convenience text files containing the necessary commands to write the efuses
The KAK and CSK keys are expected to reside in the files kwb_kak.key and kwb_csk.key (OpenSSL 2048 bit private keys) in the top-level directory.
--- Makefile | 3 +- arch/arm/mach-mvebu/Kconfig | 20 + arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/efuse.c | 293 ++++++++++++ arch/arm/mach-mvebu/include/mach/cpu.h | 2 + arch/arm/mach-mvebu/include/mach/efuse.h | 71 +++ tools/Makefile | 6 +- tools/kwbimage.c | 744 ++++++++++++++++++++++++++++++- tools/kwbimage.h | 37 ++ 9 files changed, 1169 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-mvebu/efuse.c create mode 100644 arch/arm/mach-mvebu/include/mach/efuse.h
Makefile +2 -1
@@ -938,7 +938,8 @@ MKIMAGEFLAGS_u-boot.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \ -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) MKIMAGEFLAGS_u-boot-spl.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \ - -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) + -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \ + $(if $(KEYDIR),-k $(KEYDIR)) MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \ -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage
arch/arm/mach-mvebu/Kconfig +20 -0
@@ -1,5 +1,9 @@ if ARCH_MVEBU +config HAVE_MVEBU_EFUSE + bool + default n + config ARMADA_32BIT bool select CPU_V7
@@ -21,6 +25,7 @@ config ARMADA_375 config ARMADA_38X bool select ARMADA_32BIT + select HAVE_MVEBU_EFUSE config ARMADA_XP bool
@@ -136,4 +141,19 @@ config SYS_VENDOR config SYS_SOC default "mvebu" +config MVEBU_EFUSE + bool "Enable eFuse support" + default n + depends on HAVE_MVEBU_EFUSE + +config MVEBU_EFUSE_FAKE + bool "Fake eFuse access (dry run)" + default n + depends on MVEBU_EFUSE + help + This enables a "dry run" mode where eFuses are not really programmed. + Instead the eFuse accesses are emulated by writing to and reading + from a memory block. + This is can be used for testing prog scripts. + endif
arch/arm/mach-mvebu/Makefile +1 -0
@@ -27,6 +27,7 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o endif # CONFIG_SPL_BUILD obj-y += gpio.o obj-y += mbus.o
arch/arm/mach-mvebu/efuse.c new file +293 -0
293 lines not on this page · raw message
arch/arm/mach-mvebu/include/mach/cpu.h +2 -0
@@ -36,7 +36,9 @@ enum cpu_target {CPU_TARGET_ETH01 =0x7 ,CPU_TARGET_PCIE13 =0x8 ,CPU_TARGET_SASRAM =0x9 , +CPU_TARGET_SATA01 =0xa ,/* A38X */ CPU_TARGET_NAND =0xd , + CPU_TARGET_SATA23_DFX = 0xe, /* A38X */ }; enum cpu_attrib {
arch/arm/mach-mvebu/include/mach/efuse.h new file +71 -0
71 lines not on this page · raw message
tools/Makefile +5 -1
@@ -141,8 +141,12 @@ ifdef CONFIG_SYS_U_BOOT_OFFS HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS) endif +ifneq ($(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),) +HOSTCFLAGS_kwbimage.o += -DCONFIG_KWB_SECURE +endif + # MXSImage needs LibSSL -ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),) +ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X)$(CONFIG_FIT_SIGNATURE),) HOSTLOADLIBES_mkimage += \ $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
tools/kwbimage.c +738 -6
847 lines not on this page · raw message
tools/kwbimage.h +37 -0
@@ -102,6 +102,43 @@ struct opt_hdr_v1 { };/* +* Public Key data in DER format +*/ +struct pubkey_der_v1 { +uint8_t key[524 ]; +}; + +/* +* Signature (RSA 2048) +*/ +struct sig_v1 { +uint8_t sig[256 ]; +}; + +/* +* Structure of secure header (Armada 38x) +*/ +struct secure_hdr_v1 { +uint8_t headertype;/* 0x0 */ +uint8_t headersz_msb;/* 0x1 */ +uint16_t headersz_lsb;/* 0x2 - 0x3 */ +uint32_t reserved1;/* 0x4 - 0x7 */ +struct pubkey_der_v1 kak;/* 0x8 - 0x213 */ +uint8_t jtag_delay;/* 0x214 */ +uint8_t reserved2;/* 0x215 */ +uint16_t reserved3;/* 0x216 - 0x217 */ +uint32_t boxid;/* 0x218 - 0x21B */ +uint32_t flashid;/* 0x21C - 0x21F */ +struct sig_v1 hdrsig;/* 0x220 - 0x31F */ +struct sig_v1 imgsig;/* 0x320 - 0x41F */ +struct pubkey_der_v1 csk[16 ];/* 0x420 - 0x24DF */ +struct sig_v1 csksig;/* 0x24E0 - 0x25DF */ +uint8_t next;/* 0x25E0 */ +uint8_t reserved4;/* 0x25E1 */ +uint16_t reserved5;/* 0x25E2 - 0x25E3 */ +}; + +/* * Various values for the opt_hdr_v1->headertype field, describing the * different types of optional headers. The "secure" header contains * informations related to secure boot (encryption keys, etc.). The
Signature · 1 line
2.9.0
PATCH 15/17 arm: mvebu: Implement secure boot
Quoted 10 lines · Mario Six
The patch implements secure booting for the mvebu architecture.
This includes:
- The addition of secure headers and all needed signatures and keys in mkimage
- Commands capable of writing the board's efuses to both write the needed cryptographic data and enable the secure booting mechanism
- The creation of convenience text files containing the necessary commands to write the efuses
Quoted 5 lines
The KAK and CSK keys are expected to reside in the files kwb_kak.key and kwb_csk.key (OpenSSL 2048 bit private keys) in the top-level directory.
Signed-off-by Reinhard Pfau <[email protected]>Signed-off-by Mario Six <[email protected]>
Thanks Mario, I have to admit that I'm pretty new to this secure booting support on A38x. So I can't really comment much on the technical details. I would very much like to see some documentation being added for this secure boot support on A38x (doc/...). With a more detailed explanation of this procedure and best one exmaple on how this is done in practice.
Please find some more comments below.
Quoted 43 lines
--- Makefile | 3 +- arch/arm/mach-mvebu/Kconfig | 20 + arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/efuse.c | 293 ++++++++++++ arch/arm/mach-mvebu/include/mach/cpu.h | 2 + arch/arm/mach-mvebu/include/mach/efuse.h | 71 +++ tools/Makefile | 6 +- tools/kwbimage.c | 744 ++++++++++++++++++++++++++++++- tools/kwbimage.h | 37 ++ 9 files changed, 1169 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-mvebu/efuse.c create mode 100644 arch/arm/mach-mvebu/include/mach/efuse.hMakefile +2
-1@@ -938,7 +938,8 @@ MKIMAGEFLAGS_u-boot.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \ -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) MKIMAGEFLAGS_u-boot-spl.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \ - -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) + -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \ + $(if $(KEYDIR),-k $(KEYDIR)) MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \ -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimagearch/arm/mach-mvebu/Kconfig +4
-0@@ -1,5 +1,9 @@ if ARCH_MVEBU +config HAVE_MVEBU_EFUSE + bool + default n + config ARMADA_32BIT bool select CPU_V7
arch/arm/mach-mvebu/Kconfig config ARMADA_375 · line 28
Quoted 4 lines
arch/arm/mach-mvebu/Kconfig +1
-0@@ -21,6 +25,7 @@ config ARMADA_375 config ARMADA_38X bool select ARMADA_32BIT + select HAVE_MVEBU_EFUSE
Do you know if this secure boot support provided in this patch (and the one before it) also supports the Armada XP SoCs?
arch/arm/mach-mvebu/Kconfig config SYS_VENDOR · line 147
Quoted 10 lines
arch/arm/mach-mvebu/Kconfig +4
-0config ARMADA_XP bool@@ -136,4 +141,19 @@ config SYS_VENDOR config SYS_SOC default "mvebu" +config MVEBU_EFUSE + bool "Enable eFuse support" + default n + depends on HAVE_MVEBU_EFUSE
Is this Kconfig option enabled in your board support patch? I can't find it there. And could you please add a help text to this option as well?
Quoted 35 lines
arch/arm/mach-mvebu/Kconfig +10
-0+config MVEBU_EFUSE_FAKE + bool "Fake eFuse access (dry run)" + default n + depends on MVEBU_EFUSE + help + This enables a "dry run" mode where eFuses are not really programmed. + Instead the eFuse accesses are emulated by writing to and reading + from a memory block. + This is can be used for testing prog scripts. + endifarch/arm/mach-mvebu/Makefile +1
-0@@ -27,6 +27,7 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o endif # CONFIG_SPL_BUILD obj-y += gpio.o obj-y += mbus.oarch/arm/mach-mvebu/efuse.c new file +6
-0@@ -0,0 +1,293 @@ +/* +* Copyright (C) 2015-2016 Reinhard Pfau <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +
arch/arm/mach-mvebu/efuse.c line 16
Quoted 10 lines
arch/arm/mach-mvebu/efuse.c new file +10
-0+#include <config.h> +#include <common.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/efuse.h> +#include <asm/arch/soc.h> +#include <linux/mbus.h> + +#if defined(CONFIG_MVEBU_EFUSE )
This check should not be needed, as this file only gets compiled if CONFIG_MVEBU_EFUSE is defined.
Quoted 44 lines
arch/arm/mach-mvebu/efuse.c new file +44
-0+ +#if defined(CONFIG_MVEBU_EFUSE_FAKE ) +#define DRY_RUN +#else +#undef DRY_RUN +#endif + +#define MBUS_EFUSE_BASE 0xF6000000 +#define MBUS_EFUSE_SIZE BIT(20) + +#define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008)) + +enum { +MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 <<31 ), +}; + +struct mvebu_hd_efuse { +u32 bits_31_0; +u32 bits_63_32; +u32 bit64; +u32 reserved0; +}; + +#ifndef DRY_RUN +static struct mvebu_hd_efuse *efuses = + (struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE +0xF9000 ); +#else +static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX +1 ]; +#endif + +static int efuse_initialised; + +static struct mvebu_hd_efuse *get_efuse_line (int nr) +{ +if (nr <0 || nr >63 || !efuse_initialised) +return NULL ; + +return efuses + nr; +} + +static void enable_efuse_program (void ) +{ +#ifndef DRY_RUN +setbits_le32 (MVEBU_EFUSE_CONTROL ,MVEBU_EFUSE_CTRL_PROGRAM_ENABLE );
arch/arm/mach-mvebu/efuse.c line 70
Quoted 10 lines
arch/arm/mach-mvebu/efuse.c new file +10
-0+#endif +} + +static void disable_efuse_program (void ) +{ +#ifndef DRY_RUN +u32 reg =readl (MVEBU_EFUSE_CONTROL ); + + reg &= ~MVEBU_EFUSE_CTRL_PROGRAM_ENABLE ; +writel (MVEBU_EFUSE_CONTROL , reg);
clrbits_le32() please.
Quoted 228 lines
arch/arm/mach-mvebu/efuse.c new file +223
-0+#endif +} + +static int do_prog_efuse (struct mvebu_hd_efuse *efuse, +struct efuse_val *new_val,u32 mask0,u32 mask1) +{ +struct efuse_val val; + + val.dwords.d[0 ] =readl (&efuse->bits_31_0); + val.dwords.d[1 ] =readl (&efuse->bits_63_32); + val.lock =readl (&efuse->bit64); + +if (val.lock &1 ) +return -EPERM ; + + val.dwords.d[0 ] |= (new_val->dwords.d[0 ] & mask0); + val.dwords.d[1 ] |= (new_val->dwords.d[1 ] & mask1); + val.lock |= new_val->lock; + +writel (val.dwords.d[0 ], &efuse->bits_31_0); +mdelay (1 ); +writel (val.dwords.d[1 ], &efuse->bits_63_32); +mdelay (1 ); +writel (val.lock, &efuse->bit64); +mdelay (5 ); + +return 0 ; +} + +static int prog_efuse (int nr,struct efuse_val *new_val,u32 mask0,u32 mask1) +{ +struct mvebu_hd_efuse *efuse; +int res =0 ; + + res =mvebu_efuse_init_hw (); +if (res) +return res; + + efuse =get_efuse_line (nr); +if (!efuse) +return -ENODEV ; + +if (!new_val) +return -EINVAL ; + +/* only write a fuse line with lock bit */ +if (!new_val->lock) +return -EINVAL ; + +/* according to specs ECC protection bits must be 0 on write */ +if (new_val->bytes.d[7 ] &0xFE ) +return -EINVAL ; + +if (!new_val->dwords.d[0 ] && !new_val->dwords.d[1 ] && (mask0 | mask1)) +return 0 ; + +enable_efuse_program (); + + res =do_prog_efuse (efuse, new_val, mask0, mask1); + +disable_efuse_program (); + +return res; +} + +int mvebu_efuse_init_hw (void ) +{ +int ret; + +if (efuse_initialised) +return 0 ; + + ret =mvebu_mbus_add_window_by_id ( +CPU_TARGET_SATA23_DFX ,0xA ,MBUS_EFUSE_BASE ,MBUS_EFUSE_SIZE ); + +if (ret) +return ret; + + efuse_initialised =1 ; + +return 0 ; +} + +int mvebu_read_efuse (int nr,struct efuse_val *val) +{ +struct mvebu_hd_efuse *efuse; +int res; + + res =mvebu_efuse_init_hw (); +if (res) +return res; + + efuse =get_efuse_line (nr); +if (!efuse) +return -ENODEV ; + +if (!val) +return -EINVAL ; + + val->dwords.d[0 ] =readl (&efuse->bits_31_0); + val->dwords.d[1 ] =readl (&efuse->bits_63_32); + val->lock =readl (&efuse->bit64); +return 0 ; +} + +int mvebu_write_efuse (int nr,struct efuse_val *val) +{ +return prog_efuse (nr, val, ~0 , ~0 ); +} + +int mvebu_lock_efuse (int nr) +{ +struct efuse_val val = { + .lock =1 , + }; + +return prog_efuse (nr, &val,0 ,0 ); +} + +#else + +int mvebu_efuse_init_hw (void ) +{ +return -ENODEV ; +} + +int mvebu_read_efuse (int nr,struct efuse_val *val) +{ +return -ENODEV ; +} + +int mvebu_write_efuse (int nr,struct efuse_val *val) +{ +return -ENODEV ; +} + +int mvebu_lock_efuse (int nr) +{ +return -ENODEV ; +} + +#endif + +/* +* wrapper funcs providing the fuse API +* +* we use the following mapping: +* "bank" -> eFuse line +* "word" -> 0: bits 0-31 +* 1: bits 32-63 +* 2: bit 64 (lock) +*/ + +static struct efuse_val prog_val; +static int valid_prog_words; + +int fuse_read (u32 bank,u32 word,u32 *val) +{ +struct efuse_val fuse_line; +int res; + +if (bank <EFUSE_LINE_MIN || bank >EFUSE_LINE_MAX || word >2 ) +return -EINVAL ; + + res =mvebu_read_efuse (bank, &fuse_line); +if (res) +return res; + +if (word <2 ) + *val = fuse_line.dwords.d[word]; +else + *val = fuse_line.lock; + +return res; +} + +int fuse_sense (u32 bank,u32 word,u32 *val) +{ +/* not supported */ +return -ENOSYS ; +} + +int fuse_prog (u32 bank,u32 word,u32 val) +{ +int res =0 ; + +/* +* NOTE: Fuse line should be written as whole. +* So how can we do that with this API? +* For now: remember values for word == 0 and word == 1 and write the +* whole line when word == 2. +* This implies that we always require all 3 fuse prog cmds (one for +* for each word) to write a single fuse line. +* Exception is a single write to word 2 which will lock the fuse line. +* +* Hope that will be OK. +*/ + +if (bank <EFUSE_LINE_MIN || bank >EFUSE_LINE_MAX || word >2 ) +return -EINVAL ; + +if (word <2 ) { + prog_val.dwords.d[word] = val; + valid_prog_words |= (1 << word); + }else if ((valid_prog_words &3 ) ==0 && val) { + res =mvebu_lock_efuse (bank); + valid_prog_words =0 ; + }else if ((valid_prog_words &3 ) !=3 || !val) { + res = -EINVAL ; + }else { + prog_val.lock = val !=0 ; + res =mvebu_write_efuse (bank, &prog_val); + valid_prog_words =0 ; + } + +return res; +} + +int fuse_override (u32 bank,u32 word,u32 val) +{ +/* not supported */ +return -ENOSYS ; +}arch/arm/mach-mvebu/include/mach/cpu.h +0
-0
arch/arm/mach-mvebu/include/mach/cpu.h enum cpu_target { · line 42
Quoted 7 lines
arch/arm/mach-mvebu/include/mach/cpu.h +2
-0@@ -36,7 +36,9 @@ enum cpu_target {CPU_TARGET_ETH01 =0x7 ,CPU_TARGET_PCIE13 =0x8 ,CPU_TARGET_SASRAM =0x9 , +CPU_TARGET_SATA01 =0xa ,/* A38X */ CPU_TARGET_NAND =0xd , + CPU_TARGET_SATA23_DFX = 0xe, /* A38X */ };
This looks like an unrelated change, perhaps better moved into a separate patch?
arch/arm/mach-mvebu/include/mach/efuse.h line 2
Quoted 10 lines
arch/arm/mach-mvebu/include/mach/cpu.h +0
-0enum cpu_attrib {arch/arm/mach-mvebu/include/mach/efuse.h new file +2
-0@@ -0,0 +1,71 @@ +/* +* Copyright (C) 2015 Reinhard Pfau <[email protected]>
Only 2015? This might need to get changed in more files, I didn't check closely.
Quoted 58 lines
arch/arm/mach-mvebu/include/mach/efuse.h new file +58
-0+* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _MVEBU_EFUSE_H +#define _MVEBU_EFUSE_H + +#include <common.h> + +struct efuse_val { +union { +struct { +u8 d[8 ]; + } bytes; +struct { +u16 d[4 ]; + } words; +struct { +u32 d[2 ]; + } dwords; + }; +u32 lock; +}; + +#if defined(CONFIG_ARMADA_38X ) + +enum efuse_line { +EFUSE_LINE_SECURE_BOOT =24 , +EFUSE_LINE_PUBKEY_DIGEST_0 =26 , +EFUSE_LINE_PUBKEY_DIGEST_1 =27 , +EFUSE_LINE_PUBKEY_DIGEST_2 =28 , +EFUSE_LINE_PUBKEY_DIGEST_3 =29 , +EFUSE_LINE_PUBKEY_DIGEST_4 =30 , +EFUSE_LINE_CSK_0_VALID =31 , +EFUSE_LINE_CSK_1_VALID =32 , +EFUSE_LINE_CSK_2_VALID =33 , +EFUSE_LINE_CSK_3_VALID =34 , +EFUSE_LINE_CSK_4_VALID =35 , +EFUSE_LINE_CSK_5_VALID =36 , +EFUSE_LINE_CSK_6_VALID =37 , +EFUSE_LINE_CSK_7_VALID =38 , +EFUSE_LINE_CSK_8_VALID =39 , +EFUSE_LINE_CSK_9_VALID =40 , +EFUSE_LINE_CSK_10_VALID =41 , +EFUSE_LINE_CSK_11_VALID =42 , +EFUSE_LINE_CSK_12_VALID =43 , +EFUSE_LINE_CSK_13_VALID =44 , +EFUSE_LINE_CSK_14_VALID =45 , +EFUSE_LINE_CSK_15_VALID =46 , +EFUSE_LINE_FLASH_ID =47 , +EFUSE_LINE_BOX_ID =48 , + +EFUSE_LINE_MIN =0 , +EFUSE_LINE_MAX =63 , +}; + +#endif +
arch/arm/mach-mvebu/include/mach/efuse.h line 70
Quoted 10 lines
arch/arm/mach-mvebu/include/mach/efuse.h new file +10
-0+ +int mvebu_efuse_init_hw (void ); + +int mvebu_read_efuse (int nr,struct efuse_val *val); + +int mvebu_write_efuse (int nr,struct efuse_val *val); + +int mvebu_lock_efuse (int nr); + +
Double empty line not needed.
Quoted 921 lines
arch/arm/mach-mvebu/include/mach/efuse.h new file +1
-0+#endif tools/Makefile +5
-1@@ -141,8 +141,12 @@ ifdef CONFIG_SYS_U_BOOT_OFFS HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS) endif +ifneq ($(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),) +HOSTCFLAGS_kwbimage.o += -DCONFIG_KWB_SECURE +endif + # MXSImage needs LibSSL -ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),) +ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X)$(CONFIG_FIT_SIGNATURE),) HOSTLOADLIBES_mkimage += \ $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")tools/kwbimage.c +738
-6@@ -1,30 +1,47 @@/* * Image manipulator for Marvell SoCs -* supports Kirkwood, Dove, Armada 370, and Armada XP +* supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x * * (C) Copyright 2013 Thomas Petazzoni * <[email protected]> * * SPDX-License-Identifier: GPL-2.0+ * -* Not implemented: support for the register headers and secure -* headers in v1 images +* Not implemented: support for the register headers in v1 images */ #include "imagetool.h" #include <limits.h> #include <image.h> +#include <stdarg.h> #include <stdint.h> #include "kwbimage.h" +#ifdef CONFIG_KWB_SECURE +#include <openssl/rsa.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#endif +static struct image_cfg_element *image_cfg;static int cfgn; +#ifdef CONFIG_KWB_SECURE +static int verbose_mode; +#endif struct boot_mode {unsigned int id;const char *name; }; +/* +* SHA2-256 hash +*/ +struct hash_v1 { +uint8_t hash[32 ]; +}; +struct boot_mode boot_modes[] = { {0x4D ,"i2c" }, {0x5A ,"spi" },@@ -68,6 +85,16 @@ enum image_cfg_type {IMAGE_CFG_BINARY ,IMAGE_CFG_PAYLOAD ,IMAGE_CFG_DATA , +IMAGE_CFG_KAK , +IMAGE_CFG_CSK , +IMAGE_CFG_CSK_INDEX , +IMAGE_CFG_JTAG_DELAY , +IMAGE_CFG_BOX_ID , +IMAGE_CFG_FLASH_ID , +IMAGE_CFG_SEC_COMMON_IMG , +IMAGE_CFG_SEC_SPECIALIZED_IMG , +IMAGE_CFG_SEC_BOOT_DEV , +IMAGE_CFG_SEC_FUSE_DUMP ,IMAGE_CFG_COUNT } type;@@ -84,6 +111,16 @@ static const char * const id_strs[] = { [IMAGE_CFG_BINARY] = "BINARY", [IMAGE_CFG_PAYLOAD] = "PAYLOAD", [IMAGE_CFG_DATA] = "DATA", + [IMAGE_CFG_KAK] = "KAK", + [IMAGE_CFG_CSK] = "CSK", + [IMAGE_CFG_CSK_INDEX] = "CSK_INDEX", + [IMAGE_CFG_JTAG_DELAY] = "JTAG_DELAY", + [IMAGE_CFG_BOX_ID] = "BOX_ID", + [IMAGE_CFG_FLASH_ID] = "FLASH_ID", + [IMAGE_CFG_SEC_COMMON_IMG] = "SEC_COMMON_IMG", + [IMAGE_CFG_SEC_SPECIALIZED_IMG] = "SEC_SPECIALIZED_IMG", + [IMAGE_CFG_SEC_BOOT_DEV] = "SEC_BOOT_DEV", + [IMAGE_CFG_SEC_FUSE_DUMP ] ="SEC_FUSE_DUMP" };struct image_cfg_element {@@ -104,6 +141,14 @@ struct image_cfg_element {unsigned int nandeccmode;unsigned int nandpagesz;struct ext_hdr_v0_reg regdata; +const char *key_name; +int csk_idx; +uint8_t jtag_delay; +uint32_t boxid; +uint32_t flashid; +bool sec_specialized_img; +unsigned int sec_boot_dev; +const char *name; }; };@@ -172,6 +217,32 @@ image_count_options(unsigned int optiontype)return count; } +#if defined(CONFIG_KWB_SECURE ) + +static int image_get_csk_index (void ) +{ +struct image_cfg_element *e; + + e =image_find_option (IMAGE_CFG_CSK_INDEX ); +if (!e) +return -1 ; + +return e->csk_idx; +} + +static bool image_get_spezialized_img (void ) +{ +struct image_cfg_element *e; + + e =image_find_option (IMAGE_CFG_SEC_SPECIALIZED_IMG ); +if (!e) +return false; + +return e->sec_specialized_img; +} + +#endif +/* * Compute a 8-bit checksum of a memory area. This algorithm follows * the requirements of the Marvell SoC BootROM specifications. @@ -217,6 +288,493 @@ static uint32_t image_checksum32(void *start, uint32_t len)return csum; } +#if defined(CONFIG_KWB_SECURE ) +static void kwb_msg (const char *fmt, ...) +{ +if (verbose_mode) { +va_list ap; + +va_start (ap, fmt); +vfprintf (stdout, fmt, ap); +va_end (ap); + } +} + +static int openssl_err (const char *msg) +{ +unsigned long ssl_err =ERR_get_error (); + +fprintf (stderr,"%s" , msg); +fprintf (stderr,": %s\n" , +ERR_error_string (ssl_err,0 )); + +return -1 ; +} + +static int kwb_load_rsa_key (const char *keydir,const char *name,RSA **p_rsa) +{ +char path[PATH_MAX ]; +RSA *rsa; +FILE *f; + +if (!keydir) + keydir ="." ; + +snprintf (path,sizeof (path),"%s/%s.key" , keydir, name); + f =fopen (path,"r" ); +if (!f) { +fprintf (stderr,"Couldn't open RSA private key: '%s': %s\n" , + path,strerror (errno)); +return -ENOENT ; + } + + rsa =PEM_read_RSAPrivateKey (f,0 ,NULL ,"" ); +if (!rsa) { +openssl_err ("Failure reading private key" ); +fclose (f); +return -EPROTO ; + } +fclose (f); + *p_rsa = rsa; + +return 0 ; +} + +static int kwb_load_cfg_key (struct image_tool_params *params, +unsigned int cfg_option,const char *key_name, +RSA **p_key) +{ +struct image_cfg_element *e_key; +RSA *key; +int res; + + *p_key =NULL ; + + e_key =image_find_option (cfg_option); +if (!e_key) { +fprintf (stderr,"%s not configured\n" , key_name); +return -ENOENT ; + } + + res =kwb_load_rsa_key (params->keydir, e_key->key_name, &key); +if (res <0 ) { +fprintf (stderr,"Failed to load %s\n" , key_name); +return -ENOENT ; + } + + *p_key = key; + +return 0 ; +} + +static int kwb_load_kak (struct image_tool_params *params,RSA **p_kak) +{ +return kwb_load_cfg_key (params,IMAGE_CFG_KAK ,"KAK" , p_kak); +} + +static int kwb_load_csk (struct image_tool_params *params,RSA **p_csk) +{ +return kwb_load_cfg_key (params,IMAGE_CFG_CSK ,"CSK" , p_csk); +} + +static int kwb_compute_pubkey_hash (struct pubkey_der_v1 *pk, +struct hash_v1 *hash) +{ +EVP_MD_CTX *ctx; +unsigned int key_size; +unsigned int hash_size; +int ret =0 ; + +if (!pk || !hash || pk->key[0 ] !=0x30 || pk->key[1 ] !=0x82 ) +return -EINVAL ; + + key_size = (pk->key[2 ] <<8 ) + pk->key[3 ] +4 ; + + ctx =EVP_MD_CTX_create (); +if (!ctx) +return openssl_err ("EVP context creation failed" ); + +EVP_MD_CTX_init (ctx); +if (!EVP_DigestInit (ctx,EVP_sha256 ())) { + ret =openssl_err ("Digest setup failed" ); + goto hash_err_ctx; + } + +if (!EVP_DigestUpdate (ctx, pk->key, key_size)) { + ret =openssl_err ("Hashing data failed" ); + goto hash_err_ctx; + } + +if (!EVP_DigestFinal (ctx, hash->hash, &hash_size)) { + ret =openssl_err ("Could not obtain hash" ); + goto hash_err_ctx; + } + +EVP_MD_CTX_cleanup (ctx); + +hash_err_ctx: +EVP_MD_CTX_destroy (ctx); +return ret; +} + +static int kwb_import_pubkey (RSA **key,struct pubkey_der_v1 *src,char *keyname) +{ +RSA *rsa; +const unsigned char *ptr; + +if (!key || !src) + goto fail; + + ptr = src->key; + rsa =d2i_RSAPublicKey (key, &ptr,sizeof (src->key)); +if (!rsa) { +openssl_err ("error decoding public key" ); + goto fail; + } + +return 0 ; +fail: +fprintf (stderr,"Failed to decode %s pubkey\n" , keyname); +return -EINVAL ; +} + +static int kwb_export_pubkey (RSA *key,struct pubkey_der_v1 *dst,FILE *hashf, +char *keyname) +{ +int size_exp, size_mod, size_seq; +uint8_t *cur; +char *errmsg ="Failed to encode %s\n" ; + +if (!key || !key->e || !key->n || !dst) { +fprintf (stderr,"export pk failed: (%p, %p, %p, %p)" , + key, key->e, key->n, dst); +fprintf (stderr, errmsg, keyname); +return -EINVAL ; + } + +/* +* According to the specs, the key should be PKCS#1 DER encoded. +* But unfortunately the really required encoding seems to be different; +* it violates DER...! (But it still conformes to BER.) +* (Length always in long form w/ 2 byte length code; no leading zero +* when MSB of first byte is set...) +* So we cannot use the encoding func provided by OpenSSL and have to +* do the encoding manually. +*/ + + size_exp =BN_num_bytes (key->e); + size_mod =BN_num_bytes (key->n); + size_seq =4 + size_mod +4 + size_exp; + +if (size_mod >256 ) { +fprintf (stderr,"export pk failed: wrong mod size: %d\n" , + size_mod); +fprintf (stderr, errmsg, keyname); +return -EINVAL ; + } + +if (4 + size_seq >sizeof (dst->key)) { +fprintf (stderr,"export pk failed: seq too large (%d, %lu)\n" , +4 + size_seq,sizeof (dst->key)); +fprintf (stderr, errmsg, keyname); +return -ENOBUFS ; + } + + cur = dst->key; + +/* PKCS#1 (RFC3447) RSAPublicKey structure */ + *cur++ =0x30 ;/* SEQUENCE */ + *cur++ =0x82 ; + *cur++ = (size_seq >>8 ) &0xFF ; + *cur++ = size_seq &0xFF ; +/* Modulus */ + *cur++ =0x02 ;/* INTEGER */ + *cur++ =0x82 ; + *cur++ = (size_mod >>8 ) &0xFF ; + *cur++ = size_mod &0xFF ; +BN_bn2bin (key->n, cur); + cur += size_mod; +/* Exponent */ + *cur++ =0x02 ;/* INTEGER */ + *cur++ =0x82 ; + *cur++ = (size_exp >>8 ) &0xFF ; + *cur++ = size_exp &0xFF ; +BN_bn2bin (key->e, cur); + +if (hashf) { +struct hash_v1 pk_hash; +int i; +int ret =0 ; + + ret =kwb_compute_pubkey_hash (dst, &pk_hash); +if (ret <0 ) { +fprintf (stderr, errmsg, keyname); +return ret; + } + +fprintf (hashf,"SHA256 = " ); +for (i =0 ; i <sizeof (pk_hash.hash); ++i) +fprintf (hashf,"%02X" , pk_hash.hash[i]); +fprintf (hashf,"\n" ); + } + +return 0 ; +} + +int kwb_sign (RSA *key,void *data,int datasz,struct sig_v1 *sig,char *signame) +{ +EVP_PKEY *evp_key; +EVP_MD_CTX *ctx; +unsigned int sig_size; +int size; +int ret =0 ; + + evp_key =EVP_PKEY_new (); +if (!evp_key) +return openssl_err ("EVP_PKEY object creation failed" ); + +if (!EVP_PKEY_set1_RSA (evp_key, key)) { + ret =openssl_err ("EVP key setup failed" ); + goto err_key; + } + + size =EVP_PKEY_size (evp_key); +if (size >sizeof (sig->sig)) { +fprintf (stderr,"Buffer to small for signature (%d bytes)\n" , + size); + ret = -ENOBUFS ; + goto err_key; + } + + ctx =EVP_MD_CTX_create (); +if (!ctx) { + ret =openssl_err ("EVP context creation failed" ); + goto err_key; + } +EVP_MD_CTX_init (ctx); +if (!EVP_SignInit (ctx,EVP_sha256 ())) { + ret =openssl_err ("Signer setup failed" ); + goto err_ctx; + } + +if (!EVP_SignUpdate (ctx, data, datasz)) { + ret =openssl_err ("Signing data failed" ); + goto err_ctx; + } + +if (!EVP_SignFinal (ctx, sig->sig, &sig_size, evp_key)) { + ret =openssl_err ("Could not obtain signature" ); + goto err_ctx; + } + +EVP_MD_CTX_cleanup (ctx); +EVP_MD_CTX_destroy (ctx); +EVP_PKEY_free (evp_key); + +return 0 ; + +err_ctx: +EVP_MD_CTX_destroy (ctx); +err_key: +EVP_PKEY_free (evp_key); +fprintf (stderr,"Failed to create %s signature\n" , signame); +return ret; +} + +int kwb_verify (RSA *key,void *data,int datasz,struct sig_v1 *sig, +char *signame) +{ +EVP_PKEY *evp_key; +EVP_MD_CTX *ctx; +int size; +int ret =0 ; + + evp_key =EVP_PKEY_new (); +if (!evp_key) +return openssl_err ("EVP_PKEY object creation failed" ); + +if (!EVP_PKEY_set1_RSA (evp_key, key)) { + ret =openssl_err ("EVP key setup failed" ); + goto err_key; + } + + size =EVP_PKEY_size (evp_key); +if (size >sizeof (sig->sig)) { +fprintf (stderr,"Invalid signature size (%d bytes)\n" , + size); + ret = -EINVAL ; + goto err_key; + } + + ctx =EVP_MD_CTX_create (); +if (!ctx) { + ret =openssl_err ("EVP context creation failed" ); + goto err_key; + } +EVP_MD_CTX_init (ctx); +if (!EVP_VerifyInit (ctx,EVP_sha256 ())) { + ret =openssl_err ("Verifier setup failed" ); + goto err_ctx; + } + +if (!EVP_VerifyUpdate (ctx, data, datasz)) { + ret =openssl_err ("Hashing data failed" ); + goto err_ctx; + } + +if (!EVP_VerifyFinal (ctx, sig->sig,sizeof (sig->sig), evp_key)) { + ret =openssl_err ("Could not verify signature" ); + goto err_ctx; + } + +EVP_MD_CTX_cleanup (ctx); +EVP_MD_CTX_destroy (ctx); +EVP_PKEY_free (evp_key); + +return 0 ; + +err_ctx: +EVP_MD_CTX_destroy (ctx); +err_key: +EVP_PKEY_free (evp_key); +fprintf (stderr,"Failed to verify %s signature\n" , signame); +return ret; +} + +int kwb_sign_and_verify (RSA *key,void *data,int datasz,struct sig_v1 *sig, +char *signame) +{ +if (kwb_sign (key, data, datasz, sig, signame) <0 ) +return -1 ; + +if (kwb_verify (key, data, datasz, sig, signame) <0 ) +return -1 ; + +return 0 ; +} + + +int kwb_dump_fuse_cmds_38x (FILE *out,struct secure_hdr_v1 *sec_hdr) +{ +struct hash_v1 kak_pub_hash; +struct image_cfg_element *e; +unsigned int fuse_line; +int i, idx; +uint8_t *ptr; +uint32_t val; +int ret =0 ; + +if (!out || !sec_hdr) +return -EINVAL ; + + ret =kwb_compute_pubkey_hash (&sec_hdr->kak, &kak_pub_hash); +if (ret <0 ) + goto done; + +fprintf (out,"# burn KAK pub key hash\n" ); + ptr = kak_pub_hash.hash; +for (fuse_line =26 ; fuse_line <=30 ; ++fuse_line) { +fprintf (out,"fuse prog -y %u 0 " , fuse_line); + +for (i =4 ; i-- >0 ;) +fprintf (out,"%02hx" , (ushort )ptr[i]); + ptr +=4 ; +fprintf (out," 00" ); + +if (fuse_line <30 ) { +for (i =3 ; i-- >0 ;) +fprintf (out,"%02hx" , (ushort )ptr[i]); + ptr +=3 ; + }else { +fprintf (out,"000000" ); + } + +fprintf (out," 1\n" ); + } + +fprintf (out,"# burn CSK selection\n" ); + + idx =image_get_csk_index (); +if (idx <0 || idx >15 ) { + ret = -EINVAL ; + goto done; + } +if (idx >0 ) { +for (fuse_line =31 ; fuse_line <31 + idx; ++fuse_line) +fprintf (out,"fuse prog -y %u 0 00000001 00000000 1\n" , + fuse_line); + }else { +fprintf (out,"# CSK index is 0; no mods needed\n" ); + } + + e =image_find_option (IMAGE_CFG_BOX_ID ); +if (e) { +fprintf (out,"# set box ID\n" ); +fprintf (out,"fuse prog -y 48 0 %08x 00000000 1\n" , e->boxid); + } + + e =image_find_option (IMAGE_CFG_FLASH_ID ); +if (e) { +fprintf (out,"# set flash ID\n" ); +fprintf (out,"fuse prog -y 47 0 %08x 00000000 1\n" , e->flashid); + } + +fprintf (out,"# enable secure mode " ); +fprintf (out,"(must be the last fuse line written)\n" ); + + val =1 ; + e =image_find_option (IMAGE_CFG_SEC_BOOT_DEV ); +if (!e) { +fprintf (stderr,"ERROR: secured mode boot device not given\n" ); + ret = -EINVAL ; + goto done; + } + +if (e->sec_boot_dev >0xff ) { +fprintf (stderr,"ERROR: secured mode boot device invalid\n" ); + ret = -EINVAL ; + goto done; + } + + val |= (e->sec_boot_dev <<8 ); + +fprintf (out,"fuse prog -y 24 0 %08x 0103e0a9 1\n" , val); + +fprintf (out,"# lock (unused) fuse lines (0-23)s\n" ); +for (fuse_line =0 ; fuse_line <24 ; ++fuse_line) +fprintf (out,"fuse prog -y %u 2 1\n" , fuse_line); + +fprintf (out,"# OK, that's all :-)\n" ); + +done: +return ret; +} + +static int kwb_dump_fuse_cmds (struct secure_hdr_v1 *sec_hdr) +{ +int ret =0 ; +struct image_cfg_element *e; + + e =image_find_option (IMAGE_CFG_SEC_FUSE_DUMP ); +if (!e) +return 0 ; + +if (!strcmp (e->name,"a38x" )) { +FILE *out =fopen ("kwb_fuses_a38x.txt" ,"w+" ); + +kwb_dump_fuse_cmds_38x (out, sec_hdr); +fclose (out); + goto done; + } + + ret = -ENOSYS ; + +done: +return ret; +} + +#endif +static void *image_create_v0 (size_t *imagesz,struct image_tool_params *params,int payloadsz) {@@ -353,6 +911,14 @@ static size_t image_headersz_v1(int *hasext) *hasext =1 ; } +#if defined(CONFIG_KWB_SECURE ) +if (image_get_csk_index () >=0 ) { + headersz +=sizeof (struct secure_hdr_v1 ); +if (hasext) + *hasext =1 ; + } +#endif +#if defined(CONFIG_SYS_U_BOOT_OFFS )if (headersz >CONFIG_SYS_U_BOOT_OFFS ) { fprintf(stderr,@@ -448,14 +1014,129 @@ int add_binary_header_v1(uint8_t *cur)return 0 ; } +#if defined(CONFIG_KWB_SECURE ) + +int export_pub_kak_hash (RSA *kak,struct secure_hdr_v1 *secure_hdr) +{ +FILE *hashf; +int res; + + hashf =fopen ("pub_kak_hash.txt" ,"w" ); + + res =kwb_export_pubkey (kak, &secure_hdr->kak, hashf,"KAK" ); + +fclose (hashf); + +return res <0 ?1 :0 ; +} + +int kwb_sign_csk_with_kak (struct image_tool_params *params, +struct secure_hdr_v1 *secure_hdr,RSA *csk) +{ +RSA *kak =NULL ; +RSA *kak_pub =NULL ; +int csk_idx =image_get_csk_index (); +struct sig_v1 tmp_sig; + +if (csk_idx >=16 ) { +fprintf (stderr,"Invalid CSK index %d\n" , csk_idx); +return 1 ; + } + +if (kwb_load_kak (params, &kak) <0 ) +return 1 ; + +if (export_pub_kak_hash (kak, secure_hdr)) +return 1 ; + +if (kwb_import_pubkey (&kak_pub, &secure_hdr->kak,"KAK" ) <0 ) +return 1 ; + +if (kwb_export_pubkey (csk, &secure_hdr->csk[csk_idx],NULL ,"CSK" ) <0 ) +return 1 ; + +if (kwb_sign_and_verify (kak, &secure_hdr->csk, +sizeof (secure_hdr->csk) + +sizeof (secure_hdr->csksig), + &tmp_sig,"CSK" ) <0 ) +return 1 ; + +if (kwb_verify (kak_pub, &secure_hdr->csk, +sizeof (secure_hdr->csk) + +sizeof (secure_hdr->csksig), + &tmp_sig,"CSK (2)" ) <0 ) +return 1 ; + + secure_hdr->csksig = tmp_sig; + +return 0 ; +} + +int add_secure_header_v1 (struct image_tool_params *params,uint8_t *ptr, +int payloadsz,size_t headersz,uint8_t *image, +struct secure_hdr_v1 *secure_hdr) +{ +struct image_cfg_element *e_jtagdelay; +struct image_cfg_element *e_boxid; +struct image_cfg_element *e_flashid; +RSA *csk =NULL ; +unsigned char *image_ptr; +size_t image_size; +struct sig_v1 tmp_sig; +bool specialized_img =image_get_spezialized_img (); + +kwb_msg ("Create secure header content\n" ); + + e_jtagdelay =image_find_option (IMAGE_CFG_JTAG_DELAY ); + e_boxid =image_find_option (IMAGE_CFG_BOX_ID ); + e_flashid =image_find_option (IMAGE_CFG_FLASH_ID ); + +if (kwb_load_csk (params, &csk) <0 ) +return 1 ; + + secure_hdr->headertype =OPT_HDR_V1_SECURE_TYPE ; + secure_hdr->headersz_msb =0 ; + secure_hdr->headersz_lsb =cpu_to_le16 (sizeof (struct secure_hdr_v1 )); +if (e_jtagdelay) + secure_hdr->jtag_delay = e_jtagdelay->jtag_delay; +if (e_boxid && specialized_img) + secure_hdr->boxid =cpu_to_le32 (e_boxid->boxid); +if (e_flashid && specialized_img) + secure_hdr->flashid =cpu_to_le32 (e_flashid->flashid); + +if (kwb_sign_csk_with_kak (params, secure_hdr, csk)) +return 1 ; + + image_ptr = ptr + headersz; + image_size = payloadsz - headersz; + +if (kwb_sign_and_verify (csk, image_ptr, image_size, + &secure_hdr->imgsig,"image" ) <0 ) +return 1 ; + +if (kwb_sign_and_verify (csk, image, headersz, &tmp_sig,"header" ) <0 ) +return 1 ; + + secure_hdr->hdrsig = tmp_sig; + +kwb_dump_fuse_cmds (secure_hdr); + +return 0 ; +} +#endif +static void *image_create_v1 (size_t *imagesz,struct image_tool_params *params, -int payloadsz) +uint8_t *ptr,int payloadsz) {struct image_cfg_element *e;struct main_hdr_v1 *main_hdr; +#if defined(CONFIG_KWB_SECURE ) +struct secure_hdr_v1 *secure_hdr =NULL ; +#endif size_t headersz;uint8_t *image, *cur;int hasext =0 ; +uint8_t *next_ext =NULL ;/* * Calculate the size of the header and the size of the @@ -474,7 +1155,9 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,memset (image,0 , headersz); main_hdr = (struct main_hdr_v1 *)image; - cur = image +sizeof (struct main_hdr_v1 ); + cur = image; + cur +=sizeof (struct main_hdr_v1 ); + next_ext = &main_hdr->ext;/* Fill the main header */ main_hdr->blocksize =@@ -497,9 +1180,28 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,if (e) main_hdr->nandbadblklocation = e->nandbadblklocation; +#if defined(CONFIG_KWB_SECURE ) +if (image_get_csk_index () >=0 ) { +/* +* only reserve the space here; we fill the header later since +* we need the header to be complete to compute the signatures +*/ + secure_hdr = (struct secure_hdr_v1 *)cur; + cur +=sizeof (struct secure_hdr_v1 ); + next_ext = &secure_hdr->next; + } +#endif + *next_ext =1 ; +if (add_binary_header_v1 (cur))return NULL ; +#if defined(CONFIG_KWB_SECURE ) +if (secure_hdr &&add_secure_header_v1 (params, ptr, payloadsz, + headersz, image, secure_hdr)) +return NULL ; +#endif +/* Calculate and set the header checksum */ main_hdr->checksum =image_checksum8 (main_hdr, headersz);@@ -605,6 +1307,36 @@ static int image_create_config_parse_oneline(char *line, el->regdata.raddr =strtoul (value1,NULL ,16 ); el->regdata.rdata =strtoul (value2,NULL ,16 );break ; +case IMAGE_CFG_KAK : + el->key_name =strdup (value1); +break ; +case IMAGE_CFG_CSK : + el->key_name =strdup (value1); +break ; +case IMAGE_CFG_CSK_INDEX : + el->csk_idx =strtol (value1,NULL ,0 ); +break ; +case IMAGE_CFG_JTAG_DELAY : + el->jtag_delay =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_BOX_ID : + el->boxid =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_FLASH_ID : + el->flashid =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_SEC_SPECIALIZED_IMG : + el->sec_specialized_img = true; +break ; +case IMAGE_CFG_SEC_COMMON_IMG : + el->sec_specialized_img = false; +break ; +case IMAGE_CFG_SEC_BOOT_DEV : + el->sec_boot_dev =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_SEC_FUSE_DUMP : + el->name =strdup (value1); +break ;default :fprintf (stderr, unknown_msg, line); }@@ -764,7 +1496,7 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,break ;case 1 : - image =image_create_v1 (&headersz, params, sbuf->st_size); + image =image_create_v1 (&headersz, params, ptr, sbuf->st_size);break ;default :tools/kwbimage.h +30
-0@@ -102,6 +102,43 @@ struct opt_hdr_v1 { };/* +* Public Key data in DER format +*/ +struct pubkey_der_v1 { +uint8_t key[524 ]; +}; + +/* +* Signature (RSA 2048) +*/ +struct sig_v1 { +uint8_t sig[256 ]; +}; + +/* +* Structure of secure header (Armada 38x) +*/ +struct secure_hdr_v1 { +uint8_t headertype;/* 0x0 */ +uint8_t headersz_msb;/* 0x1 */ +uint16_t headersz_lsb;/* 0x2 - 0x3 */ +uint32_t reserved1;/* 0x4 - 0x7 */ +struct pubkey_der_v1 kak;/* 0x8 - 0x213 */ +uint8_t jtag_delay;/* 0x214 */ +uint8_t reserved2;/* 0x215 */ +uint16_t reserved3;/* 0x216 - 0x217 */ +uint32_t boxid;/* 0x218 - 0x21B */ +uint32_t flashid;/* 0x21C - 0x21F */ +struct sig_v1 hdrsig;/* 0x220 - 0x31F */ +struct sig_v1 imgsig;/* 0x320 - 0x41F */ +struct pubkey_der_v1 csk[16 ];/* 0x420 - 0x24DF */
tools/kwbimage.h struct opt_hdr_v1 { · line 144
Quoted 10 lines
tools/kwbimage.h +7
-0+struct sig_v1 csksig;/* 0x24E0 - 0x25DF */ +uint8_t next;/* 0x25E0 */ +uint8_t reserved4;/* 0x25E1 */ +uint16_t reserved5;/* 0x25E2 - 0x25E3 */ +}; + +/* * Various values for the opt_hdr_v1->headertype field, describing the * different types of optional headers. The "secure" header contains * informations related to secure boot (encryption keys, etc.). The
Thanks,
Stefan
PATCH 15/17 arm: mvebu: Implement secure boot
Hi Stefan,
Quoted 14 lines · Stefan Roese
Quoted 13 lines · Mario Six
The patch implements secure booting for the mvebu architecture.
This includes:
- The addition of secure headers and all needed signatures and keys in mkimage
- Commands capable of writing the board's efuses to both write the needed cryptographic data and enable the secure booting mechanism
- The creation of convenience text files containing the necessary commands to write the efusesThe KAK and CSK keys are expected to reside in the files kwb_kak.key and kwb_csk.key (OpenSSL 2048 bit private keys) in the top-level directory.
Quoted 9 lines
Quoted 2 lines
Signed-off-by Reinhard Pfau <[email protected]>Signed-off-by Mario Six <[email protected]>Thanks Mario, I have to admit that I'm pretty new to this secure booting support on A38x. So I can't really comment much on the technical details. I would very much like to see some documentation being added for this secure boot support on A38x (doc/...). With a more detailed explanation of this procedure and best one exmaple on how this is done in practice.
I'll add some documentation in v2.
Quoted 37 lines
Please find some more comments below.
Quoted 35 lines
--- Makefile | 3 +- arch/arm/mach-mvebu/Kconfig | 20 + arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/efuse.c | 293 ++++++++++++ arch/arm/mach-mvebu/include/mach/cpu.h | 2 + arch/arm/mach-mvebu/include/mach/efuse.h | 71 +++ tools/Makefile | 6 +- tools/kwbimage.c | 744 ++++++++++++++++++++++++++++++- tools/kwbimage.h | 37 ++ 9 files changed, 1169 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-mvebu/efuse.c create mode 100644 arch/arm/mach-mvebu/include/mach/efuse.hMakefile +2
-1@@ -938,7 +938,8 @@ MKIMAGEFLAGS_u-boot.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \ -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) MKIMAGEFLAGS_u-boot-spl.kwb = -n $(srctree)/$(CONFIG_SYS_KWD_CONFIG:"%"=%) \ - -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) + -T kwbimage -a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \ + $(if $(KEYDIR),-k $(KEYDIR)) MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \ -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimagearch/arm/mach-mvebu/Kconfig +0
-0@@ -1,5 +1,9 @@ if ARCH_MVEBU
Quoted 16 lines
arch/arm/mach-mvebu/Kconfig config ARMADA_375 · line 28
Quoted 12 lines
arch/arm/mach-mvebu/Kconfig +5
-0+config HAVE_MVEBU_EFUSE + bool + default n + config ARMADA_32BIT bool select CPU_V7@@ -21,6 +25,7 @@ config ARMADA_375 config ARMADA_38X bool select ARMADA_32BIT + select HAVE_MVEBU_EFUSEDo you know if this secure boot support provided in this patch (and the one before it) also supports the Armada XP SoCs?
I just skimmed the Armada XP secure boot process, and it looks strikingly similar to the Armada 38x one. I haven't looked at the details, but I would tentatively say that the process implemented here should work on Armada XP as well.
Quoted 6 lines
Quoted 6 lines
arch/arm/mach-mvebu/Kconfig +0
-0config ARMADA_XP bool@@ -136,4 +141,19 @@ config SYS_VENDOR config SYS_SOC default "mvebu"
Quoted 9 lines
arch/arm/mach-mvebu/Kconfig config SYS_VENDOR · line 147
Quoted 4 lines
arch/arm/mach-mvebu/Kconfig +4
-0+config MVEBU_EFUSE + bool "Enable eFuse support" + default n + depends on HAVE_MVEBU_EFUSEIs this
Kconfigoption enabled in your board support patch? I can't find it there. And could you please add a help text to this option as well?
We're not using the secure boot in production yet, so it's not enabled in the board for now (we'll most likely activate it in a later revision). And I'll add a help text in v2.
Quoted 40 lines
Quoted 40 lines
arch/arm/mach-mvebu/Kconfig +10
-0+config MVEBU_EFUSE_FAKE + bool "Fake eFuse access (dry run)" + default n + depends on MVEBU_EFUSE + help + This enables a "dry run" mode where eFuses are not really programmed. + Instead the eFuse accesses are emulated by writing to and reading + from a memory block. + This is can be used for testing prog scripts. + endifarch/arm/mach-mvebu/Makefile +1
-0@@ -27,6 +27,7 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o obj-$(CONFIG_ARMADA_XP) += ../../../drivers/ddr/marvell/axp/xor.o +obj-$(CONFIG_MVEBU_EFUSE) += efuse.o endif # CONFIG_SPL_BUILD obj-y += gpio.o obj-y += mbus.oarch/arm/mach-mvebu/efuse.c new file +11
-0@@ -0,0 +1,293 @@ +/* +* Copyright (C) 2015-2016 Reinhard Pfau <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <config.h> +#include <common.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/arch/cpu.h>
Quoted 9 lines
arch/arm/mach-mvebu/efuse.c line 16
Quoted 5 lines
arch/arm/mach-mvebu/efuse.c new file +5
-0+#include <asm/arch/efuse.h> +#include <asm/arch/soc.h> +#include <linux/mbus.h> + +#if defined(CONFIG_MVEBU_EFUSE )This check should not be needed, as this file only gets compiled if
CONFIG_MVEBU_EFUSEis defined.
Indeed, that's the case. Will be fixed in v2.
Quoted 48 lines
Quoted 48 lines
arch/arm/mach-mvebu/efuse.c new file +48
-0+ +#if defined(CONFIG_MVEBU_EFUSE_FAKE ) +#define DRY_RUN +#else +#undef DRY_RUN +#endif + +#define MBUS_EFUSE_BASE 0xF6000000 +#define MBUS_EFUSE_SIZE BIT(20) + +#define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008)) + +enum { +MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 <<31 ), +}; + +struct mvebu_hd_efuse { +u32 bits_31_0; +u32 bits_63_32; +u32 bit64; +u32 reserved0; +}; + +#ifndef DRY_RUN +static struct mvebu_hd_efuse *efuses = + (struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE +0xF9000 ); +#else +static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX +1 ]; +#endif + +static int efuse_initialised; + +static struct mvebu_hd_efuse *get_efuse_line (int nr) +{ +if (nr <0 || nr >63 || !efuse_initialised) +return NULL ; + +return efuses + nr; +} + +static void enable_efuse_program (void ) +{ +#ifndef DRY_RUN +setbits_le32 (MVEBU_EFUSE_CONTROL ,MVEBU_EFUSE_CTRL_PROGRAM_ENABLE ); +#endif +} + +static void disable_efuse_program (void )
Quoted 9 lines
arch/arm/mach-mvebu/efuse.c line 70
Quoted 6 lines
arch/arm/mach-mvebu/efuse.c new file +6
-0+{ +#ifndef DRY_RUN +u32 reg =readl (MVEBU_EFUSE_CONTROL ); + + reg &= ~MVEBU_EFUSE_CTRL_PROGRAM_ENABLE ; +writel (MVEBU_EFUSE_CONTROL , reg);
clrbits_le32()please.
I apparently converted enable_efuse_program, but forgot disable_efuse program. Will be fixed in v2.
Quoted 230 lines
Quoted 230 lines
arch/arm/mach-mvebu/efuse.c new file +223
-0+#endif +} + +static int do_prog_efuse (struct mvebu_hd_efuse *efuse, +struct efuse_val *new_val,u32 mask0,u32 mask1) +{ +struct efuse_val val; + + val.dwords.d[0 ] =readl (&efuse->bits_31_0); + val.dwords.d[1 ] =readl (&efuse->bits_63_32); + val.lock =readl (&efuse->bit64); + +if (val.lock &1 ) +return -EPERM ; + + val.dwords.d[0 ] |= (new_val->dwords.d[0 ] & mask0); + val.dwords.d[1 ] |= (new_val->dwords.d[1 ] & mask1); + val.lock |= new_val->lock; + +writel (val.dwords.d[0 ], &efuse->bits_31_0); +mdelay (1 ); +writel (val.dwords.d[1 ], &efuse->bits_63_32); +mdelay (1 ); +writel (val.lock, &efuse->bit64); +mdelay (5 ); + +return 0 ; +} + +static int prog_efuse (int nr,struct efuse_val *new_val,u32 mask0,u32 mask1) +{ +struct mvebu_hd_efuse *efuse; +int res =0 ; + + res =mvebu_efuse_init_hw (); +if (res) +return res; + + efuse =get_efuse_line (nr); +if (!efuse) +return -ENODEV ; + +if (!new_val) +return -EINVAL ; + +/* only write a fuse line with lock bit */ +if (!new_val->lock) +return -EINVAL ; + +/* according to specs ECC protection bits must be 0 on write */ +if (new_val->bytes.d[7 ] &0xFE ) +return -EINVAL ; + +if (!new_val->dwords.d[0 ] && !new_val->dwords.d[1 ] && (mask0 | mask1)) +return 0 ; + +enable_efuse_program (); + + res =do_prog_efuse (efuse, new_val, mask0, mask1); + +disable_efuse_program (); + +return res; +} + +int mvebu_efuse_init_hw (void ) +{ +int ret; + +if (efuse_initialised) +return 0 ; + + ret =mvebu_mbus_add_window_by_id ( +CPU_TARGET_SATA23_DFX ,0xA ,MBUS_EFUSE_BASE ,MBUS_EFUSE_SIZE ); + +if (ret) +return ret; + + efuse_initialised =1 ; + +return 0 ; +} + +int mvebu_read_efuse (int nr,struct efuse_val *val) +{ +struct mvebu_hd_efuse *efuse; +int res; + + res =mvebu_efuse_init_hw (); +if (res) +return res; + + efuse =get_efuse_line (nr); +if (!efuse) +return -ENODEV ; + +if (!val) +return -EINVAL ; + + val->dwords.d[0 ] =readl (&efuse->bits_31_0); + val->dwords.d[1 ] =readl (&efuse->bits_63_32); + val->lock =readl (&efuse->bit64); +return 0 ; +} + +int mvebu_write_efuse (int nr,struct efuse_val *val) +{ +return prog_efuse (nr, val, ~0 , ~0 ); +} + +int mvebu_lock_efuse (int nr) +{ +struct efuse_val val = { + .lock =1 , + }; + +return prog_efuse (nr, &val,0 ,0 ); +} + +#else + +int mvebu_efuse_init_hw (void ) +{ +return -ENODEV ; +} + +int mvebu_read_efuse (int nr,struct efuse_val *val) +{ +return -ENODEV ; +} + +int mvebu_write_efuse (int nr,struct efuse_val *val) +{ +return -ENODEV ; +} + +int mvebu_lock_efuse (int nr) +{ +return -ENODEV ; +} + +#endif + +/* +* wrapper funcs providing the fuse API +* +* we use the following mapping: +* "bank" -> eFuse line +* "word" -> 0: bits 0-31 +* 1: bits 32-63 +* 2: bit 64 (lock) +*/ + +static struct efuse_val prog_val; +static int valid_prog_words; + +int fuse_read (u32 bank,u32 word,u32 *val) +{ +struct efuse_val fuse_line; +int res; + +if (bank <EFUSE_LINE_MIN || bank >EFUSE_LINE_MAX || word >2 ) +return -EINVAL ; + + res =mvebu_read_efuse (bank, &fuse_line); +if (res) +return res; + +if (word <2 ) + *val = fuse_line.dwords.d[word]; +else + *val = fuse_line.lock; + +return res; +} + +int fuse_sense (u32 bank,u32 word,u32 *val) +{ +/* not supported */ +return -ENOSYS ; +} + +int fuse_prog (u32 bank,u32 word,u32 val) +{ +int res =0 ; + +/* +* NOTE: Fuse line should be written as whole. +* So how can we do that with this API? +* For now: remember values for word == 0 and word == 1 and write the +* whole line when word == 2. +* This implies that we always require all 3 fuse prog cmds (one for +* for each word) to write a single fuse line. +* Exception is a single write to word 2 which will lock the fuse line. +* +* Hope that will be OK. +*/ + +if (bank <EFUSE_LINE_MIN || bank >EFUSE_LINE_MAX || word >2 ) +return -EINVAL ; + +if (word <2 ) { + prog_val.dwords.d[word] = val; + valid_prog_words |= (1 << word); + }else if ((valid_prog_words &3 ) ==0 && val) { + res =mvebu_lock_efuse (bank); + valid_prog_words =0 ; + }else if ((valid_prog_words &3 ) !=3 || !val) { + res = -EINVAL ; + }else { + prog_val.lock = val !=0 ; + res =mvebu_write_efuse (bank, &prog_val); + valid_prog_words =0 ; + } + +return res; +} + +int fuse_override (u32 bank,u32 word,u32 val) +{ +/* not supported */ +return -ENOSYS ; +}arch/arm/mach-mvebu/include/mach/cpu.h +0
-0@@ -36,7 +36,9 @@ enum cpu_target {CPU_TARGET_ETH01 =0x7 , CPU_TARGET_PCIE13 = 0x8,
Quoted 9 lines
arch/arm/mach-mvebu/include/mach/cpu.h enum cpu_target { · line 42
Quoted 5 lines
arch/arm/mach-mvebu/include/mach/cpu.h +2
-0CPU_TARGET_SASRAM =0x9 , +CPU_TARGET_SATA01 =0xa ,/* A38X */ CPU_TARGET_NAND =0xd , + CPU_TARGET_SATA23_DFX = 0xe, /* A38X */ };This looks like an unrelated change, perhaps better moved into a separate patch?
That's what I thought too when I saw this for the first time, but take a look at arch/arm/mach-mvebu/efuse:c:138. To access the efuses, you actually need to add the SATA23_DFX window using mvebu_mbus_add_window_by_id; and the SATA01 enum is then added just for completeness' sake.
Quoted 14 lines
arch/arm/mach-mvebu/include/mach/efuse.h line 2
Quoted 10 lines
arch/arm/mach-mvebu/include/mach/cpu.h +0
-0enum cpu_attrib {arch/arm/mach-mvebu/include/mach/efuse.h new file +2
-0@@ -0,0 +1,71 @@ +/* +* Copyright (C) 2015 Reinhard Pfau <[email protected]> Only 2015? This might need to get changed in more files, I didn't check closely.
Reinhard actually wrote the secure boot code last year, and I just rebased and tested it, so that's correct.
Quoted 62 lines
Quoted 62 lines
arch/arm/mach-mvebu/include/mach/efuse.h new file +62
-0+* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _MVEBU_EFUSE_H +#define _MVEBU_EFUSE_H + +#include <common.h> + +struct efuse_val { +union { +struct { +u8 d[8 ]; + } bytes; +struct { +u16 d[4 ]; + } words; +struct { +u32 d[2 ]; + } dwords; + }; +u32 lock; +}; + +#if defined(CONFIG_ARMADA_38X ) + +enum efuse_line { +EFUSE_LINE_SECURE_BOOT =24 , +EFUSE_LINE_PUBKEY_DIGEST_0 =26 , +EFUSE_LINE_PUBKEY_DIGEST_1 =27 , +EFUSE_LINE_PUBKEY_DIGEST_2 =28 , +EFUSE_LINE_PUBKEY_DIGEST_3 =29 , +EFUSE_LINE_PUBKEY_DIGEST_4 =30 , +EFUSE_LINE_CSK_0_VALID =31 , +EFUSE_LINE_CSK_1_VALID =32 , +EFUSE_LINE_CSK_2_VALID =33 , +EFUSE_LINE_CSK_3_VALID =34 , +EFUSE_LINE_CSK_4_VALID =35 , +EFUSE_LINE_CSK_5_VALID =36 , +EFUSE_LINE_CSK_6_VALID =37 , +EFUSE_LINE_CSK_7_VALID =38 , +EFUSE_LINE_CSK_8_VALID =39 , +EFUSE_LINE_CSK_9_VALID =40 , +EFUSE_LINE_CSK_10_VALID =41 , +EFUSE_LINE_CSK_11_VALID =42 , +EFUSE_LINE_CSK_12_VALID =43 , +EFUSE_LINE_CSK_13_VALID =44 , +EFUSE_LINE_CSK_14_VALID =45 , +EFUSE_LINE_CSK_15_VALID =46 , +EFUSE_LINE_FLASH_ID =47 , +EFUSE_LINE_BOX_ID =48 , + +EFUSE_LINE_MIN =0 , +EFUSE_LINE_MAX =63 , +}; + +#endif + + +int mvebu_efuse_init_hw (void ); + +int mvebu_read_efuse (int nr,struct efuse_val *val);
Quoted 9 lines
arch/arm/mach-mvebu/include/mach/efuse.h line 70
Quoted 6 lines
arch/arm/mach-mvebu/include/mach/efuse.h new file +6
-0+ +int mvebu_write_efuse (int nr,struct efuse_val *val); + +int mvebu_lock_efuse (int nr); + +Double empty line not needed.
Will remove in v2.
Quoted 926 lines
Quoted 926 lines
arch/arm/mach-mvebu/include/mach/efuse.h new file +1
-0+#endif tools/Makefile +5
-1@@ -141,8 +141,12 @@ ifdef CONFIG_SYS_U_BOOT_OFFS HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS) endif +ifneq ($(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),) +HOSTCFLAGS_kwbimage.o += -DCONFIG_KWB_SECURE +endif + # MXSImage needs LibSSL -ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),) +ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X)$(CONFIG_FIT_SIGNATURE),) HOSTLOADLIBES_mkimage += \ $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")tools/kwbimage.c +738
-6@@ -1,30 +1,47 @@/* * Image manipulator for Marvell SoCs -* supports Kirkwood, Dove, Armada 370, and Armada XP +* supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x * * (C) Copyright 2013 Thomas Petazzoni * <[email protected]> * * SPDX-License-Identifier: GPL-2.0+ * -* Not implemented: support for the register headers and secure -* headers in v1 images +* Not implemented: support for the register headers in v1 images */ #include "imagetool.h" #include <limits.h> #include <image.h> +#include <stdarg.h> #include <stdint.h> #include "kwbimage.h" +#ifdef CONFIG_KWB_SECURE +#include <openssl/rsa.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#endif +static struct image_cfg_element *image_cfg;static int cfgn; +#ifdef CONFIG_KWB_SECURE +static int verbose_mode; +#endif struct boot_mode {unsigned int id;const char *name; }; +/* +* SHA2-256 hash +*/ +struct hash_v1 { +uint8_t hash[32 ]; +}; +struct boot_mode boot_modes[] = { {0x4D ,"i2c" }, {0x5A ,"spi" },@@ -68,6 +85,16 @@ enum image_cfg_type {IMAGE_CFG_BINARY ,IMAGE_CFG_PAYLOAD ,IMAGE_CFG_DATA , +IMAGE_CFG_KAK , +IMAGE_CFG_CSK , +IMAGE_CFG_CSK_INDEX , +IMAGE_CFG_JTAG_DELAY , +IMAGE_CFG_BOX_ID , +IMAGE_CFG_FLASH_ID , +IMAGE_CFG_SEC_COMMON_IMG , +IMAGE_CFG_SEC_SPECIALIZED_IMG , +IMAGE_CFG_SEC_BOOT_DEV , +IMAGE_CFG_SEC_FUSE_DUMP ,IMAGE_CFG_COUNT } type;@@ -84,6 +111,16 @@ static const char * const id_strs[] = { [IMAGE_CFG_BINARY] = "BINARY", [IMAGE_CFG_PAYLOAD] = "PAYLOAD", [IMAGE_CFG_DATA] = "DATA", + [IMAGE_CFG_KAK] = "KAK", + [IMAGE_CFG_CSK] = "CSK", + [IMAGE_CFG_CSK_INDEX] = "CSK_INDEX", + [IMAGE_CFG_JTAG_DELAY] = "JTAG_DELAY", + [IMAGE_CFG_BOX_ID] = "BOX_ID", + [IMAGE_CFG_FLASH_ID] = "FLASH_ID", + [IMAGE_CFG_SEC_COMMON_IMG] = "SEC_COMMON_IMG", + [IMAGE_CFG_SEC_SPECIALIZED_IMG] = "SEC_SPECIALIZED_IMG", + [IMAGE_CFG_SEC_BOOT_DEV] = "SEC_BOOT_DEV", + [IMAGE_CFG_SEC_FUSE_DUMP ] ="SEC_FUSE_DUMP" };struct image_cfg_element {@@ -104,6 +141,14 @@ struct image_cfg_element {unsigned int nandeccmode;unsigned int nandpagesz;struct ext_hdr_v0_reg regdata; +const char *key_name; +int csk_idx; +uint8_t jtag_delay; +uint32_t boxid; +uint32_t flashid; +bool sec_specialized_img; +unsigned int sec_boot_dev; +const char *name; }; };@@ -172,6 +217,32 @@ image_count_options(unsigned int optiontype)return count; } +#if defined(CONFIG_KWB_SECURE ) + +static int image_get_csk_index (void ) +{ +struct image_cfg_element *e; + + e =image_find_option (IMAGE_CFG_CSK_INDEX ); +if (!e) +return -1 ; + +return e->csk_idx; +} + +static bool image_get_spezialized_img (void ) +{ +struct image_cfg_element *e; + + e =image_find_option (IMAGE_CFG_SEC_SPECIALIZED_IMG ); +if (!e) +return false; + +return e->sec_specialized_img; +} + +#endif +/* * Compute a 8-bit checksum of a memory area. This algorithm follows * the requirements of the Marvell SoC BootROM specifications. @@ -217,6 +288,493 @@ static uint32_t image_checksum32(void *start, uint32_t len)return csum; } +#if defined(CONFIG_KWB_SECURE ) +static void kwb_msg (const char *fmt, ...) +{ +if (verbose_mode) { +va_list ap; + +va_start (ap, fmt); +vfprintf (stdout, fmt, ap); +va_end (ap); + } +} + +static int openssl_err (const char *msg) +{ +unsigned long ssl_err =ERR_get_error (); + +fprintf (stderr,"%s" , msg); +fprintf (stderr,": %s\n" , +ERR_error_string (ssl_err,0 )); + +return -1 ; +} + +static int kwb_load_rsa_key (const char *keydir,const char *name,RSA **p_rsa) +{ +char path[PATH_MAX ]; +RSA *rsa; +FILE *f; + +if (!keydir) + keydir ="." ; + +snprintf (path,sizeof (path),"%s/%s.key" , keydir, name); + f =fopen (path,"r" ); +if (!f) { +fprintf (stderr,"Couldn't open RSA private key: '%s': %s\n" , + path,strerror (errno)); +return -ENOENT ; + } + + rsa =PEM_read_RSAPrivateKey (f,0 ,NULL ,"" ); +if (!rsa) { +openssl_err ("Failure reading private key" ); +fclose (f); +return -EPROTO ; + } +fclose (f); + *p_rsa = rsa; + +return 0 ; +} + +static int kwb_load_cfg_key (struct image_tool_params *params, +unsigned int cfg_option,const char *key_name, +RSA **p_key) +{ +struct image_cfg_element *e_key; +RSA *key; +int res; + + *p_key =NULL ; + + e_key =image_find_option (cfg_option); +if (!e_key) { +fprintf (stderr,"%s not configured\n" , key_name); +return -ENOENT ; + } + + res =kwb_load_rsa_key (params->keydir, e_key->key_name, &key); +if (res <0 ) { +fprintf (stderr,"Failed to load %s\n" , key_name); +return -ENOENT ; + } + + *p_key = key; + +return 0 ; +} + +static int kwb_load_kak (struct image_tool_params *params,RSA **p_kak) +{ +return kwb_load_cfg_key (params,IMAGE_CFG_KAK ,"KAK" , p_kak); +} + +static int kwb_load_csk (struct image_tool_params *params,RSA **p_csk) +{ +return kwb_load_cfg_key (params,IMAGE_CFG_CSK ,"CSK" , p_csk); +} + +static int kwb_compute_pubkey_hash (struct pubkey_der_v1 *pk, +struct hash_v1 *hash) +{ +EVP_MD_CTX *ctx; +unsigned int key_size; +unsigned int hash_size; +int ret =0 ; + +if (!pk || !hash || pk->key[0 ] !=0x30 || pk->key[1 ] !=0x82 ) +return -EINVAL ; + + key_size = (pk->key[2 ] <<8 ) + pk->key[3 ] +4 ; + + ctx =EVP_MD_CTX_create (); +if (!ctx) +return openssl_err ("EVP context creation failed" ); + +EVP_MD_CTX_init (ctx); +if (!EVP_DigestInit (ctx,EVP_sha256 ())) { + ret =openssl_err ("Digest setup failed" ); + goto hash_err_ctx; + } + +if (!EVP_DigestUpdate (ctx, pk->key, key_size)) { + ret =openssl_err ("Hashing data failed" ); + goto hash_err_ctx; + } + +if (!EVP_DigestFinal (ctx, hash->hash, &hash_size)) { + ret =openssl_err ("Could not obtain hash" ); + goto hash_err_ctx; + } + +EVP_MD_CTX_cleanup (ctx); + +hash_err_ctx: +EVP_MD_CTX_destroy (ctx); +return ret; +} + +static int kwb_import_pubkey (RSA **key,struct pubkey_der_v1 *src,char *keyname) +{ +RSA *rsa; +const unsigned char *ptr; + +if (!key || !src) + goto fail; + + ptr = src->key; + rsa =d2i_RSAPublicKey (key, &ptr,sizeof (src->key)); +if (!rsa) { +openssl_err ("error decoding public key" ); + goto fail; + } + +return 0 ; +fail: +fprintf (stderr,"Failed to decode %s pubkey\n" , keyname); +return -EINVAL ; +} + +static int kwb_export_pubkey (RSA *key,struct pubkey_der_v1 *dst,FILE *hashf, +char *keyname) +{ +int size_exp, size_mod, size_seq; +uint8_t *cur; +char *errmsg ="Failed to encode %s\n" ; + +if (!key || !key->e || !key->n || !dst) { +fprintf (stderr,"export pk failed: (%p, %p, %p, %p)" , + key, key->e, key->n, dst); +fprintf (stderr, errmsg, keyname); +return -EINVAL ; + } + +/* +* According to the specs, the key should be PKCS#1 DER encoded. +* But unfortunately the really required encoding seems to be different; +* it violates DER...! (But it still conformes to BER.) +* (Length always in long form w/ 2 byte length code; no leading zero +* when MSB of first byte is set...) +* So we cannot use the encoding func provided by OpenSSL and have to +* do the encoding manually. +*/ + + size_exp =BN_num_bytes (key->e); + size_mod =BN_num_bytes (key->n); + size_seq =4 + size_mod +4 + size_exp; + +if (size_mod >256 ) { +fprintf (stderr,"export pk failed: wrong mod size: %d\n" , + size_mod); +fprintf (stderr, errmsg, keyname); +return -EINVAL ; + } + +if (4 + size_seq >sizeof (dst->key)) { +fprintf (stderr,"export pk failed: seq too large (%d, %lu)\n" , +4 + size_seq,sizeof (dst->key)); +fprintf (stderr, errmsg, keyname); +return -ENOBUFS ; + } + + cur = dst->key; + +/* PKCS#1 (RFC3447) RSAPublicKey structure */ + *cur++ =0x30 ;/* SEQUENCE */ + *cur++ =0x82 ; + *cur++ = (size_seq >>8 ) &0xFF ; + *cur++ = size_seq &0xFF ; +/* Modulus */ + *cur++ =0x02 ;/* INTEGER */ + *cur++ =0x82 ; + *cur++ = (size_mod >>8 ) &0xFF ; + *cur++ = size_mod &0xFF ; +BN_bn2bin (key->n, cur); + cur += size_mod; +/* Exponent */ + *cur++ =0x02 ;/* INTEGER */ + *cur++ =0x82 ; + *cur++ = (size_exp >>8 ) &0xFF ; + *cur++ = size_exp &0xFF ; +BN_bn2bin (key->e, cur); + +if (hashf) { +struct hash_v1 pk_hash; +int i; +int ret =0 ; + + ret =kwb_compute_pubkey_hash (dst, &pk_hash); +if (ret <0 ) { +fprintf (stderr, errmsg, keyname); +return ret; + } + +fprintf (hashf,"SHA256 = " ); +for (i =0 ; i <sizeof (pk_hash.hash); ++i) +fprintf (hashf,"%02X" , pk_hash.hash[i]); +fprintf (hashf,"\n" ); + } + +return 0 ; +} + +int kwb_sign (RSA *key,void *data,int datasz,struct sig_v1 *sig,char *signame) +{ +EVP_PKEY *evp_key; +EVP_MD_CTX *ctx; +unsigned int sig_size; +int size; +int ret =0 ; + + evp_key =EVP_PKEY_new (); +if (!evp_key) +return openssl_err ("EVP_PKEY object creation failed" ); + +if (!EVP_PKEY_set1_RSA (evp_key, key)) { + ret =openssl_err ("EVP key setup failed" ); + goto err_key; + } + + size =EVP_PKEY_size (evp_key); +if (size >sizeof (sig->sig)) { +fprintf (stderr,"Buffer to small for signature (%d bytes)\n" , + size); + ret = -ENOBUFS ; + goto err_key; + } + + ctx =EVP_MD_CTX_create (); +if (!ctx) { + ret =openssl_err ("EVP context creation failed" ); + goto err_key; + } +EVP_MD_CTX_init (ctx); +if (!EVP_SignInit (ctx,EVP_sha256 ())) { + ret =openssl_err ("Signer setup failed" ); + goto err_ctx; + } + +if (!EVP_SignUpdate (ctx, data, datasz)) { + ret =openssl_err ("Signing data failed" ); + goto err_ctx; + } + +if (!EVP_SignFinal (ctx, sig->sig, &sig_size, evp_key)) { + ret =openssl_err ("Could not obtain signature" ); + goto err_ctx; + } + +EVP_MD_CTX_cleanup (ctx); +EVP_MD_CTX_destroy (ctx); +EVP_PKEY_free (evp_key); + +return 0 ; + +err_ctx: +EVP_MD_CTX_destroy (ctx); +err_key: +EVP_PKEY_free (evp_key); +fprintf (stderr,"Failed to create %s signature\n" , signame); +return ret; +} + +int kwb_verify (RSA *key,void *data,int datasz,struct sig_v1 *sig, +char *signame) +{ +EVP_PKEY *evp_key; +EVP_MD_CTX *ctx; +int size; +int ret =0 ; + + evp_key =EVP_PKEY_new (); +if (!evp_key) +return openssl_err ("EVP_PKEY object creation failed" ); + +if (!EVP_PKEY_set1_RSA (evp_key, key)) { + ret =openssl_err ("EVP key setup failed" ); + goto err_key; + } + + size =EVP_PKEY_size (evp_key); +if (size >sizeof (sig->sig)) { +fprintf (stderr,"Invalid signature size (%d bytes)\n" , + size); + ret = -EINVAL ; + goto err_key; + } + + ctx =EVP_MD_CTX_create (); +if (!ctx) { + ret =openssl_err ("EVP context creation failed" ); + goto err_key; + } +EVP_MD_CTX_init (ctx); +if (!EVP_VerifyInit (ctx,EVP_sha256 ())) { + ret =openssl_err ("Verifier setup failed" ); + goto err_ctx; + } + +if (!EVP_VerifyUpdate (ctx, data, datasz)) { + ret =openssl_err ("Hashing data failed" ); + goto err_ctx; + } + +if (!EVP_VerifyFinal (ctx, sig->sig,sizeof (sig->sig), evp_key)) { + ret =openssl_err ("Could not verify signature" ); + goto err_ctx; + } + +EVP_MD_CTX_cleanup (ctx); +EVP_MD_CTX_destroy (ctx); +EVP_PKEY_free (evp_key); + +return 0 ; + +err_ctx: +EVP_MD_CTX_destroy (ctx); +err_key: +EVP_PKEY_free (evp_key); +fprintf (stderr,"Failed to verify %s signature\n" , signame); +return ret; +} + +int kwb_sign_and_verify (RSA *key,void *data,int datasz,struct sig_v1 *sig, +char *signame) +{ +if (kwb_sign (key, data, datasz, sig, signame) <0 ) +return -1 ; + +if (kwb_verify (key, data, datasz, sig, signame) <0 ) +return -1 ; + +return 0 ; +} + + +int kwb_dump_fuse_cmds_38x (FILE *out,struct secure_hdr_v1 *sec_hdr) +{ +struct hash_v1 kak_pub_hash; +struct image_cfg_element *e; +unsigned int fuse_line; +int i, idx; +uint8_t *ptr; +uint32_t val; +int ret =0 ; + +if (!out || !sec_hdr) +return -EINVAL ; + + ret =kwb_compute_pubkey_hash (&sec_hdr->kak, &kak_pub_hash); +if (ret <0 ) + goto done; + +fprintf (out,"# burn KAK pub key hash\n" ); + ptr = kak_pub_hash.hash; +for (fuse_line =26 ; fuse_line <=30 ; ++fuse_line) { +fprintf (out,"fuse prog -y %u 0 " , fuse_line); + +for (i =4 ; i-- >0 ;) +fprintf (out,"%02hx" , (ushort )ptr[i]); + ptr +=4 ; +fprintf (out," 00" ); + +if (fuse_line <30 ) { +for (i =3 ; i-- >0 ;) +fprintf (out,"%02hx" , (ushort )ptr[i]); + ptr +=3 ; + }else { +fprintf (out,"000000" ); + } + +fprintf (out," 1\n" ); + } + +fprintf (out,"# burn CSK selection\n" ); + + idx =image_get_csk_index (); +if (idx <0 || idx >15 ) { + ret = -EINVAL ; + goto done; + } +if (idx >0 ) { +for (fuse_line =31 ; fuse_line <31 + idx; ++fuse_line) +fprintf (out,"fuse prog -y %u 0 00000001 00000000 1\n" , + fuse_line); + }else { +fprintf (out,"# CSK index is 0; no mods needed\n" ); + } + + e =image_find_option (IMAGE_CFG_BOX_ID ); +if (e) { +fprintf (out,"# set box ID\n" ); +fprintf (out,"fuse prog -y 48 0 %08x 00000000 1\n" , e->boxid); + } + + e =image_find_option (IMAGE_CFG_FLASH_ID ); +if (e) { +fprintf (out,"# set flash ID\n" ); +fprintf (out,"fuse prog -y 47 0 %08x 00000000 1\n" , e->flashid); + } + +fprintf (out,"# enable secure mode " ); +fprintf (out,"(must be the last fuse line written)\n" ); + + val =1 ; + e =image_find_option (IMAGE_CFG_SEC_BOOT_DEV ); +if (!e) { +fprintf (stderr,"ERROR: secured mode boot device not given\n" ); + ret = -EINVAL ; + goto done; + } + +if (e->sec_boot_dev >0xff ) { +fprintf (stderr,"ERROR: secured mode boot device invalid\n" ); + ret = -EINVAL ; + goto done; + } + + val |= (e->sec_boot_dev <<8 ); + +fprintf (out,"fuse prog -y 24 0 %08x 0103e0a9 1\n" , val); + +fprintf (out,"# lock (unused) fuse lines (0-23)s\n" ); +for (fuse_line =0 ; fuse_line <24 ; ++fuse_line) +fprintf (out,"fuse prog -y %u 2 1\n" , fuse_line); + +fprintf (out,"# OK, that's all :-)\n" ); + +done: +return ret; +} + +static int kwb_dump_fuse_cmds (struct secure_hdr_v1 *sec_hdr) +{ +int ret =0 ; +struct image_cfg_element *e; + + e =image_find_option (IMAGE_CFG_SEC_FUSE_DUMP ); +if (!e) +return 0 ; + +if (!strcmp (e->name,"a38x" )) { +FILE *out =fopen ("kwb_fuses_a38x.txt" ,"w+" ); + +kwb_dump_fuse_cmds_38x (out, sec_hdr); +fclose (out); + goto done; + } + + ret = -ENOSYS ; + +done: +return ret; +} + +#endif +static void *image_create_v0 (size_t *imagesz,struct image_tool_params *params,int payloadsz) {@@ -353,6 +911,14 @@ static size_t image_headersz_v1(int *hasext) *hasext =1 ; } +#if defined(CONFIG_KWB_SECURE ) +if (image_get_csk_index () >=0 ) { + headersz +=sizeof (struct secure_hdr_v1 ); +if (hasext) + *hasext =1 ; + } +#endif +#if defined(CONFIG_SYS_U_BOOT_OFFS )if (headersz >CONFIG_SYS_U_BOOT_OFFS ) { fprintf(stderr,@@ -448,14 +1014,129 @@ int add_binary_header_v1(uint8_t *cur)return 0 ; } +#if defined(CONFIG_KWB_SECURE ) + +int export_pub_kak_hash (RSA *kak,struct secure_hdr_v1 *secure_hdr) +{ +FILE *hashf; +int res; + + hashf =fopen ("pub_kak_hash.txt" ,"w" ); + + res =kwb_export_pubkey (kak, &secure_hdr->kak, hashf,"KAK" ); + +fclose (hashf); + +return res <0 ?1 :0 ; +} + +int kwb_sign_csk_with_kak (struct image_tool_params *params, +struct secure_hdr_v1 *secure_hdr,RSA *csk) +{ +RSA *kak =NULL ; +RSA *kak_pub =NULL ; +int csk_idx =image_get_csk_index (); +struct sig_v1 tmp_sig; + +if (csk_idx >=16 ) { +fprintf (stderr,"Invalid CSK index %d\n" , csk_idx); +return 1 ; + } + +if (kwb_load_kak (params, &kak) <0 ) +return 1 ; + +if (export_pub_kak_hash (kak, secure_hdr)) +return 1 ; + +if (kwb_import_pubkey (&kak_pub, &secure_hdr->kak,"KAK" ) <0 ) +return 1 ; + +if (kwb_export_pubkey (csk, &secure_hdr->csk[csk_idx],NULL ,"CSK" ) <0 ) +return 1 ; + +if (kwb_sign_and_verify (kak, &secure_hdr->csk, +sizeof (secure_hdr->csk) + +sizeof (secure_hdr->csksig), + &tmp_sig,"CSK" ) <0 ) +return 1 ; + +if (kwb_verify (kak_pub, &secure_hdr->csk, +sizeof (secure_hdr->csk) + +sizeof (secure_hdr->csksig), + &tmp_sig,"CSK (2)" ) <0 ) +return 1 ; + + secure_hdr->csksig = tmp_sig; + +return 0 ; +} + +int add_secure_header_v1 (struct image_tool_params *params,uint8_t *ptr, +int payloadsz,size_t headersz,uint8_t *image, +struct secure_hdr_v1 *secure_hdr) +{ +struct image_cfg_element *e_jtagdelay; +struct image_cfg_element *e_boxid; +struct image_cfg_element *e_flashid; +RSA *csk =NULL ; +unsigned char *image_ptr; +size_t image_size; +struct sig_v1 tmp_sig; +bool specialized_img =image_get_spezialized_img (); + +kwb_msg ("Create secure header content\n" ); + + e_jtagdelay =image_find_option (IMAGE_CFG_JTAG_DELAY ); + e_boxid =image_find_option (IMAGE_CFG_BOX_ID ); + e_flashid =image_find_option (IMAGE_CFG_FLASH_ID ); + +if (kwb_load_csk (params, &csk) <0 ) +return 1 ; + + secure_hdr->headertype =OPT_HDR_V1_SECURE_TYPE ; + secure_hdr->headersz_msb =0 ; + secure_hdr->headersz_lsb =cpu_to_le16 (sizeof (struct secure_hdr_v1 )); +if (e_jtagdelay) + secure_hdr->jtag_delay = e_jtagdelay->jtag_delay; +if (e_boxid && specialized_img) + secure_hdr->boxid =cpu_to_le32 (e_boxid->boxid); +if (e_flashid && specialized_img) + secure_hdr->flashid =cpu_to_le32 (e_flashid->flashid); + +if (kwb_sign_csk_with_kak (params, secure_hdr, csk)) +return 1 ; + + image_ptr = ptr + headersz; + image_size = payloadsz - headersz; + +if (kwb_sign_and_verify (csk, image_ptr, image_size, + &secure_hdr->imgsig,"image" ) <0 ) +return 1 ; + +if (kwb_sign_and_verify (csk, image, headersz, &tmp_sig,"header" ) <0 ) +return 1 ; + + secure_hdr->hdrsig = tmp_sig; + +kwb_dump_fuse_cmds (secure_hdr); + +return 0 ; +} +#endif +static void *image_create_v1 (size_t *imagesz,struct image_tool_params *params, -int payloadsz) +uint8_t *ptr,int payloadsz) {struct image_cfg_element *e;struct main_hdr_v1 *main_hdr; +#if defined(CONFIG_KWB_SECURE ) +struct secure_hdr_v1 *secure_hdr =NULL ; +#endif size_t headersz;uint8_t *image, *cur;int hasext =0 ; +uint8_t *next_ext =NULL ;/* * Calculate the size of the header and the size of the @@ -474,7 +1155,9 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,memset (image,0 , headersz); main_hdr = (struct main_hdr_v1 *)image; - cur = image +sizeof (struct main_hdr_v1 ); + cur = image; + cur +=sizeof (struct main_hdr_v1 ); + next_ext = &main_hdr->ext;/* Fill the main header */ main_hdr->blocksize =@@ -497,9 +1180,28 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,if (e) main_hdr->nandbadblklocation = e->nandbadblklocation; +#if defined(CONFIG_KWB_SECURE ) +if (image_get_csk_index () >=0 ) { +/* +* only reserve the space here; we fill the header later since +* we need the header to be complete to compute the signatures +*/ + secure_hdr = (struct secure_hdr_v1 *)cur; + cur +=sizeof (struct secure_hdr_v1 ); + next_ext = &secure_hdr->next; + } +#endif + *next_ext =1 ; +if (add_binary_header_v1 (cur))return NULL ; +#if defined(CONFIG_KWB_SECURE ) +if (secure_hdr &&add_secure_header_v1 (params, ptr, payloadsz, + headersz, image, secure_hdr)) +return NULL ; +#endif +/* Calculate and set the header checksum */ main_hdr->checksum =image_checksum8 (main_hdr, headersz);@@ -605,6 +1307,36 @@ static int image_create_config_parse_oneline(char *line, el->regdata.raddr =strtoul (value1,NULL ,16 ); el->regdata.rdata =strtoul (value2,NULL ,16 );break ; +case IMAGE_CFG_KAK : + el->key_name =strdup (value1); +break ; +case IMAGE_CFG_CSK : + el->key_name =strdup (value1); +break ; +case IMAGE_CFG_CSK_INDEX : + el->csk_idx =strtol (value1,NULL ,0 ); +break ; +case IMAGE_CFG_JTAG_DELAY : + el->jtag_delay =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_BOX_ID : + el->boxid =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_FLASH_ID : + el->flashid =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_SEC_SPECIALIZED_IMG : + el->sec_specialized_img = true; +break ; +case IMAGE_CFG_SEC_COMMON_IMG : + el->sec_specialized_img = false; +break ; +case IMAGE_CFG_SEC_BOOT_DEV : + el->sec_boot_dev =strtoul (value1,NULL ,0 ); +break ; +case IMAGE_CFG_SEC_FUSE_DUMP : + el->name =strdup (value1); +break ;default :fprintf (stderr, unknown_msg, line); }@@ -764,7 +1496,7 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,break ;case 1 : - image =image_create_v1 (&headersz, params, sbuf->st_size); + image =image_create_v1 (&headersz, params, ptr, sbuf->st_size);break ;default :tools/kwbimage.h +36
-0@@ -102,6 +102,43 @@ struct opt_hdr_v1 { };/* +* Public Key data in DER format +*/ +struct pubkey_der_v1 { +uint8_t key[524 ]; +}; + +/* +* Signature (RSA 2048) +*/ +struct sig_v1 { +uint8_t sig[256 ]; +}; + +/* +* Structure of secure header (Armada 38x) +*/ +struct secure_hdr_v1 { +uint8_t headertype;/* 0x0 */ +uint8_t headersz_msb;/* 0x1 */ +uint16_t headersz_lsb;/* 0x2 - 0x3 */ +uint32_t reserved1;/* 0x4 - 0x7 */ +struct pubkey_der_v1 kak;/* 0x8 - 0x213 */ +uint8_t jtag_delay;/* 0x214 */ +uint8_t reserved2;/* 0x215 */ +uint16_t reserved3;/* 0x216 - 0x217 */ +uint32_t boxid;/* 0x218 - 0x21B */ +uint32_t flashid;/* 0x21C - 0x21F */ +struct sig_v1 hdrsig;/* 0x220 - 0x31F */ +struct sig_v1 imgsig;/* 0x320 - 0x41F */ +struct pubkey_der_v1 csk[16 ];/* 0x420 - 0x24DF */ +struct sig_v1 csksig;/* 0x24E0 - 0x25DF */ +uint8_t next;/* 0x25E0 */ +uint8_t reserved4;/* 0x25E1 */ +uint16_t reserved5;/* 0x25E2 - 0x25E3 */ +}; +
Quoted 9 lines
tools/kwbimage.h struct opt_hdr_v1 { · line 144
Quoted 5 lines
tools/kwbimage.h +1
-0+/* * Various values for the opt_hdr_v1->headertype field, describing the * different types of optional headers. The "secure" header contains * informations related to secure boot (encryption keys, etc.). The Thanks,
Stefan
Thanks for the review!
Best regards,
Mario
PATCH 16/17 arm: mvebu: Add gdsys ControlCenter-Compact board
In reply to Mario SixFrom: Dirk Eibach <[email protected]>
The gdsys ControlCenter Digital board is based on a Marvell Armada 38x SOC.
It boots from SPI-Flash but can be configured to boot from SD-card for factory programming and testing.
On board peripherals include:
- 2 x GbE
- Xilinx Kintex-7 FPGA connected via PCIe
- mSATA
- USB3 host
- Atmel TPM
--- arch/arm/Kconfig | 1 + arch/arm/dts/Makefile | 3 +- arch/arm/dts/controlcenterdc.dts | 629 +++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/Kconfig | 4 + board/gdsys/38x/.gitignore | 1 + board/gdsys/38x/Kconfig | 42 +++ board/gdsys/38x/MAINTAINERS | 7 + board/gdsys/38x/Makefile | 30 ++ board/gdsys/38x/README | 18 + board/gdsys/38x/controlcenterdc.c | 717 ++++++++++++++++++++++++++++++++++++++ board/gdsys/38x/dt_helpers.c | 60 ++++ board/gdsys/38x/dt_helpers.h | 16 + board/gdsys/38x/hre.c | 517 +++++++++++++++++++++++++++ board/gdsys/38x/hre.h | 38 ++ board/gdsys/38x/keyprogram.c | 158 +++++++++ board/gdsys/38x/keyprogram.h | 14 + board/gdsys/38x/kwbimage.cfg.in | 12 + board/gdsys/38x/spl.c | 21 ++ configs/controlcenterdc_defconfig | 54 +++ include/configs/controlcenterdc.h | 244 +++++++++++++ 20 files changed, 2585 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/controlcenterdc.dts create mode 100644 board/gdsys/38x/.gitignore create mode 100644 board/gdsys/38x/Kconfig create mode 100644 board/gdsys/38x/MAINTAINERS create mode 100644 board/gdsys/38x/Makefile create mode 100644 board/gdsys/38x/README create mode 100644 board/gdsys/38x/controlcenterdc.c create mode 100644 board/gdsys/38x/dt_helpers.c create mode 100644 board/gdsys/38x/dt_helpers.h create mode 100644 board/gdsys/38x/hre.c create mode 100644 board/gdsys/38x/hre.h create mode 100644 board/gdsys/38x/keyprogram.c create mode 100644 board/gdsys/38x/keyprogram.h create mode 100644 board/gdsys/38x/kwbimage.cfg.in create mode 100644 board/gdsys/38x/spl.c create mode 100644 configs/controlcenterdc_defconfig create mode 100644 include/configs/controlcenterdc.h
arch/arm/Kconfig +1 -0
@@ -970,6 +970,7 @@ source "board/freescale/mx53loco/Kconfig" source "board/freescale/mx53smd/Kconfig" source "board/freescale/s32v234evb/Kconfig" source "board/freescale/vf610twr/Kconfig" +source "board/gdsys/38x/Kconfig" source "board/gumstix/pepper/Kconfig" source "board/h2200/Kconfig" source "board/hisilicon/hikey/Kconfig"
arch/arm/dts/Makefile +2 -1
@@ -76,7 +76,8 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-xp-gp.dtb \ armada-xp-maxbcm.dtb \ armada-xp-synology-ds414.dtb \ - armada-xp-theadorable.dtb + armada-xp-theadorable.dtb \ + controlcenterdc.dtb dtb-$(CONFIG_ARCH_UNIPHIER) += \ uniphier-ld11-ref.dtb \
arch/arm/dts/controlcenterdc.dts new file +629 -0
629 lines not on this page · raw message
arch/arm/mach-mvebu/Kconfig +4 -0
@@ -102,6 +102,10 @@ config TARGET_THEADORABLE bool "Support theadorable Armada XP" select MV78260 +config TARGET_CONTROLCENTERDC + bool "Support CONTROLCENTERDC" + select 88F6820 + endchoice config SYS_BOARD
board/gdsys/38x/.gitignore new file +1 -0
@@ -0,0 +1 @@ +kwbimage.cfg
board/gdsys/38x/Kconfig new file +42 -0
42 lines not on this page · raw message
board/gdsys/38x/MAINTAINERS new file +7 -0
@@ -0,0 +1,7 @@ +38X BOARD +M: Dirk Eibach <[email protected]> +M: Mario Six <[email protected]> +S: Maintained +F: board/gdsys/38x/ +F: include/configs/controlcenterdc.h +F: configs/controlcenterdc_defconfig
board/gdsys/38x/Makefile new file +30 -0
@@ -0,0 +1,30 @@ +# +# Copyright (C) 2015 Stefan Roese <[email protected]> +# Copyright (C) 2015 Reinhard Pfau <[email protected]> +# Copyright (C) 2016 Mario Six <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += controlcenterdc.o hre.o spl.o keyprogram.o dt_helpers.o + +ifeq ($(CONFIG_SPL_BUILD),) + +extra-$(CONFIG_TARGET_CONTROLCENTERDC) += kwbimage.cfg + +ifneq ($(CONFIG_TARGET_CONTROLCENTERDC),) +KWB_REPLACE += BOOT_FROM +ifneq ($(CONFIG_SPL_BOOT_DEVICE_SPI),) + KWB_CFG_BOOT_FROM=spi +endif +ifneq ($(CONFIG_SPL_BOOT_DEVICE_MMC),) + KWB_CFG_BOOT_FROM=sdio +endif +endif + +$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ + include/config/auto.conf + $(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ + <$< >$@ + +endif
board/gdsys/38x/README new file +18 -0
@@ -0,0 +1,18 @@ +Update from original Marvell U-Boot to mainline U-Boot: +------------------------------------------------------- + +The resulting image including the SPL binary with the +full DDR setup is "u-boot-spl.kwb". + +To update the SPI NOR flash, please use the following +command: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf update 2000000 0 60000 + +Note that the original Marvell U-Boot seems to have +problems with the "sf update" command. This does not +work reliable. So here this command should be used: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf erase 0 60000;sf write 2000000 0 60000
board/gdsys/38x/controlcenterdc.c new file +717 -0
717 lines not on this page · raw message
board/gdsys/38x/dt_helpers.c new file +60 -0
60 lines not on this page · raw message
board/gdsys/38x/dt_helpers.h new file +16 -0
@@ -0,0 +1,16 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __DT_HELPERS_H +#define __DT_HELPERS_H + +bool get_gpio (char *name,struct gpio_desc *gpio); +int fdt_disable_by_ofname (char *ofname); +struct udevice *dev_get_by_ofname (char *ofname); +bool dm_i2c_simple_probe (struct udevice *bus,uint chip_addr); + +#endif /* __DT_HELPERS_H */
board/gdsys/38x/hre.c new file +517 -0
517 lines not on this page · raw message
board/gdsys/38x/hre.h new file +38 -0
@@ -0,0 +1,38 @@ +/* +* (C) Copyright 2013 +* Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __HRE_H +#define __HRE_H + +struct key_program { +uint32_t magic; +uint32_t code_crc; +uint32_t code_size; +uint8_t code[]; +}; + +struct h_reg { +bool valid; +uint8_t digest[20 ]; +}; + +/* CCDM specific contants */ +enum { +/* NV indices */ +NV_COMMON_DATA_INDEX =0x40000001 , +/* magics for key blob chains */ +MAGIC_KEY_PROGRAM =0x68726500 , +MAGIC_HMAC =0x68616300 , +MAGIC_END_OF_CHAIN =0x00000000 , +/* sizes */ +NV_COMMON_DATA_MIN_SIZE =3 *sizeof (uint64_t ) +2 *sizeof (uint16_t ), +}; + +int hre_verify_program (struct key_program *prg); +int hre_run_program (const uint8_t *code,size_t code_size); + +#endif /* __HRE_H */
board/gdsys/38x/keyprogram.c new file +158 -0
158 lines not on this page · raw message
board/gdsys/38x/keyprogram.h new file +14 -0
@@ -0,0 +1,14 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __KEYPROGRAM_H +#define __KEYPROGRAM_H + +int load_and_run_keyprog (void ); +int flush_keys (void ); + +#endif /* __KEYPROGRAM_H */
board/gdsys/38x/kwbimage.cfg.in new file +12 -0
@@ -0,0 +1,12 @@ +# +# Copyright (C) 2014 Stefan Roese <[email protected]> +# + +# Armada 38x uses version 1 image format +VERSION 1 + +# Boot Media configurations +#@BOOT_FROM + +# Binary Header (bin_hdr) with DDR3 training code +BINARY spl/u-boot-spl.bin 0000005b 00000068
board/gdsys/38x/spl.c new file +21 -0
@@ -0,0 +1,21 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <config.h> +#include <asm/arch/cpu.h> + +void spl_board_init (void ) +{ +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SPI_NOR_FLASH +u32 *bootrom_save = (u32 *)CONFIG_SPL_BOOTROM_SAVE ; +u32 *regs = (u32 *)(*bootrom_save); + +printf ("Returning to BootROM (return address %08x)...\n" , regs[13 ]); +return_to_bootrom (); +#endif +}
configs/controlcenterdc_defconfig new file +54 -0
54 lines not on this page · raw message
include/configs/controlcenterdc.h new file +244 -0
244 lines not on this page · raw message
Signature · 1 line
2.9.0
PATCH 16/17 arm: mvebu: Add gdsys ControlCenter-Compact board
Quoted 15 lines · Mario Six
From: Dirk Eibach <[email protected]>
The gdsys ControlCenter Digital board is based on a Marvell Armada 38x SOC.
It boots from SPI-Flash but can be configured to boot from SD-card for factory programming and testing.
On board peripherals include:
- 2 x GbE
- Xilinx Kintex-7 FPGA connected via PCIe
- mSATA
- USB3 host
- Atmel TPM
Quoted 6 lines
Signed-off-by Dirk Eibach <[email protected]>Signed-off-by Mario Six <[email protected]>--- arch/arm/Kconfig | 1 + arch/arm/dts/Makefile | 3 +- arch/arm/dts/controlcenterdc.dts | 629 +++++++++++++++++++++++++++++++++
Could you perhaps rename this file (and board name as well?) to something like "armada-38x-controlcenterdc*" instead? Its much easier to match the files to the architecture this way. And until now, all Armada XP / 38x (etc) files match this rule.
Quoted 2 lines
arch/arm/mach-mvebu/Kconfig | 4 + board/gdsys/38x/.gitignore | 1 +
Perhaps better s/38x/a38x for "Armada"?
Quoted 751 lines
board/gdsys/38x/Kconfig | 42 +++ board/gdsys/38x/MAINTAINERS | 7 + board/gdsys/38x/Makefile | 30 ++ board/gdsys/38x/README | 18 + board/gdsys/38x/controlcenterdc.c | 717 ++++++++++++++++++++++++++++++++++++++ board/gdsys/38x/dt_helpers.c | 60 ++++ board/gdsys/38x/dt_helpers.h | 16 + board/gdsys/38x/hre.c | 517 +++++++++++++++++++++++++++ board/gdsys/38x/hre.h | 38 ++ board/gdsys/38x/keyprogram.c | 158 +++++++++ board/gdsys/38x/keyprogram.h | 14 + board/gdsys/38x/kwbimage.cfg.in | 12 + board/gdsys/38x/spl.c | 21 ++ configs/controlcenterdc_defconfig | 54 +++ include/configs/controlcenterdc.h | 244 +++++++++++++ 20 files changed, 2585 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/controlcenterdc.dts create mode 100644 board/gdsys/38x/.gitignore create mode 100644 board/gdsys/38x/Kconfig create mode 100644 board/gdsys/38x/MAINTAINERS create mode 100644 board/gdsys/38x/Makefile create mode 100644 board/gdsys/38x/README create mode 100644 board/gdsys/38x/controlcenterdc.c create mode 100644 board/gdsys/38x/dt_helpers.c create mode 100644 board/gdsys/38x/dt_helpers.h create mode 100644 board/gdsys/38x/hre.c create mode 100644 board/gdsys/38x/hre.h create mode 100644 board/gdsys/38x/keyprogram.c create mode 100644 board/gdsys/38x/keyprogram.h create mode 100644 board/gdsys/38x/kwbimage.cfg.in create mode 100644 board/gdsys/38x/spl.c create mode 100644 configs/controlcenterdc_defconfig create mode 100644 include/configs/controlcenterdc.harch/arm/Kconfig +1
-0@@ -970,6 +970,7 @@ source "board/freescale/mx53loco/Kconfig" source "board/freescale/mx53smd/Kconfig" source "board/freescale/s32v234evb/Kconfig" source "board/freescale/vf610twr/Kconfig" +source "board/gdsys/38x/Kconfig" source "board/gumstix/pepper/Kconfig" source "board/h2200/Kconfig" source "board/hisilicon/hikey/Kconfig"arch/arm/dts/Makefile +2
-1@@ -76,7 +76,8 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-xp-gp.dtb \ armada-xp-maxbcm.dtb \ armada-xp-synology-ds414.dtb \ - armada-xp-theadorable.dtb + armada-xp-theadorable.dtb \ + controlcenterdc.dtb dtb-$(CONFIG_ARCH_UNIPHIER) += \ uniphier-ld11-ref.dtb \arch/arm/dts/controlcenterdc.dts new file +629
-0@@ -0,0 +1,629 @@ +/* + * Device Tree file for the Guntermann & Drunck ControlCenter-Compact board + * + * Copyright (C) 2016 Mario Six <[email protected]> + * + * based on the Device Tree file for Marvell Armada 388 evaluation board + * (DB-88F6820), which is + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni <[email protected]> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +#include "armada-388.dtsi" + +&uart0 { + u-boot,dm-pre-reloc; +}; + +&uart1 { + u-boot,dm-pre-reloc; +}; + +/ { + model = "Controlcenter Digital Compact"; + compatible = "marvell,a385-db", "marvell,armada388", + "marvell,armada385", "marvell,armada380"; + + chosen { + bootargs = "console=ttyS1,115200 earlyprintk"; + stdout-path = "/soc/internal-regs/serial at 12100"; + }; + + aliases { + ethernet0 = ð0; + ethernet2 = ð2; + mdio-gpio0 = &MDIO0; + mdio-gpio1 = &MDIO1; + mdio-gpio2 = &MDIO2; + spi0 = &spi0; + spi1 = &spi1; + i2c0 = &I2C0; + i2c1 = &I2C1; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; /* 256 MB */ + }; + + clocks { + sc16isclk: sc16isclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <11059200>; + }; + }; + + soc { + ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000 + MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>; + + internal-regs { + spi0: spi at 10600 { + status = "okay"; + sc16is741: sc16is741 at 0 { + compatible = "nxp,sc16is741"; + reg = <0>; + clocks = <&sc16isclk>; + spi-max-frequency = <4000000>; + interrupt-parent = <&gpio0>; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + spi1: spi at 10680 { + status = "okay"; + u-boot,dm-pre-reloc; + spi-flash at 0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q016a"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <108000000>; + }; + spi-flash at 1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128a11"; + reg = <1>; /* Chip select 1 */ + spi-max-frequency = <108000000>; + u-boot,dm-pre-reloc; + }; + }; + + I2C0: i2c at 11000 { + status = "okay"; + clock-frequency = <1000000>; + u-boot,dm-pre-reloc; + PCA21: pca9698 at 21 { + compatible = "nxp,pca9698"; + reg = <0x21>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA22: pca9698 at 22 { + compatible = "nxp,pca9698"; + u-boot,dm-pre-reloc; + reg = <0x22>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA23: pca9698 at 23 { + compatible = "nxp,pca9698"; + reg = <0x23>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA24: pca9698 at 24 { + compatible = "nxp,pca9698"; + reg = <0x24>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA25: pca9698 at 25 { + compatible = "nxp,pca9698"; + reg = <0x25>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA26: pca9698 at 26 { + compatible = "nxp,pca9698"; + reg = <0x26>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + + I2C1: i2c at 11100 { + status = "okay"; + clock-frequency = <400000>; + at97sc3205t at 29 { + compatible = "atmel,at97sc3204t"; + reg = <0x29>; + u-boot,i2c-offset-len = <0>; + }; + emc2305 at 2d { + compatible = "smsc,emc2305"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2d>; + fan at 0 { + reg = <0>; + }; + fan at 1 { + reg = <1>; + }; + fan at 2 { + reg = <2>; + }; + fan at 3 { + reg = <3>; + }; + fan at 4 { + reg = <4>; + }; + }; + lm77 at 48 { + compatible = "national,lm77"; + reg = <0x48>; + }; + ads1015 at 49 { + compatible = "ti,ads1015"; + reg = <0x49>; + }; + lm77 at 4a { + compatible = "national,lm77"; + reg = <0x4a>; + }; + ads1015 at 4b { + compatible = "ti,ads1015"; + reg = <0x4b>; + }; + emc2305 at 4c { + compatible = "smsc,emc2305"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4c>; + fan at 0 { + reg = <0>; + }; + fan at 1 { + reg = <1>; + }; + fan at 2 { + reg = <2>; + }; + fan at 3 { + reg = <3>; + }; + fan at 4 { + reg = <4>; + }; + }; + at24c512 at 54 { + compatible = "atmel,24c512"; + reg = <0x54>; + u-boot,i2c-offset-len = <2>; + }; + ds1339 at 68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + serial at 12000 { + status = "okay"; + }; + + serial at 12100 { + status = "okay"; + }; + + ethernet at 34000 { + status = "okay"; + phy = <&phy1>; + phy-mode = "sgmii"; + }; + + usb at 58000 { + status = "ok"; + }; + + ethernet at 70000 { + status = "okay"; + phy = <&phy0>; + phy-mode = "sgmii"; + }; + + mdio at 72004 { + phy0: ethernet-phy at 0 { + reg = <1>; + }; + + phy1: ethernet-phy at 1 { + reg = <0>; + }; + }; + + sata at a8000 { + status = "okay"; + }; + + sdhci at d8000 { + broken-cd; + wp-inverted; + bus-width = <4>; + status = "okay"; + no-1-8-v; + }; + + usb3 at f0000 { + status = "okay"; + }; + }; + + pcie-controller { + status = "okay"; + /* + * The two PCIe units are accessible through + * standard PCIe slots on the board. + */ + pcie at 3,0 { + /* Port 0, Lane 0 */ + status = "okay"; + }; + }; + + MDIO0: mdio0 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio0 13 0 + /*MDIO*/ &gpio0 14 0>; + mv88e1240 at 0 { + reg = <0x0>; + }; + mv88e1240 at 1 { + reg = <0x1>; + }; + mv88e1240 at 2 { + reg = <0x2>; + }; + mv88e1240 at 3 { + reg = <0x3>; + }; + mv88e1240 at 4 { + reg = <0x4>; + }; + mv88e1240 at 5 { + reg = <0x5>; + }; + mv88e1240 at 6 { + reg = <0x6>; + }; + mv88e1240 at 7 { + reg = <0x7>; + }; + mv88e1240 at 8 { + reg = <0x8>; + }; + mv88e1240 at 9 { + reg = <0x9>; + }; + mv88e1240 at a { + reg = <0xa>; + }; + mv88e1240 at b { + reg = <0xb>; + }; + mv88e1240 at c { + reg = <0xc>; + }; + mv88e1240 at d { + reg = <0xd>; + }; + mv88e1240 at e { + reg = <0xe>; + }; + mv88e1240 at f { + reg = <0xf>; + }; + mv88e1240 at 10 { + reg = <0x10>; + }; + mv88e1240 at 11 { + reg = <0x11>; + }; + mv88e1240 at 12 { + reg = <0x12>; + }; + mv88e1240 at 13 { + reg = <0x13>; + }; + mv88e1240 at 14 { + reg = <0x14>; + }; + mv88e1240 at 15 { + reg = <0x15>; + }; + mv88e1240 at 16 { + reg = <0x16>; + }; + mv88e1240 at 17 { + reg = <0x17>; + }; + mv88e1240 at 18 { + reg = <0x18>; + }; + mv88e1240 at 19 { + reg = <0x19>; + }; + mv88e1240 at 1a { + reg = <0x1a>; + }; + mv88e1240 at 1b { + reg = <0x1b>; + }; + mv88e1240 at 1c { + reg = <0x1c>; + }; + mv88e1240 at 1d { + reg = <0x1d>; + }; + mv88e1240 at 1e { + reg = <0x1e>; + }; + mv88e1240 at 1f { + reg = <0x1f>; + }; + }; + + MDIO1: mdio1 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio0 25 0 + /*MDIO*/ &gpio1 13 0>; + mv88e1240 at 0 { + reg = <0x0>; + }; + mv88e1240 at 1 { + reg = <0x1>; + }; + mv88e1240 at 2 { + reg = <0x2>; + }; + mv88e1240 at 3 { + reg = <0x3>; + }; + mv88e1240 at 4 { + reg = <0x4>; + }; + mv88e1240 at 5 { + reg = <0x5>; + }; + mv88e1240 at 6 { + reg = <0x6>; + }; + mv88e1240 at 7 { + reg = <0x7>; + }; + mv88e1240 at 8 { + reg = <0x8>; + }; + mv88e1240 at 9 { + reg = <0x9>; + }; + mv88e1240 at a { + reg = <0xa>; + }; + mv88e1240 at b { + reg = <0xb>; + }; + mv88e1240 at c { + reg = <0xc>; + }; + mv88e1240 at d { + reg = <0xd>; + }; + mv88e1240 at e { + reg = <0xe>; + }; + mv88e1240 at f { + reg = <0xf>; + }; + mv88e1240 at 10 { + reg = <0x10>; + }; + mv88e1240 at 11 { + reg = <0x11>; + }; + mv88e1240 at 12 { + reg = <0x12>; + }; + mv88e1240 at 13 { + reg = <0x13>; + }; + mv88e1240 at 14 { + reg = <0x14>; + }; + mv88e1240 at 15 { + reg = <0x15>; + }; + mv88e1240 at 16 { + reg = <0x16>; + }; + mv88e1240 at 17 { + reg = <0x17>; + }; + mv88e1240 at 18 { + reg = <0x18>; + }; + mv88e1240 at 19 { + reg = <0x19>; + }; + mv88e1240 at 1a { + reg = <0x1a>; + }; + mv88e1240 at 1b { + reg = <0x1b>; + }; + mv88e1240 at 1c { + reg = <0x1c>; + }; + mv88e1240 at 1d { + reg = <0x1d>; + }; + mv88e1240 at 1e { + reg = <0x1e>; + }; + mv88e1240 at 1f { + reg = <0x1f>; + }; + }; + + MDIO2: mdio2 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio1 14 0 + /*MDIO*/ &gpio0 24 0>; + mv88e1240 at 0 { + reg = <0x0>; + }; + mv88e1240 at 1 { + reg = <0x1>; + }; + mv88e1240 at 2 { + reg = <0x2>; + }; + mv88e1240 at 3 { + reg = <0x3>; + }; + mv88e1240 at 4 { + reg = <0x4>; + }; + mv88e1240 at 5 { + reg = <0x5>; + }; + mv88e1240 at 6 { + reg = <0x6>; + }; + mv88e1240 at 7 { + reg = <0x7>; + }; + mv88e1240 at 8 { + reg = <0x8>; + }; + mv88e1240 at 9 { + reg = <0x9>; + }; + mv88e1240 at a { + reg = <0xa>; + }; + mv88e1240 at b { + reg = <0xb>; + }; + mv88e1240 at c { + reg = <0xc>; + }; + mv88e1240 at d { + reg = <0xd>; + }; + mv88e1240 at e { + reg = <0xe>; + }; + mv88e1240 at f { + reg = <0xf>; + }; + mv88e1240 at 10 { + reg = <0x10>; + }; + mv88e1240 at 11 { + reg = <0x11>; + }; + mv88e1240 at 12 { + reg = <0x12>; + }; + mv88e1240 at 13 { + reg = <0x13>; + }; + mv88e1240 at 14 { + reg = <0x14>; + }; + mv88e1240 at 15 { + reg = <0x15>; + }; + }; + }; + + cat_gpio_0 { + compatible = "generic,cat-gpio-0"; + gpios = <&PCA23 0x20 0x0>; + }; + + cat_gpio_1 { + compatible = "generic,cat-gpio-1"; + gpios = <&PCA21 0x20 0x0>; + }; + + cat_gpio_2 { + compatible = "generic,cat-gpio-2"; + gpios = <&PCA24 0x20 0x0>; + }; + + cat_gpio_3 { + compatible = "generic,cat-gpio-3"; + gpios = <&PCA25 0x20 0x0>; + }; + + cat_gpio_4 { + compatible = "generic,cat-gpio-4"; + gpios = <&PCA26 0x20 0x0>; + }; + + second_octo_gpio_0 { + compatible = "generic,second-octo-gpio-0"; + gpios = <&PCA23 0x27 0x0>; + }; + + fpga_program_gpio { + compatible = "generic,fpga-program-gpio"; + u-boot,dm-pre-reloc; + gpios = <&PCA22 31 0>; + }; + + fpga_done_gpio { + compatible = "generic,fpga-done-gpio"; + u-boot,dm-pre-reloc; + gpios = <&PCA22 19 0>; + }; + + fpga_ready_gpio { + compatible = "generic,fpga-ready-gpio"; + u-boot,dm-pre-reloc; + gpios = <&PCA22 27 0>; + }; + + leds { + compatible = "gpio-leds"; + + finder_led { + label = "finder-led"; + gpios = <&PCA22 25 0>; + }; + + status_led { + label = "status-led"; + gpios = <&gpio0 29 0>; + }; + }; +};arch/arm/mach-mvebu/Kconfig +4
-0@@ -102,6 +102,10 @@ config TARGET_THEADORABLE bool "Support theadorable Armada XP" select MV78260 +config TARGET_CONTROLCENTERDC + bool "Support CONTROLCENTERDC" + select 88F6820 + endchoice config SYS_BOARDboard/gdsys/38x/.gitignore new file +1
-0@@ -0,0 +1 @@ +kwbimage.cfgboard/gdsys/38x/Kconfig new file +28
-0@@ -0,0 +1,42 @@ +if TARGET_CONTROLCENTERDC + +config SYS_BOARD + default "38x" + +config SYS_VENDOR + default "gdsys" + +config SYS_SOC + default "mvebu" + +config SYS_CONFIG_NAME + default "controlcenterdc" + +menu "Controlcenter DC board options" + +choice + prompt "Select boot method" + +config SPL_BOOT_DEVICE_SPI + bool "SPI" + +config SPL_BOOT_DEVICE_MMC + bool "MMC" + select SPL_LIBDISK_SUPPORT + +endchoice +
board/gdsys/38x/Kconfig line 38
Quoted 10 lines
board/gdsys/38x/Kconfig new file +10
-0+#config SPL_BOOT_DEVICE +# int +# default 1 if SPL_BOOT_DEVICE_SPI +# default 2 if SPL_BOOT_DEVICE_MMC + +config SYS_BOOTIMAGE_DEST_ADDR + hex "Boot image destination address" + default 0x007fffc0 + help + Blah
Hmmm, the help text is not really "helpful". ;)
This option is also not referenced, so perhaps you can remove it?
Quoted 36 lines
board/gdsys/38x/Kconfig new file +4
-0+ +endmenu + +endifboard/gdsys/38x/MAINTAINERS new file +7
-0@@ -0,0 +1,7 @@ +38X BOARD +M: Dirk Eibach <[email protected]> +M: Mario Six <[email protected]> +S: Maintained +F: board/gdsys/38x/ +F: include/configs/controlcenterdc.h +F: configs/controlcenterdc_defconfigboard/gdsys/38x/Makefile new file +13
-0@@ -0,0 +1,30 @@ +# +# Copyright (C) 2015 Stefan Roese <[email protected]> +# Copyright (C) 2015 Reinhard Pfau <[email protected]> +# Copyright (C) 2016 Mario Six <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += controlcenterdc.o hre.o spl.o keyprogram.o dt_helpers.o + +ifeq ($(CONFIG_SPL_BUILD),) + +extra-$(CONFIG_TARGET_CONTROLCENTERDC) += kwbimage.cfg
board/gdsys/38x/Makefile line 23
Quoted 10 lines
board/gdsys/38x/Makefile new file +10
-0+ +ifneq ($(CONFIG_TARGET_CONTROLCENTERDC),) +KWB_REPLACE += BOOT_FROM +ifneq ($(CONFIG_SPL_BOOT_DEVICE_SPI),) + KWB_CFG_BOOT_FROM=spi +endif +ifneq ($(CONFIG_SPL_BOOT_DEVICE_MMC),) + KWB_CFG_BOOT_FROM=sdio +endif +endif
Do you have multiple build targets for this directory? Do you need to have this check with CONFIG_TARGET_CONTROLCENTERDC?
Quoted 21 lines
board/gdsys/38x/Makefile new file +7
-0+ +$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ + include/config/auto.conf + $(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ + <$< >$@ + +endifboard/gdsys/38x/README new file +8
-0@@ -0,0 +1,18 @@ +Update from original Marvell U-Boot to mainline U-Boot: +------------------------------------------------------- + +The resulting image including the SPL binary with the +full DDR setup is "u-boot-spl.kwb". + +To update the SPI NOR flash, please use the following +command:
board/gdsys/38x/README line 18
Quoted 10 lines
board/gdsys/38x/README new file +10
-0+ +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf update 2000000 0 60000 + +Note that the original Marvell U-Boot seems to have +problems with the "sf update" command. This does not +work reliable. So here this command should be used: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf erase 0 60000;sf write 2000000 0 60000
You copied this file from the Marvell directory. Does it really make sense to add it here as well? I suggest to just remove it.
Quoted 146 lines
board/gdsys/38x/controlcenterdc.c new file +140
-0@@ -0,0 +1,717 @@ +/* +* Copyright (C) 2015 Stefan Roese <[email protected]> +* Copyright (C) 2016 Mario Six <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <console.h> /* disable_ctrlc */ +#include <miiphy.h> +#include <tpm.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm-generic/gpio.h> + +#include "../drivers/ddr/marvell/a38x/ddr3_a38x_topology.h" +#include "../arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h" + +#include "keyprogram.h" +#include "dt_helpers.h" + +DECLARE_GLOBAL_DATA_PTR ; + +#define ETH_PHY_CTRL_REG 0 +#define ETH_PHY_CTRL_POWER_DOWN_BIT 11 +#define ETH_PHY_CTRL_POWER_DOWN_MASK (1 << ETH_PHY_CTRL_POWER_DOWN_BIT) + +#define DB_GP_88F68XX_GPP_OUT_ENA_LOW 0x7fffffff +#define DB_GP_88F68XX_GPP_OUT_ENA_MID 0xffffefff + +#define DB_GP_88F68XX_GPP_OUT_VAL_LOW 0x0 +#define DB_GP_88F68XX_GPP_OUT_VAL_MID 0x00001000 +#define DB_GP_88F68XX_GPP_POL_LOW 0x0 +#define DB_GP_88F68XX_GPP_POL_MID 0x0 + +#ifndef CONFIG_SPL_BUILD +enum { +HWVER_100 =0 , +HWVER_110 =1 , +HWVER_120 =2 , +}; + +enum { +PORTTYPE_MAIN_CAT , +PORTTYPE_TOP_CAT , +PORTTYPE_16C_16F , +PORTTYPE_UNKNOWN +}; + +static struct porttype { +bool phy_invert_in_pol; +bool phy_invert_out_pol; +} porttypes[] = { + { true, false }, + { false, true }, + { false, false }, +}; + +struct ihs_fpga { +u32 reflection_low;/* 0x0000 */ +u32 versions;/* 0x0004 */ +u32 fpga_version;/* 0x0008 */ +u32 fpga_features;/* 0x000c */ +u32 reserved0[4 ];/* 0x0010 */ +u32 control;/* 0x0020 */ +u32 reserved1[375 ];/* 0x0024 */ +u32 qsgmii_port_state[80 ];/* 0x0600 */ +}; + +static struct ihs_fpga *fpga; + +static struct pci_device_id hydra_supported[] = { + {0x6d5e ,0xcdc1 }, + {} +}; +#endif + +/* +* Define the DDR layout / topology here in the board file. This will +* be used by the DDR3 init code in the SPL U-Boot version to configure +* the DDR3 controller. +*/ +static struct hws_topology_map ddr_topology_map = { +0x1 ,/* active interfaces */ +/* cs_mask, mirror, dqs_swap, ck_swap X PUPs */ + { { { {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 } }, +SPEED_BIN_DDR_1600K ,/* speed_bin */ +BUS_WIDTH_16 ,/* memory_width */ +MEM_4G ,/* mem_size */ +DDR_FREQ_533 ,/* frequency */ +0 ,0 ,/* cas_l cas_wl */ +HWS_TEMP_LOW } },/* temperature */ +5 ,/* Num Of Bus Per Interface*/ +BUS_MASK_32BIT /* Busses mask */ +}; + +static struct serdes_map serdes_topology_map[] = { + {SGMII0 ,SERDES_SPEED_1_25_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, + {USB3_HOST0 ,SERDES_SPEED_5_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, +/* SATA tx polarity is inverted */ + {SATA1 ,SERDES_SPEED_3_GBPS ,SERDES_DEFAULT_MODE ,0 ,1 }, + {SGMII2 ,SERDES_SPEED_1_25_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, + {DEFAULT_SERDES ,SERDES_SPEED_3_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, + {PEX2 ,SERDES_SPEED_5_GBPS ,PEX_ROOT_COMPLEX_X1 ,0 ,0 } +}; + +int hws_board_topology_load (struct serdes_map **serdes_map_array,u8 *count) +{ + *serdes_map_array = serdes_topology_map; + *count =ARRAY_SIZE (serdes_topology_map); +return 0 ; +} + +void board_pex_config (void ) +{ +#ifdef CONFIG_SPL_BUILD +uint k; +struct gpio_desc gpio = {}; + +if (get_gpio ("generic,fpga-program-gpio" , &gpio)) { +/* prepare FPGA reconfiguration */ +dm_gpio_set_dir_flags (&gpio,GPIOD_IS_OUT ); +dm_gpio_set_value (&gpio,0 ); + +/* give lunatic PCIe clock some time to stabilize */ +mdelay (500 ); + +/* start FPGA reconfiguration */ +dm_gpio_set_dir_flags (&gpio,GPIOD_IS_IN ); + } + +/* wait for FPGA done */ +if (get_gpio ("generic,fpga-done-gpio" , &gpio)) { +for (k =0 ; k <20 ; ++k) { +if (dm_gpio_get_value (&gpio)) {
board/gdsys/38x/controlcenterdc.c line 150
Quoted 10 lines
board/gdsys/38x/controlcenterdc.c new file +10
-0+printf ("FPGA done after %u rounds\n" , k); +break ; + } +mdelay (100 ); + } + } + +/* disable FPGA reset */ +kw_gpio_set_valid (6 ,GPIO_OUTPUT_OK ); +kw_gpio_direction_output (6 ,1 );
Ah, here you use the "old" GPIO infrastucture. Please move to the DM GPIO driver and use the generic API instead.
Quoted 50 lines
board/gdsys/38x/controlcenterdc.c new file +50
-0+ +/* wait for FPGA ready */ +if (get_gpio ("generic,fpga-ready-gpio" , &gpio)) { +for (k =0 ; k <2 ; ++k) { +if (!dm_gpio_get_value (&gpio)) +break ; +mdelay (100 ); + } + } +#endif +} + +struct hws_topology_map *ddr3_get_topology_map (void ) +{ +return &ddr_topology_map; +} + +int board_early_init_f (void ) +{ +#ifdef CONFIG_SPL_BUILD +/* Configure MPP */ +writel (0x00111111 ,MVEBU_MPP_BASE +0x00 ); +writel (0x40040000 ,MVEBU_MPP_BASE +0x04 ); +writel (0x00466444 ,MVEBU_MPP_BASE +0x08 ); +writel (0x00043300 ,MVEBU_MPP_BASE +0x0c ); +writel (0x44400000 ,MVEBU_MPP_BASE +0x10 ); +writel (0x20000334 ,MVEBU_MPP_BASE +0x14 ); +writel (0x40000000 ,MVEBU_MPP_BASE +0x18 ); +writel (0x00004444 ,MVEBU_MPP_BASE +0x1c ); + +/* Set GPP Out value */ +writel (DB_GP_88F68XX_GPP_OUT_VAL_LOW ,MVEBU_GPIO0_BASE +0x00 ); +writel (DB_GP_88F68XX_GPP_OUT_VAL_MID ,MVEBU_GPIO1_BASE +0x00 ); + +/* Set GPP Polarity */ +writel (DB_GP_88F68XX_GPP_POL_LOW ,MVEBU_GPIO0_BASE +0x0c ); +writel (DB_GP_88F68XX_GPP_POL_MID ,MVEBU_GPIO1_BASE +0x0c ); + +/* Set GPP Out Enable */ +writel (DB_GP_88F68XX_GPP_OUT_ENA_LOW ,MVEBU_GPIO0_BASE +0x04 ); +writel (DB_GP_88F68XX_GPP_OUT_ENA_MID ,MVEBU_GPIO1_BASE +0x04 ); +#endif + +return 0 ; +} + +int board_init (void ) +{ +/* adress of boot parameters */ + gd->bd->bi_boot_params =mvebu_sdram_bar (0 ) +0x100 ;
board/gdsys/38x/controlcenterdc.c line 210
Quoted 10 lines
board/gdsys/38x/controlcenterdc.c new file +10
-0+ +return 0 ; +} + +int checkboard (void ) +{ +puts ("Board: Controlcenter Digital Compact\n" ); + +return 0 ; +}
With DT support you should already get the board model printed from the DT. Do yo need this line here as well?
Quoted 87 lines
board/gdsys/38x/controlcenterdc.c new file +87
-0+ +#ifndef CONFIG_SPL_BUILD +static void ihs_phy_config (struct phy_device *phydev,bool qinpn,bool qoutpn) +{ +u16 reg; + +phy_config (phydev); + +/* enable QSGMII autonegotiation with flow control */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0004 ); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,16 ); + reg |= (3 <<6 ); +phy_write (phydev,MDIO_DEVAD_NONE ,16 , reg); + +/* +* invert QSGMII Q_INP/N and Q_OUTP/N if required +* and perform global reset +*/ + reg =phy_read (phydev,MDIO_DEVAD_NONE ,26 ); +if (qinpn) + reg |= (1 <<13 ); +if (qoutpn) + reg |= (1 <<12 ); + reg |= (1 <<15 ); +phy_write (phydev,MDIO_DEVAD_NONE ,26 , reg); + +/* advertise 1000BASE-T full-duplex only */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,4 ); + reg &= ~0x1e0 ; +phy_write (phydev,MDIO_DEVAD_NONE ,4 , reg); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,9 ); + reg = (reg & ~0x300 ) |0x200 ; +phy_write (phydev,MDIO_DEVAD_NONE ,9 , reg); + +/* copper power up */ + reg =phy_read (phydev,MDIO_DEVAD_NONE ,16 ); + reg &= ~0x0004 ; +phy_write (phydev,MDIO_DEVAD_NONE ,16 , reg); +} + +void init_host_phys (struct mii_dev *bus) +{ +uint k; + +for (k =0 ; k <2 ; ++k) { +struct phy_device *phydev; + + phydev =phy_find_by_mask (bus,1 << k, +PHY_INTERFACE_MODE_SGMII ); + +if (phydev) +phy_config (phydev); + } +} + +uint calculate_octo_phy_mask (void ) +{ +uint k; +uint octo_phy_mask =0 ; +struct gpio_desc gpio = {}; +char name[64 ]; + +/* mark all octo phys that should be present */ +for (k =0 ; k <5 ; ++k) { +snprintf (name,64 ,"generic,cat-gpio-%u" , k); + +if (!get_gpio (name, &gpio)) +continue ; + +/* check CAT flag */ +if (dm_gpio_get_value (&gpio)) + octo_phy_mask |= (1 << (k *2 )); +else +/* If CAT == 0, there's no second octo phy -> skip */ +continue ; + +snprintf (name,64 ,"generic,second-octo-gpio-%u" , k); + +if (!get_gpio (name, &gpio)) { +/* default: second octo phy is present */ + octo_phy_mask |= (1 << (k *2 +1 )); +continue ; + } + +if (dm_gpio_get_value (&gpio) ==0 ) + octo_phy_mask |= (1 << (k *2 +1 ));
board/gdsys/38x/controlcenterdc.c line 307
Quoted 10 lines
board/gdsys/38x/controlcenterdc.c new file +10
-0+ } + +return octo_phy_mask; +} + +int register_miiphy_bus (uint k,struct mii_dev **bus) +{ +int retval; +struct mii_dev *mdiodev =mdio_alloc (); +char *name = bb_miiphy_buses[k].name;
I'm wondering how this works if "bb_miiphy_buses" is defined later in this file and you have no header file.
Quoted 47 lines
board/gdsys/38x/controlcenterdc.c new file +47
-0+ +if (!mdiodev) +return -ENOMEM ; +strncpy (mdiodev->name, + name, +MDIO_NAME_LEN ); + mdiodev->read = bb_miiphy_read; + mdiodev->write = bb_miiphy_write; + + retval =mdio_register (mdiodev); +if (retval <0 ) +return retval; + *bus =miiphy_get_dev_by_name (name); + +return 0 ; +} + +struct porttype *get_porttype (uint octo_phy_mask,uint k) +{ +uint octo_index = k *4 ; + +if (!k) { +if (octo_phy_mask &0x01 ) +return &porttypes[PORTTYPE_MAIN_CAT ]; +else if (!(octo_phy_mask &0x03 )) +return &porttypes[PORTTYPE_16C_16F ]; + }else { +if (octo_phy_mask & (1 << octo_index)) +return &porttypes[PORTTYPE_TOP_CAT ]; + } + +return NULL ; +} + +int init_octo_phys (uint octo_phy_mask) +{ +uint bus_idx; + +/* there are up to four octo-phys on each mdio bus */ +for (bus_idx =0 ; bus_idx < bb_miiphy_buses_num; ++bus_idx) { +uint m; +uint octo_index = bus_idx *4 ; +struct mii_dev *bus =NULL ; +struct porttype *porttype =NULL ; +int ret; + + porttype =get_porttype (octo_phy_mask, bus_idx);
board/gdsys/38x/controlcenterdc.c line 364
Quoted 10 lines
board/gdsys/38x/controlcenterdc.c new file +10
-0+ +if (!porttype) +continue ; + +for (m =0 ; m <4 ; ++m) { +uint phy_idx; + +/* Register a bus device if there is at least one phy +* on the current bus +*/
Multiline comment style please.
Quoted 342 lines
board/gdsys/38x/controlcenterdc.c new file +342
-0+if (!m && octo_phy_mask & (0xf << octo_index)) { + ret =register_miiphy_bus (bus_idx, &bus); +if (ret) +return ret; + } + +if (!(octo_phy_mask & (1 << (octo_index + m)))) +continue ; + +for (phy_idx =0 ; phy_idx <8 ; ++phy_idx) { +struct phy_device *phydev =phy_find_by_mask ( + bus,1 << (m *8 + phy_idx), +PHY_INTERFACE_MODE_MII ); + +printf (" %u" , bus_idx *32 + m *8 + phy_idx); + +ihs_phy_config (phydev, + porttype->phy_invert_in_pol, + porttype->phy_invert_out_pol); + } + } + } + +return 0 ; +} + +int ccdc_eth_init (void ) +{ +uint k; +uint octo_phy_mask =0 ; +int ret; +struct mii_dev *bus; + +/* Init SoC's phys */ + bus =miiphy_get_dev_by_name ("ethernet at 34000" ); + +if (bus) +init_host_phys (bus); + + bus =miiphy_get_dev_by_name ("ethernet at 70000" ); + +if (bus) +init_host_phys (bus); + +/* Init octo phys */ + octo_phy_mask =calculate_octo_phy_mask (); + +printf ("IHS PHYS: %08x" , octo_phy_mask); + + ret =init_octo_phys (octo_phy_mask); + +if (ret) +return ret; + +printf ("\n" ); + +/* reset all FPGA-QSGMII instances */ +for (k =0 ; k <80 ; ++k) +writel (1 <<31 , &fpga->qsgmii_port_state[k]); + +udelay (100 ); + +for (k =0 ; k <80 ; ++k) +writel (0 , &fpga->qsgmii_port_state[k]); +return 0 ; +} + +void print_hydra_version (uint index) +{ +u32 versions =readl (&fpga->versions); +u32 fpga_version =readl (&fpga->fpga_version); + +uint hardware_version = versions &0xf ; + +printf ("FPGA%u: mapped to %p\n " , index, fpga); + +switch (hardware_version) { +case HWVER_100 : +printf ("HW-Ver 1.00\n" ); +break ; + +case HWVER_110 : +printf ("HW-Ver 1.10\n" ); +break ; + +case HWVER_120 : +printf ("HW-Ver 1.20\n" ); +break ; + +default : +printf ("HW-Ver %d(not supported)\n" , + hardware_version); +break ; + } + +printf (" FPGA V %d.%02d\n" , + fpga_version /100 , fpga_version %100 ); +} + +static void hydra_initialize (void ) +{ +uint i; +pci_dev_t devno; + +/* Find and probe all the matching PCI devices */ +for (i =0 ; (devno =pci_find_devices (hydra_supported, i)) >=0 ; i++) { +u32 val; + +/* Try to enable I/O accesses and bus-mastering */ + val =PCI_COMMAND_MEMORY |PCI_COMMAND_MASTER ; +pci_write_config_dword (devno,PCI_COMMAND , val); + +/* Make sure it worked */ +pci_read_config_dword (devno,PCI_COMMAND , &val); +if (!(val &PCI_COMMAND_MEMORY )) { +puts ("Can't enable I/O memory\n" ); +continue ; + } +if (!(val &PCI_COMMAND_MASTER )) { +puts ("Can't enable bus-mastering\n" ); +continue ; + } + +/* read FPGA details */ + fpga =pci_map_bar (devno,PCI_BASE_ADDRESS_0 , +PCI_REGION_MEM ); + +print_hydra_version (i); + } +} +#endif + +int board_late_init (void ) +{ +#ifndef CONFIG_SPL_BUILD +hydra_initialize (); +#endif +return 0 ; +} + +int board_fix_fdt (void ) +{ +struct udevice *bus; +uint k; +char name[64 ]; + + bus =dev_get_by_ofname ("/soc/internal-regs/i2c at 11000" ); + +for (k =0x21 ; k <=0x26 ; k++) { +snprintf (name,64 , +"/soc/internal-regs/i2c at 11000/pca9698@%02x" , k); + +if (!dm_i2c_simple_probe (bus, k)) +fdt_disable_by_ofname (name); + } + +return 0 ; +} + +int last_stage_init (void ) +{ +disable_ctrlc (1 ); + +#ifndef CONFIG_SPL_BUILD +ccdc_eth_init (); +#endif +if (tpm_init () ||tpm_startup (TPM_ST_CLEAR ) || +tpm_continue_self_test ()) { +return 1 ; + } + +mdelay (37 ); + +flush_keys (); +load_and_run_keyprog (); + +return 0 ; +} + +#ifndef CONFIG_SPL_BUILD + +#define REFL_PATTERN (0xdededede) +#define REFL_PATTERN_INV (~REFL_PATTERN) + +int do_hydrate(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + uint k = 0; + void __iomem *pcie2_base = (void __iomem *)(MVEBU_REG_PCIE_BASE + + 0x4000); + + if (!fpga) + return -1; + + while (1) { + u32 res; + + writel(REFL_PATTERN, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN_INV) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN_INV); + writel(REFL_PATTERN_INV, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN); + + res = readl(pcie2_base + 0x118) & 0x1f; + if (res) + printf("FrstErrPtr %u\n", res); + res = readl(pcie2_base + 0x104); + if (res) { + printf("Uncorrectable Error Status 0x%08x\n", res); + writel(res, pcie2_base + 0x104); + } + + if (!(++k % 10000)) + printf("round %u\n", k); + + if (ctrlc()) + break; + } + + return 0; +} + +U_BOOT_CMD( + hydrate, 1, 0, do_hydrate, + "hydra reflection test", + "hydra reflection test" +); + +/* + * MII GPIO bitbang implementation + * MDC MDIO bus + * 13 14 PHY1-4 + * 25 45 PHY5-8 + * 46 24 PHY9-10 + */ + +struct gpio_mii { + int mdc; + int mdio; + int mdio_value; +} gpio_mii_set[] = { + { 13, 14, 1 }, + { 25, 45, 1 }, + { 46, 24, 1 }, +}; + +static int mii_mdio_init(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_set_valid(gpio_mii->mdc, GPIO_OUTPUT_OK); + kw_gpio_set_valid(gpio_mii->mdio, GPIO_INPUT_OK | GPIO_OUTPUT_OK); + kw_gpio_direction_output(gpio_mii->mdc, 1); + + return 0; +} + +static int mii_mdio_active(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_direction_output(gpio_mii->mdio, gpio_mii->mdio_value); + + return 0; +} + +static int mii_mdio_tristate(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_direction_input(gpio_mii->mdio); + + return 0; +} + +static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_set_value(gpio_mii->mdio, v); + gpio_mii->mdio_value = v; + + return 0; +} + +static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + *v = (kw_gpio_get_value(gpio_mii->mdio) != 0); + + return 0; +} + +static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_set_value(gpio_mii->mdc, v); + + return 0; +} + +static int mii_delay(struct bb_miiphy_bus *bus) +{ + udelay(1); + + return 0; +} + +struct bb_miiphy_bus bb_miiphy_buses[] = { + { + .name = "ihs0", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[0], + }, + { + .name = "ihs1", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[1], + }, + { + .name = "ihs2", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate,
board/gdsys/38x/controlcenterdc.c line 716
Quoted 10 lines
board/gdsys/38x/controlcenterdc.c new file +10
-0+ .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[2], + }, +}; + +int bb_miiphy_buses_num =sizeof (bb_miiphy_buses) / +sizeof (bb_miiphy_buses[0 ]);
static? And can you use ARRAY_SIZE()?
board/gdsys/38x/controlcenterdc.c line 717
Quoted 1 line
board/gdsys/38x/controlcenterdc.c new file +1
-0+#endif
Perhaps its also a good idea to move at least some of this code (especiall the command and perhaps some MDIO stuff) into separate files that are only compiled for non-SPL U-Boot. This will remove some of the #ifdefs as well.
Quoted 56 lines
board/gdsys/38x/dt_helpers.c new file +50
-0@@ -0,0 +1,60 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <i2c.h> +#include <dm.h> +#include <fdt_support.h> +#include <asm-generic/gpio.h> + +DECLARE_GLOBAL_DATA_PTR ; + +bool get_gpio (char *name,struct gpio_desc *gpio) +{ +int node =fdt_node_offset_by_compatible (gd->fdt_blob,0 , name); +int ret; + +if (node <0 ) +return false; + + ret =gpio_request_by_name_nodev (gd->fdt_blob, node,"gpios" ,0 , gpio, +0 ); + +if (ret <0 ) +return false; + +return dm_gpio_is_valid (gpio); +} + +int fdt_disable_by_ofname (char *ofname) +{ +void *blob = gd->fdt_blob; +int offset; + + offset =fdt_path_offset (blob, ofname); +return fdt_status_disabled (blob, offset); +} + +struct udevice *dev_get_by_ofname (char *ofname) +{ +void *blob = gd->fdt_blob; +int offset; +struct udevice *dev; + + offset =fdt_path_offset (blob, ofname); +device_get_global_by_of_offset (offset, &dev); +
board/gdsys/38x/dt_helpers.c line 60
Quoted 10 lines
board/gdsys/38x/dt_helpers.c new file +10
-0+return dev; +} + +bool dm_i2c_simple_probe (struct udevice *bus,uint chip_addr) +{ +struct udevice *dev; + +return !dm_i2c_probe (bus, chip_addr,DM_I2C_CHIP_RD_ADDRESS | +DM_I2C_CHIP_WR_ADDRESS , &dev); +}
At least some of this might be very helpful as common U-Boot functions available for all boards.
Quoted 375 lines
board/gdsys/38x/dt_helpers.h new file +16
-0@@ -0,0 +1,16 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __DT_HELPERS_H +#define __DT_HELPERS_H + +bool get_gpio (char *name,struct gpio_desc *gpio); +int fdt_disable_by_ofname (char *ofname); +struct udevice *dev_get_by_ofname (char *ofname); +bool dm_i2c_simple_probe (struct udevice *bus,uint chip_addr); + +#endif /* __DT_HELPERS_H */ board/gdsys/38x/hre.c new file +347
-0@@ -0,0 +1,517 @@ +/* +* (C) Copyright 2013 +* Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <malloc.h> +#include <fs.h> +#include <i2c.h> +#include <mmc.h> +#include <tpm.h> +#include <u-boot/sha1.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> +#include <pca9698.h> + +#include "hre.h" + +/* other constants */ +enum { +ESDHC_BOOT_IMAGE_SIG_OFS =0x40 , +ESDHC_BOOT_IMAGE_SIZE_OFS =0x48 , +ESDHC_BOOT_IMAGE_ADDR_OFS =0x50 , +ESDHC_BOOT_IMAGE_TARGET_OFS =0x58 , +ESDHC_BOOT_IMAGE_ENTRY_OFS =0x60 , +}; + +enum { +I2C_SOC_0 =0 , +I2C_SOC_1 =1 , +}; + +enum access_mode { +HREG_NONE =0 , +HREG_RD =1 , +HREG_WR =2 , +HREG_RDWR =3 , +}; + +/* register constants */ +enum { +FIX_HREG_DEVICE_ID_HASH =0 , +FIX_HREG_UNUSED1 =1 , +FIX_HREG_UNUSED2 =2 , +FIX_HREG_VENDOR =3 , +COUNT_FIX_HREGS +}; + +static struct h_reg pcr_hregs[24 ]; +static struct h_reg fix_hregs[COUNT_FIX_HREGS ]; +static struct h_reg var_hregs[8 ]; + +/* hre opcodes */ +enum { +/* opcodes w/o data */ +HRE_NOP =0x00 , +HRE_SYNC =HRE_NOP , +HRE_CHECK0 =0x01 , +/* opcodes w/o data, w/ sync dst */ +/* opcodes w/ data */ +HRE_LOAD =0x81 , +/* opcodes w/data, w/sync dst */ +HRE_XOR =0xC1 , +HRE_AND =0xC2 , +HRE_OR =0xC3 , +HRE_EXTEND =0xC4 , +HRE_LOADKEY =0xC5 , +}; + +/* hre errors */ +enum { +HRE_E_OK =0 , +HRE_E_TPM_FAILURE , +HRE_E_INVALID_HREG , +}; + +static uint64_t device_id; +static uint64_t device_cl; +static uint64_t device_type; + +static uint32_t platform_key_handle; + +static uint32_t hre_tpm_err; +static int hre_err =HRE_E_OK ; + +#define IS_PCR_HREG (spec) ((spec) & 0x20) +#define IS_FIX_HREG (spec) (((spec) & 0x38) == 0x08) +#define IS_VAR_HREG (spec) (((spec) & 0x38) == 0x10) +#define HREG_IDX (spec) ((spec) & (IS_PCR_HREG(spec) ? 0x1f : 0x7)) + +static const uint8_t vendor[] ="Guntermann & Drunck" ; + +/** +* @brief get the size of a given (TPM) NV area +* @param index NV index of the area to get size for +* @param size pointer to the size +* @return 0 on success, != 0 on error +*/ +static int get_tpm_nv_size (uint32_t index,uint32_t *size) +{ +uint32_t err; +uint8_t info[72 ]; +uint8_t *ptr; +uint16_t v16; + + err =tpm_get_capability (TPM_CAP_NV_INDEX , index, + info,sizeof (info)); +if (err) { +printf ("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n" , + index, err); +return 1 ; + } + +/* skip tag and nvIndex */ + ptr = info +6 ; +/* skip 2 pcr info fields */ + v16 =get_unaligned_be16 (ptr); + ptr +=2 + v16 +1 +20 ; + v16 =get_unaligned_be16 (ptr); + ptr +=2 + v16 +1 +20 ; +/* skip permission and flags */ + ptr +=6 +3 ; + + *size =get_unaligned_be32 (ptr); +return 0 ; +} + +/** +* @brief search for a key by usage auth and pub key hash. +* @param auth usage auth of the key to search for +* @param pubkey_digest (SHA1) hash of the pub key structure of the key +* @param[out] handle the handle of the key iff found +* @return 0 if key was found in TPM; != 0 if not. +*/ +static int find_key (const uint8_t auth[20 ],const uint8_t pubkey_digest[20 ], +uint32_t *handle) +{ +uint16_t key_count; +uint32_t key_handles[10 ]; +uint8_t buf[288 ]; +uint8_t *ptr; +uint32_t err; +uint8_t digest[20 ]; +size_t buf_len; +unsigned int i; + +/* fetch list of already loaded keys in the TPM */ + err =tpm_get_capability (TPM_CAP_HANDLE ,TPM_RT_KEY , buf,sizeof (buf)); +if (err) +return -1 ; + key_count =get_unaligned_be16 (buf); + ptr = buf +2 ; +for (i =0 ; i < key_count; ++i, ptr +=4 ) + key_handles[i] =get_unaligned_be32 (ptr); + +/* now search a(/ the) key which we can access with the given auth */ +for (i =0 ; i < key_count; ++i) { + buf_len =sizeof (buf); + err =tpm_get_pub_key_oiap (key_handles[i], auth, buf, &buf_len); +if (err && err !=TPM_AUTHFAIL ) +return -1 ; +if (err) +continue ; +sha1_csum (buf, buf_len, digest); +if (!memcmp (digest, pubkey_digest,20 )) { + *handle = key_handles[i]; +return 0 ; + } + } +return 1 ; +} + +/** +* @brief read CCDM common data from TPM NV +* @return 0 if CCDM common data was found and read, !=0 if something failed. +*/ +static int read_common_data (void ) +{ +uint32_t size =0 ; +uint32_t err; +uint8_t buf[256 ]; +sha1_context ctx; + +if (get_tpm_nv_size (NV_COMMON_DATA_INDEX , &size) || + size <NV_COMMON_DATA_MIN_SIZE ) +return 1 ; + err =tpm_nv_read_value (NV_COMMON_DATA_INDEX , + buf,min (sizeof (buf), size)); +if (err) { +printf ("tpm_nv_read_value() failed: %u\n" , err); +return 1 ; + } + + device_id =get_unaligned_be64 (buf); + device_cl =get_unaligned_be64 (buf +8 ); + device_type =get_unaligned_be64 (buf +16 ); + +sha1_starts (&ctx); +sha1_update (&ctx, buf,24 ); +sha1_finish (&ctx, fix_hregs[FIX_HREG_DEVICE_ID_HASH ].digest); + fix_hregs[FIX_HREG_DEVICE_ID_HASH ].valid = true; + + platform_key_handle =get_unaligned_be32 (buf +24 ); + +return 0 ; +} + +/** +* @brief get pointer to hash register by specification +* @param spec specification of a hash register +* @return pointer to hash register or NULL if @a spec does not qualify a +* valid hash register; NULL else. +*/ +static struct h_reg *get_hreg (uint8_t spec) +{ +uint8_t idx; + + idx =HREG_IDX (spec); +if (IS_FIX_HREG (spec)) { +if (idx <ARRAY_SIZE (fix_hregs)) +return fix_hregs + idx; + hre_err =HRE_E_INVALID_HREG ; + }else if (IS_PCR_HREG (spec)) { +if (idx <ARRAY_SIZE (pcr_hregs)) +return pcr_hregs + idx; + hre_err =HRE_E_INVALID_HREG ; + }else if (IS_VAR_HREG (spec)) { +if (idx <ARRAY_SIZE (var_hregs)) +return var_hregs + idx; + hre_err =HRE_E_INVALID_HREG ; + } +return NULL ; +} + +/** +* @brief get pointer of a hash register by specification and usage. +* @param spec specification of a hash register +* @param mode access mode (read or write or read/write) +* @return pointer to hash register if found and valid; NULL else. +* +* This func uses @a get_reg() to determine the hash register for a given spec. +* If a register is found it is validated according to the desired access mode. +* The value of automatic registers (PCR register and fixed registers) is +* loaded or computed on read access. +*/ +static struct h_reg *access_hreg (uint8_t spec,enum access_mode mode) +{ +struct h_reg *result; + + result =get_hreg (spec); +if (!result) +return NULL ; + +if (mode &HREG_WR ) { +if (IS_FIX_HREG (spec)) { + hre_err =HRE_E_INVALID_HREG ; +return NULL ; + } + } +if (mode &HREG_RD ) { +if (!result->valid) { +if (IS_PCR_HREG (spec)) { + hre_tpm_err =tpm_pcr_read (HREG_IDX (spec), + result->digest,20 ); + result->valid = (hre_tpm_err ==TPM_SUCCESS ); + }else if (IS_FIX_HREG (spec)) { +switch (HREG_IDX (spec)) { +case FIX_HREG_DEVICE_ID_HASH : +read_common_data (); +break ; +case FIX_HREG_VENDOR : +memcpy (result->digest, vendor,20 ); + result->valid = true; +break ; + } + }else { + result->valid = true; + } + } +if (!result->valid) { + hre_err =HRE_E_INVALID_HREG ; +return NULL ; + } + } + +return result; +} + +static void *compute_and (void *_dst,const void *_src,size_t n) +{ +uint8_t *dst = _dst; +const uint8_t *src = _src; +size_t i; + +for (i = n; i-- >0 ; ) + *dst++ &= *src++; + +return _dst; +} + +static void *compute_or (void *_dst,const void *_src,size_t n) +{ +uint8_t *dst = _dst; +const uint8_t *src = _src; +size_t i; + +for (i = n; i-- >0 ; ) + *dst++ |= *src++; + +return _dst; +} + +static void *compute_xor (void *_dst,const void *_src,size_t n) +{ +uint8_t *dst = _dst; +const uint8_t *src = _src; +size_t i; + +for (i = n; i-- >0 ; ) + *dst++ ^= *src++; + +return _dst; +} + +static void *compute_extend (void *_dst,const void *_src,size_t n) +{ +uint8_t digest[20 ]; +sha1_context ctx; + +sha1_starts (&ctx); +sha1_update (&ctx, _dst, n); +sha1_update (&ctx, _src, n); +sha1_finish (&ctx, digest); +memcpy (_dst, digest,min (n,sizeof (digest))); + +return _dst; +} + +static int hre_op_loadkey (struct h_reg *src_reg,struct h_reg *dst_reg, +const void *key,size_t key_size) +{ +uint32_t parent_handle; +uint32_t key_handle; + +if (!src_reg || !dst_reg || !src_reg->valid || !dst_reg->valid)
board/gdsys/38x/hre.c line 357
Quoted 10 lines
board/gdsys/38x/hre.c new file +10
-0+return -1 ; +if (find_key (src_reg->digest, dst_reg->digest, &parent_handle)) +return -1 ; + hre_tpm_err =tpm_load_key2_oiap (parent_handle, key, key_size, + src_reg->digest, &key_handle); +if (hre_tpm_err) { + hre_err =HRE_E_TPM_FAILURE ; +return -1 ; + } +/* TODO remember key handle somehow? */
Is this comment still valid?
Quoted 734 lines
board/gdsys/38x/hre.c new file +160
-0+ +return 0 ; +} + +/** +* @brief executes the next opcode on the hash register engine. +* @param[in,out] ip pointer to the opcode (instruction pointer) +* @param[in,out] code_size (remaining) size of the code +* @return new instruction pointer on success, NULL on error. +*/ +static const uint8_t *hre_execute_op (const uint8_t **ip,size_t *code_size) +{ +bool dst_modified = false; +uint32_t ins; +uint8_t opcode; +uint8_t src_spec; +uint8_t dst_spec; +uint16_t data_size; +struct h_reg *src_reg, *dst_reg; +uint8_t buf[20 ]; +const uint8_t *src_buf, *data; +uint8_t *ptr; +int i; +void * (*bin_func)(void *,const void *,size_t ); + +if (*code_size <4 ) +return NULL ; + + ins =get_unaligned_be32 (*ip); + opcode = **ip; + data = *ip +4 ; + src_spec = (ins >>18 ) &0x3f ; + dst_spec = (ins >>12 ) &0x3f ; + data_size = (ins &0x7ff ); + +debug ("HRE: ins=%08x (op=%02x, s=%02x, d=%02x, L=%d)\n" , ins, + opcode, src_spec, dst_spec, data_size); + +if ((opcode &0x80 ) && (data_size +4 ) > *code_size) +return NULL ; + + src_reg =access_hreg (src_spec,HREG_RD ); +if (hre_err || hre_tpm_err) +return NULL ; + dst_reg =access_hreg (dst_spec, (opcode &0x40 ) ?HREG_RDWR :HREG_WR ); +if (hre_err || hre_tpm_err) +return NULL ; + +switch (opcode) { +case HRE_NOP : + goto end; +case HRE_CHECK0 : +if (src_reg) { +for (i =0 ; i <20 ; ++i) { +if (src_reg->digest[i]) +return NULL ; + } + } +break ; +case HRE_LOAD : + bin_func = memcpy; + goto do_bin_func; +case HRE_XOR : + bin_func = compute_xor; + goto do_bin_func; +case HRE_AND : + bin_func = compute_and; + goto do_bin_func; +case HRE_OR : + bin_func = compute_or; + goto do_bin_func; +case HRE_EXTEND : + bin_func = compute_extend; +do_bin_func: +if (!dst_reg) +return NULL ; +if (src_reg) { + src_buf = src_reg->digest; + }else { +if (!data_size) { +memset (buf,0 ,20 ); + src_buf = buf; + }else if (data_size ==1 ) { +memset (buf, *data,20 ); + src_buf = buf; + }else if (data_size >=20 ) { + src_buf = data; + }else { + src_buf = buf; +for (ptr = (uint8_t *)src_buf, i =20 ; i >0 ; + i -= data_size, ptr += data_size) +memcpy (ptr, data, +min_t (size_t, i, data_size)); + } + } +bin_func (dst_reg->digest, src_buf,20 ); + dst_reg->valid = true; + dst_modified = true; +break ; +case HRE_LOADKEY : +if (hre_op_loadkey (src_reg, dst_reg, data, data_size)) +return NULL ; +break ; +default : +return NULL ; + } + +if (dst_reg && dst_modified &&IS_PCR_HREG (dst_spec)) { + hre_tpm_err =tpm_extend (HREG_IDX (dst_spec), dst_reg->digest, + dst_reg->digest); +if (hre_tpm_err) { + hre_err =HRE_E_TPM_FAILURE ; +return NULL ; + } + } +end: + *ip +=4 ; + *code_size -=4 ; +if (opcode &0x80 ) { + *ip += data_size; + *code_size -= data_size; + } + +return *ip; +} + +/** +* @brief runs a program on the hash register engine. +* @param code pointer to the (HRE) code. +* @param code_size size of the code (in bytes). +* @return 0 on success, != 0 on failure. +*/ +int hre_run_program (const uint8_t *code,size_t code_size) +{ +size_t code_left; +const uint8_t *ip = code; + + code_left = code_size; + hre_tpm_err =0 ; + hre_err =HRE_E_OK ; +while (code_left >0 ) +if (!hre_execute_op (&ip, &code_left)) +return -1 ; + +return hre_err; +} + +int hre_verify_program (struct key_program *prg) +{ +uint32_t crc; + + crc =crc32 (0 , prg->code, prg->code_size); + +if (crc != prg->code_crc) { +printf ("HRC crc mismatch: %08x != %08x\n" , + crc, prg->code_crc); +return 1 ; + } +return 0 ; +}board/gdsys/38x/hre.h new file +38
-0@@ -0,0 +1,38 @@ +/* +* (C) Copyright 2013 +* Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __HRE_H +#define __HRE_H + +struct key_program { +uint32_t magic; +uint32_t code_crc; +uint32_t code_size; +uint8_t code[]; +}; + +struct h_reg { +bool valid; +uint8_t digest[20 ]; +}; + +/* CCDM specific contants */ +enum { +/* NV indices */ +NV_COMMON_DATA_INDEX =0x40000001 , +/* magics for key blob chains */ +MAGIC_KEY_PROGRAM =0x68726500 , +MAGIC_HMAC =0x68616300 , +MAGIC_END_OF_CHAIN =0x00000000 , +/* sizes */ +NV_COMMON_DATA_MIN_SIZE =3 *sizeof (uint64_t ) +2 *sizeof (uint16_t ), +}; + +int hre_verify_program (struct key_program *prg); +int hre_run_program (const uint8_t *code,size_t code_size); + +#endif /* __HRE_H */ board/gdsys/38x/keyprogram.c new file +158
-0@@ -0,0 +1,158 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <tpm.h> +#include <malloc.h> +#include <linux/ctype.h> +#include <asm/unaligned.h> + +#include "hre.h" + +int flush_keys (void ) +{ +u16 key_count; +u8 buf[288 ]; +u8 *ptr; +u32 err; +uint i; + +/* fetch list of already loaded keys in the TPM */ + err =tpm_get_capability (TPM_CAP_HANDLE ,TPM_RT_KEY , buf,sizeof (buf)); +if (err) +return -1 ; + key_count =get_unaligned_be16 (buf); + ptr = buf +2 ; +for (i =0 ; i < key_count; ++i, ptr +=4 ) { + err =tpm_flush_specific (get_unaligned_be32 (ptr),TPM_RT_KEY ); +if (err && err !=TPM_KEY_OWNER_CONTROL ) +return err; + } + +return 0 ; +} + +int decode_hexstr (char *hexstr,u8 **result) +{ +int len =strlen (hexstr); +int bytes = len /2 ; +int i; +u8 acc =0 ; + +if (len %2 ==1 ) +return 1 ; + + *result = (u8 *)malloc (bytes); + +for (i =0 ; i < len; i++) { +char cur =tolower (hexstr[i]); +u8 val; + +if ((cur >='a' && cur <='f' ) || (cur >='0' && cur <='9' )) { + val = cur - (cur >'9' ?87 :48 ); + +if (i %2 ==0 ) + acc =16 * val; +else + (*result)[i /2 ] = acc + val; + }else { +free (*result); +return 1 ; + } + } + +return 0 ; +} + +int extract_subprogram (u8 **progdata,u32 expected_magic, +struct key_program **result) +{ +struct key_program *prog = *result; +u32 magic, code_crc, code_size; + + magic =get_unaligned_be32 (*progdata); + code_crc =get_unaligned_be32 (*progdata +4 ); + code_size =get_unaligned_be32 (*progdata +8 ); + + *progdata +=12 ; + +if (magic != expected_magic) +return -1 ; + + *result =malloc (sizeof (struct key_program ) + code_size); + +if (!*result) +return -1 ; + + prog->magic = magic; + prog->code_crc = code_crc; + prog->code_size = code_size; +memcpy (prog->code, *progdata, code_size); + + *progdata += code_size; + +if (hre_verify_program (prog)) { +free (prog); +return -1 ; + } + +return 0 ; +} + +struct key_program *parse_and_check_keyprog (u8 *progdata) +{ +struct key_program *result =NULL , *hmac =NULL ; + +/* Part 1: Load key program */ + +if (extract_subprogram (&progdata,MAGIC_KEY_PROGRAM , &result)) +return NULL ; + +/* Part 2: Load hmac program */ + +if (extract_subprogram (&progdata,MAGIC_HMAC , &hmac)) +return NULL ; + +free (hmac); + +return result; +} + +int load_and_run_keyprog (void ) +{ +char *cmd =NULL ; +u8 *binprog =NULL ; +char *hexprog; +struct key_program *prog; + + cmd =getenv ("loadkeyprogram" ); + +if (!cmd ||run_command (cmd,0 )) +return 1 ; + + hexprog =getenv ("keyprogram" ); + +if (decode_hexstr (hexprog, &binprog)) +return 1 ; + + prog =parse_and_check_keyprog (binprog); +free (binprog); + +if (!prog) +return 1 ; + +if (hre_run_program (prog->code, prog->code_size)) { +free (prog); +return 1 ; + } + +printf ("\nSD code ran successfully\n" ); + +free (prog); + +return 0 ; +}board/gdsys/38x/keyprogram.h new file +14
-0@@ -0,0 +1,14 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __KEYPROGRAM_H +#define __KEYPROGRAM_H + +int load_and_run_keyprog (void ); +int flush_keys (void ); + +#endif /* __KEYPROGRAM_H */ board/gdsys/38x/kwbimage.cfg.in new file +12
-0@@ -0,0 +1,12 @@ +# +# Copyright (C) 2014 Stefan Roese <[email protected]> +# + +# Armada 38x uses version 1 image format +VERSION 1 + +# Boot Media configurations +#@BOOT_FROM + +# Binary Header (bin_hdr) with DDR3 training code +BINARY spl/u-boot-spl.bin 0000005b 00000068board/gdsys/38x/spl.c new file +21
-0@@ -0,0 +1,21 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <config.h> +#include <asm/arch/cpu.h> + +void spl_board_init (void ) +{ +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SPI_NOR_FLASH +u32 *bootrom_save = (u32 *)CONFIG_SPL_BOOTROM_SAVE ; +u32 *regs = (u32 *)(*bootrom_save); + +printf ("Returning to BootROM (return address %08x)...\n" , regs[13 ]); +return_to_bootrom (); +#endif +}configs/controlcenterdc_defconfig new file +54
-0@@ -0,0 +1,54 @@ +CONFIG_ARM=y +CONFIG_ARCH_MVEBU=y +CONFIG_SPL_GPIO_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_TARGET_CONTROLCENTERDC=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI_SUPPORT=y +CONFIG_DEFAULT_DEVICE_TREE="controlcenterdc" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_SPL=y +CONFIG_SPL_SYS_MALLOC_SIMPLE=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_GO is not set +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_GPIO=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TPM=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_OF_BOARD_FIXUP=y +CONFIG_SPL_OF_TRANSLATE=y +CONFIG_DM_GPIO=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_BASE=0xd0012000 +CONFIG_DEBUG_UART_CLOCK=250000000 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SYS_NS16550=y +CONFIG_TPM_ATMEL_TWI=y +CONFIG_TPM_AUTH_SESSIONS=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_TPM=y +# CONFIG_EFI_LOADER is not setinclude/configs/controlcenterdc.h new file +234
-0@@ -0,0 +1,244 @@ +/* +* Copyright (C) 2014 Stefan Roese <[email protected]> +* Copyright (C) 2016 Mario Six <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _CONFIG_CONTROLCENTERDC_H +#define _CONFIG_CONTROLCENTERDC_H + +/* +* High Level Configuration Options (easy to change) +*/ +#define CONFIG_CUSTOMER_BOARD_SUPPORT + +#define CONFIG_SKIP_LOWLEVEL_INIT /* disable board lowlevel_init */ +#define CONFIG_DISPLAY_BOARDINFO_LATE +#define CONFIG_BOARD_LATE_INIT +#define CONFIG_LAST_STAGE_INIT +#define CONFIG_SPL_BOARD_INIT + +/* +* TEXT_BASE needs to be below 16MiB, since this area is scrubbed +* for DDR ECC byte filling in the SPL before loading the main +* U-Boot into it. +*/ +#define CONFIG_SYS_TEXT_BASE 0x00800000 + +#define CONFIG_SYS_TCLK 250000000/* 250MHz */ + +#define CONFIG_LOADADDR 1000000 + +#define CONFIG_SYS_NO_FLASH /* Declare no flash (NOR/SPI) */ + +/* +* Commands configuration +*/ +#define CONFIG_CMD_ENV +#define CONFIG_CMD_I2C +#define CONFIG_CMD_PCI +#define CONFIG_CMD_SCSI +#define CONFIG_CMD_SPI + +/* SPI NOR flash default params, used by sf commands */ +#define CONFIG_SF_DEFAULT_BUS 1 +#define CONFIG_SF_DEFAULT_SPEED 1000000 +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 + +/* +* SDIO/MMC Card Configuration +*/ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_SDHCI +#define CONFIG_MV_SDHCI +#define CONFIG_SYS_MMC_BASE MVEBU_SDIO_BASE + +/* +* SATA/SCSI/AHCI configuration +*/ +#define CONFIG_LIBATA +#define CONFIG_SCSI +#define CONFIG_SCSI_AHCI +#define CONFIG_SCSI_AHCI_PLAT +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 +#define CONFIG_SYS_SCSI_MAX_LUN 1 +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) + +/* Partition support */ +#define CONFIG_DOS_PARTITION +#define CONFIG_EFI_PARTITION + +/* Additional FS support/configuration */ +#define CONFIG_SUPPORT_VFAT + +/* USB/EHCI configuration */ +#define CONFIG_EHCI_IS_TDI + +/* Environment in SPI NOR flash */ +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_SPI_BUS 1 +#define CONFIG_ENV_OFFSET (1 << 20)/* 1MiB in */ +#define CONFIG_ENV_SIZE (64 << 10)/* 64KiB */ +#define CONFIG_ENV_SECT_SIZE (256 << 10)/* 256KiB sectors */ + +#define CONFIG_PHY_MARVELL /* there is a marvell phy */ +#define PHY_ANEG_TIMEOUT 8000/* PHY needs a longer aneg time */ + +/* PCIe support */ +#ifndef CONFIG_SPL_BUILD +#define CONFIG_PCI +#define CONFIG_PCI_MVEBU +#define CONFIG_PCI_PNP +#define CONFIG_PCI_SCAN_SHOW +#endif + +#define CONFIG_SYS_ALT_MEMTEST + +/* +* Software (bit-bang) MII driver configuration +*/ +#define CONFIG_BITBANGMII /* bit-bang MII PHY management */ +#define CONFIG_BITBANGMII_MULTI + +/* +* GPIO +*/ +#define CONFIG_KIRKWOOD_GPIO + +/* SPL */ +/* +* Select the boot device here +* +* Currently supported are: +* SPL_BOOT_SPI_NOR_FLASH - Booting via SPI NOR flash +* SPL_BOOT_SDIO_MMC_CARD - Booting via SDIO/MMC card (partition 1) +*/ +#define SPL_BOOT_SPI_NOR_FLASH 1 +#define SPL_BOOT_SDIO_MMC_CARD 2 +#define CONFIG_SPL_BOOT_DEVICE SPL_BOOT_SPI_NOR_FLASH + +/* Defines for SPL */ +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_SIZE (160 << 10) + +#if defined(CONFIG_SECURED_MODE_IMAGE ) +#define CONFIG_SPL_TEXT_BASE 0x40002614 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x2614) +#else +#define CONFIG_SPL_TEXT_BASE 0x40000030 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x30) +#endif + +#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) +#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MALLOC_SIMPLE +#endif + +#define CONFIG_SPL_STACK (0x40000000 + ((212 - 16) << 10)) +#define CONFIG_SPL_BOOTROM_SAVE (CONFIG_SPL_STACK + 4) + +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT + +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SPI_NOR_FLASH +/* SPL related SPI defines */ +#define CONFIG_SPL_SPI_LOAD +#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x30000 +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_SPI_U_BOOT_OFFS +#endif + +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SDIO_MMC_CARD +/* SPL related MMC defines */ +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 1 +#define CONFIG_SYS_MMC_U_BOOT_OFFS (168 << 10) +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_MMC_U_BOOT_OFFS +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR (CONFIG_SYS_U_BOOT_OFFS / 512) +#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS ((512 << 10) / 512)/* 512KiB */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER 0x00180000/* in SDRAM */ +#endif +#endif + +/* +* Environment Configuration +*/ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_BAUDRATE 115200 + +#define CONFIG_HOSTNAME ccdc +#define CONFIG_ROOTPATH "/opt/nfsroot" +#define CONFIG_BOOTFILE "ccdc.img" + +#define CONFIG_PREBOOT /* enable preboot variable */ + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth1\0" \ + "consoledev=ttyS1\0" \ + "u-boot=u-boot.bin\0" \ + "bootfile_addr=1000000\0" \ + "keyprogram_addr=3000000\0" \ + "keyprogram_file=keyprogram.img\0" \ + "fdtfile=controlcenterdc.dtb\0" \ + "load=tftpboot ${loadaddr} ${u-boot}\0" \ + "mmcdev=0:2\0" \ + "update=sf probe 1:0;" \ + " sf erase 0 +${filesize};" \ + " sf write ${fileaddr} 0 ${filesize}\0" \ + "upd=run load update\0" \ + "fdt_high=0x10000000\0" \ + "initrd_high=0x10000000\0" \ + "loadkeyprogram=tpm flush_keys;" \ + " mmc rescan;" \ + " ext4load mmc ${mmcdev} ${keyprogram_addr} ${keyprogram_file};"\ + " source ${keyprogram_addr}:script at 1\0" \ + "gpio1=gpio at 22_25\0" \ + "gpio2=A29\0" \ + "blinkseq='0 0 0 0 2 0 2 2 3 1 3 1 0 0 2 2 3 1 3 3 2 0 2 2 3 1 1 1 " \ + "2 0 2 2 3 1 3 1 0 0 2 0 3 3 3 1 2 0 0 0 3 1 1 1 0 0 0 0'\0" \ + "bootfail=for i in ${blinkseq}; do" \ + " if test $i -eq 0; then" \ + " gpio clear ${gpio1}; gpio set ${gpio2};" \ + " elif test $i -eq 1; then" \ + " gpio clear ${gpio1}; gpio clear ${gpio2};" \ + " elif test $i -eq 2; then" \ + " gpio set ${gpio1}; gpio set ${gpio2};" \ + " else;" \ + " gpio clear ${gpio1}; gpio set ${gpio2};" \ + " fi; sleep 0.12; done\0" + +#define CONFIG_NFSBOOTCOMMAND \ + "setenv bootargs root=/dev/nfs rw " \ + "nfsroot=${serverip}:${rootpath} " \ + "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off " \ + "console=${consoledev},${baudrate} ${othbootargs}; " \ + "tftpboot ${bootfile_addr} ${bootfile}; " \ + "bootm ${bootfile_addr}" + +#define CONFIG_MMCBOOTCOMMAND \ + "setenv bootargs root=/dev/mmcblk0p3 rw rootwait " \ + "console=${consoledev},${baudrate} ${othbootargs}; " \ + "ext2load mmc 0:2 ${bootfile_addr} ${bootfile}; " \ + "bootm ${bootfile_addr}" + +#define CONFIG_BOOTCOMMAND \ + "if env exists keyprogram; then;" \ + " setenv keyprogram; run nfsboot;" \
include/configs/controlcenterdc.h line 244
Quoted 10 lines
include/configs/controlcenterdc.h new file +10
-0+" fi;" \ +" run dobootfail" + +/* +* mv-common.h should be defined after CMD configs since it used them +* to enable certain macros + */ +#include "mv-common.h" + +#endif /* _CONFIG_CONTROLCENTERDC_H */
Thanks,
Stefan
PATCH 16/17 arm: mvebu: Add gdsys ControlCenter-Compact board
Hi Stefan,
Quoted 23 lines · Stefan Roese
Quoted 15 lines · Mario Six
From: Dirk Eibach <[email protected]>
The gdsys ControlCenter Digital board is based on a Marvell Armada 38x SOC.
It boots from SPI-Flash but can be configured to boot from SD-card for factory programming and testing.
On board peripherals include:
- 2 x GbE
- Xilinx Kintex-7 FPGA connected via PCIe
- mSATA
- USB3 host
- Atmel TPMQuoted 6 lines
Signed-off-by Dirk Eibach <[email protected]>Signed-off-by Mario Six <[email protected]>--- arch/arm/Kconfig | 1 + arch/arm/dts/Makefile | 3 +- arch/arm/dts/controlcenterdc.dts | 629 +++++++++++++++++++++++++++++++++
Quoted 5 lines
Could you perhaps rename this file (and board name as well?) to something like "armada-38x-controlcenterdc*" instead? Its much easier to match the files to the architecture this way. And until now, all Armada XP / 38x (etc) files match this rule.
Sure, I'll rename that file in v2.
Quoted 5 lines
Quoted 2 lines
arch/arm/mach-mvebu/Kconfig | 4 + board/gdsys/38x/.gitignore | 1 +Perhaps better s/38x/a38x for "Armada"?
OK, will be fixed in v2.
Quoted 764 lines
Quoted 751 lines
board/gdsys/38x/Kconfig | 42 +++ board/gdsys/38x/MAINTAINERS | 7 + board/gdsys/38x/Makefile | 30 ++ board/gdsys/38x/README | 18 + board/gdsys/38x/controlcenterdc.c | 717 ++++++++++++++++++++++++++++++++++++++ board/gdsys/38x/dt_helpers.c | 60 ++++ board/gdsys/38x/dt_helpers.h | 16 + board/gdsys/38x/hre.c | 517 +++++++++++++++++++++++++++ board/gdsys/38x/hre.h | 38 ++ board/gdsys/38x/keyprogram.c | 158 +++++++++ board/gdsys/38x/keyprogram.h | 14 + board/gdsys/38x/kwbimage.cfg.in | 12 + board/gdsys/38x/spl.c | 21 ++ configs/controlcenterdc_defconfig | 54 +++ include/configs/controlcenterdc.h | 244 +++++++++++++ 20 files changed, 2585 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/controlcenterdc.dts create mode 100644 board/gdsys/38x/.gitignore create mode 100644 board/gdsys/38x/Kconfig create mode 100644 board/gdsys/38x/MAINTAINERS create mode 100644 board/gdsys/38x/Makefile create mode 100644 board/gdsys/38x/README create mode 100644 board/gdsys/38x/controlcenterdc.c create mode 100644 board/gdsys/38x/dt_helpers.c create mode 100644 board/gdsys/38x/dt_helpers.h create mode 100644 board/gdsys/38x/hre.c create mode 100644 board/gdsys/38x/hre.h create mode 100644 board/gdsys/38x/keyprogram.c create mode 100644 board/gdsys/38x/keyprogram.h create mode 100644 board/gdsys/38x/kwbimage.cfg.in create mode 100644 board/gdsys/38x/spl.c create mode 100644 configs/controlcenterdc_defconfig create mode 100644 include/configs/controlcenterdc.harch/arm/Kconfig +1
-0@@ -970,6 +970,7 @@ source "board/freescale/mx53loco/Kconfig" source "board/freescale/mx53smd/Kconfig" source "board/freescale/s32v234evb/Kconfig" source "board/freescale/vf610twr/Kconfig" +source "board/gdsys/38x/Kconfig" source "board/gumstix/pepper/Kconfig" source "board/h2200/Kconfig" source "board/hisilicon/hikey/Kconfig"arch/arm/dts/Makefile +2
-1@@ -76,7 +76,8 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-xp-gp.dtb \ armada-xp-maxbcm.dtb \ armada-xp-synology-ds414.dtb \ - armada-xp-theadorable.dtb + armada-xp-theadorable.dtb \ + controlcenterdc.dtb dtb-$(CONFIG_ARCH_UNIPHIER) += \ uniphier-ld11-ref.dtb \arch/arm/dts/controlcenterdc.dts new file +629
-0@@ -0,0 +1,629 @@ +/* + * Device Tree file for the Guntermann & Drunck ControlCenter-Compact board + * + * Copyright (C) 2016 Mario Six <[email protected]> + * + * based on the Device Tree file for Marvell Armada 388 evaluation board + * (DB-88F6820), which is + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni <[email protected]> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; + +#include "armada-388.dtsi" + +&uart0 { + u-boot,dm-pre-reloc; +}; + +&uart1 { + u-boot,dm-pre-reloc; +}; + +/ { + model = "Controlcenter Digital Compact"; + compatible = "marvell,a385-db", "marvell,armada388", + "marvell,armada385", "marvell,armada380"; + + chosen { + bootargs = "console=ttyS1,115200 earlyprintk"; + stdout-path = "/soc/internal-regs/serial at 12100"; + }; + + aliases { + ethernet0 = ð0; + ethernet2 = ð2; + mdio-gpio0 = &MDIO0; + mdio-gpio1 = &MDIO1; + mdio-gpio2 = &MDIO2; + spi0 = &spi0; + spi1 = &spi1; + i2c0 = &I2C0; + i2c1 = &I2C1; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; /* 256 MB */ + }; + + clocks { + sc16isclk: sc16isclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <11059200>; + }; + }; + + soc { + ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000 + MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>; + + internal-regs { + spi0: spi at 10600 { + status = "okay"; + sc16is741: sc16is741 at 0 { + compatible = "nxp,sc16is741"; + reg = <0>; + clocks = <&sc16isclk>; + spi-max-frequency = <4000000>; + interrupt-parent = <&gpio0>; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + spi1: spi at 10680 { + status = "okay"; + u-boot,dm-pre-reloc; + spi-flash at 0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q016a"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <108000000>; + }; + spi-flash at 1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128a11"; + reg = <1>; /* Chip select 1 */ + spi-max-frequency = <108000000>; + u-boot,dm-pre-reloc; + }; + }; + + I2C0: i2c at 11000 { + status = "okay"; + clock-frequency = <1000000>; + u-boot,dm-pre-reloc; + PCA21: pca9698 at 21 { + compatible = "nxp,pca9698"; + reg = <0x21>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA22: pca9698 at 22 { + compatible = "nxp,pca9698"; + u-boot,dm-pre-reloc; + reg = <0x22>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA23: pca9698 at 23 { + compatible = "nxp,pca9698"; + reg = <0x23>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA24: pca9698 at 24 { + compatible = "nxp,pca9698"; + reg = <0x24>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA25: pca9698 at 25 { + compatible = "nxp,pca9698"; + reg = <0x25>; + #gpio-cells = <2>; + gpio-controller; + }; + PCA26: pca9698 at 26 { + compatible = "nxp,pca9698"; + reg = <0x26>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + + I2C1: i2c at 11100 { + status = "okay"; + clock-frequency = <400000>; + at97sc3205t at 29 { + compatible = "atmel,at97sc3204t"; + reg = <0x29>; + u-boot,i2c-offset-len = <0>; + }; + emc2305 at 2d { + compatible = "smsc,emc2305"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2d>; + fan at 0 { + reg = <0>; + }; + fan at 1 { + reg = <1>; + }; + fan at 2 { + reg = <2>; + }; + fan at 3 { + reg = <3>; + }; + fan at 4 { + reg = <4>; + }; + }; + lm77 at 48 { + compatible = "national,lm77"; + reg = <0x48>; + }; + ads1015 at 49 { + compatible = "ti,ads1015"; + reg = <0x49>; + }; + lm77 at 4a { + compatible = "national,lm77"; + reg = <0x4a>; + }; + ads1015 at 4b { + compatible = "ti,ads1015"; + reg = <0x4b>; + }; + emc2305 at 4c { + compatible = "smsc,emc2305"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4c>; + fan at 0 { + reg = <0>; + }; + fan at 1 { + reg = <1>; + }; + fan at 2 { + reg = <2>; + }; + fan at 3 { + reg = <3>; + }; + fan at 4 { + reg = <4>; + }; + }; + at24c512 at 54 { + compatible = "atmel,24c512"; + reg = <0x54>; + u-boot,i2c-offset-len = <2>; + }; + ds1339 at 68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + serial at 12000 { + status = "okay"; + }; + + serial at 12100 { + status = "okay"; + }; + + ethernet at 34000 { + status = "okay"; + phy = <&phy1>; + phy-mode = "sgmii"; + }; + + usb at 58000 { + status = "ok"; + }; + + ethernet at 70000 { + status = "okay"; + phy = <&phy0>; + phy-mode = "sgmii"; + }; + + mdio at 72004 { + phy0: ethernet-phy at 0 { + reg = <1>; + }; + + phy1: ethernet-phy at 1 { + reg = <0>; + }; + }; + + sata at a8000 { + status = "okay"; + }; + + sdhci at d8000 { + broken-cd; + wp-inverted; + bus-width = <4>; + status = "okay"; + no-1-8-v; + }; + + usb3 at f0000 { + status = "okay"; + }; + }; + + pcie-controller { + status = "okay"; + /* + * The two PCIe units are accessible through + * standard PCIe slots on the board. + */ + pcie at 3,0 { + /* Port 0, Lane 0 */ + status = "okay"; + }; + }; + + MDIO0: mdio0 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio0 13 0 + /*MDIO*/ &gpio0 14 0>; + mv88e1240 at 0 { + reg = <0x0>; + }; + mv88e1240 at 1 { + reg = <0x1>; + }; + mv88e1240 at 2 { + reg = <0x2>; + }; + mv88e1240 at 3 { + reg = <0x3>; + }; + mv88e1240 at 4 { + reg = <0x4>; + }; + mv88e1240 at 5 { + reg = <0x5>; + }; + mv88e1240 at 6 { + reg = <0x6>; + }; + mv88e1240 at 7 { + reg = <0x7>; + }; + mv88e1240 at 8 { + reg = <0x8>; + }; + mv88e1240 at 9 { + reg = <0x9>; + }; + mv88e1240 at a { + reg = <0xa>; + }; + mv88e1240 at b { + reg = <0xb>; + }; + mv88e1240 at c { + reg = <0xc>; + }; + mv88e1240 at d { + reg = <0xd>; + }; + mv88e1240 at e { + reg = <0xe>; + }; + mv88e1240 at f { + reg = <0xf>; + }; + mv88e1240 at 10 { + reg = <0x10>; + }; + mv88e1240 at 11 { + reg = <0x11>; + }; + mv88e1240 at 12 { + reg = <0x12>; + }; + mv88e1240 at 13 { + reg = <0x13>; + }; + mv88e1240 at 14 { + reg = <0x14>; + }; + mv88e1240 at 15 { + reg = <0x15>; + }; + mv88e1240 at 16 { + reg = <0x16>; + }; + mv88e1240 at 17 { + reg = <0x17>; + }; + mv88e1240 at 18 { + reg = <0x18>; + }; + mv88e1240 at 19 { + reg = <0x19>; + }; + mv88e1240 at 1a { + reg = <0x1a>; + }; + mv88e1240 at 1b { + reg = <0x1b>; + }; + mv88e1240 at 1c { + reg = <0x1c>; + }; + mv88e1240 at 1d { + reg = <0x1d>; + }; + mv88e1240 at 1e { + reg = <0x1e>; + }; + mv88e1240 at 1f { + reg = <0x1f>; + }; + }; + + MDIO1: mdio1 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio0 25 0 + /*MDIO*/ &gpio1 13 0>; + mv88e1240 at 0 { + reg = <0x0>; + }; + mv88e1240 at 1 { + reg = <0x1>; + }; + mv88e1240 at 2 { + reg = <0x2>; + }; + mv88e1240 at 3 { + reg = <0x3>; + }; + mv88e1240 at 4 { + reg = <0x4>; + }; + mv88e1240 at 5 { + reg = <0x5>; + }; + mv88e1240 at 6 { + reg = <0x6>; + }; + mv88e1240 at 7 { + reg = <0x7>; + }; + mv88e1240 at 8 { + reg = <0x8>; + }; + mv88e1240 at 9 { + reg = <0x9>; + }; + mv88e1240 at a { + reg = <0xa>; + }; + mv88e1240 at b { + reg = <0xb>; + }; + mv88e1240 at c { + reg = <0xc>; + }; + mv88e1240 at d { + reg = <0xd>; + }; + mv88e1240 at e { + reg = <0xe>; + }; + mv88e1240 at f { + reg = <0xf>; + }; + mv88e1240 at 10 { + reg = <0x10>; + }; + mv88e1240 at 11 { + reg = <0x11>; + }; + mv88e1240 at 12 { + reg = <0x12>; + }; + mv88e1240 at 13 { + reg = <0x13>; + }; + mv88e1240 at 14 { + reg = <0x14>; + }; + mv88e1240 at 15 { + reg = <0x15>; + }; + mv88e1240 at 16 { + reg = <0x16>; + }; + mv88e1240 at 17 { + reg = <0x17>; + }; + mv88e1240 at 18 { + reg = <0x18>; + }; + mv88e1240 at 19 { + reg = <0x19>; + }; + mv88e1240 at 1a { + reg = <0x1a>; + }; + mv88e1240 at 1b { + reg = <0x1b>; + }; + mv88e1240 at 1c { + reg = <0x1c>; + }; + mv88e1240 at 1d { + reg = <0x1d>; + }; + mv88e1240 at 1e { + reg = <0x1e>; + }; + mv88e1240 at 1f { + reg = <0x1f>; + }; + }; + + MDIO2: mdio2 { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = < /*MDC*/ &gpio1 14 0 + /*MDIO*/ &gpio0 24 0>; + mv88e1240 at 0 { + reg = <0x0>; + }; + mv88e1240 at 1 { + reg = <0x1>; + }; + mv88e1240 at 2 { + reg = <0x2>; + }; + mv88e1240 at 3 { + reg = <0x3>; + }; + mv88e1240 at 4 { + reg = <0x4>; + }; + mv88e1240 at 5 { + reg = <0x5>; + }; + mv88e1240 at 6 { + reg = <0x6>; + }; + mv88e1240 at 7 { + reg = <0x7>; + }; + mv88e1240 at 8 { + reg = <0x8>; + }; + mv88e1240 at 9 { + reg = <0x9>; + }; + mv88e1240 at a { + reg = <0xa>; + }; + mv88e1240 at b { + reg = <0xb>; + }; + mv88e1240 at c { + reg = <0xc>; + }; + mv88e1240 at d { + reg = <0xd>; + }; + mv88e1240 at e { + reg = <0xe>; + }; + mv88e1240 at f { + reg = <0xf>; + }; + mv88e1240 at 10 { + reg = <0x10>; + }; + mv88e1240 at 11 { + reg = <0x11>; + }; + mv88e1240 at 12 { + reg = <0x12>; + }; + mv88e1240 at 13 { + reg = <0x13>; + }; + mv88e1240 at 14 { + reg = <0x14>; + }; + mv88e1240 at 15 { + reg = <0x15>; + }; + }; + }; + + cat_gpio_0 { + compatible = "generic,cat-gpio-0"; + gpios = <&PCA23 0x20 0x0>; + }; + + cat_gpio_1 { + compatible = "generic,cat-gpio-1"; + gpios = <&PCA21 0x20 0x0>; + }; + + cat_gpio_2 { + compatible = "generic,cat-gpio-2"; + gpios = <&PCA24 0x20 0x0>; + }; + + cat_gpio_3 { + compatible = "generic,cat-gpio-3"; + gpios = <&PCA25 0x20 0x0>; + }; + + cat_gpio_4 { + compatible = "generic,cat-gpio-4"; + gpios = <&PCA26 0x20 0x0>; + }; + + second_octo_gpio_0 { + compatible = "generic,second-octo-gpio-0"; + gpios = <&PCA23 0x27 0x0>; + }; + + fpga_program_gpio { + compatible = "generic,fpga-program-gpio"; + u-boot,dm-pre-reloc; + gpios = <&PCA22 31 0>; + }; + + fpga_done_gpio { + compatible = "generic,fpga-done-gpio"; + u-boot,dm-pre-reloc; + gpios = <&PCA22 19 0>; + }; + + fpga_ready_gpio { + compatible = "generic,fpga-ready-gpio"; + u-boot,dm-pre-reloc; + gpios = <&PCA22 27 0>; + }; + + leds { + compatible = "gpio-leds"; + + finder_led { + label = "finder-led"; + gpios = <&PCA22 25 0>; + }; + + status_led { + label = "status-led"; + gpios = <&gpio0 29 0>; + }; + }; +};arch/arm/mach-mvebu/Kconfig +4
-0@@ -102,6 +102,10 @@ config TARGET_THEADORABLE bool "Support theadorable Armada XP" select MV78260 +config TARGET_CONTROLCENTERDC + bool "Support CONTROLCENTERDC" + select 88F6820 + endchoice config SYS_BOARDboard/gdsys/38x/.gitignore new file +1
-0@@ -0,0 +1 @@ +kwbimage.cfgboard/gdsys/38x/Kconfig new file +28
-0@@ -0,0 +1,42 @@ +if TARGET_CONTROLCENTERDC + +config SYS_BOARD + default "38x" + +config SYS_VENDOR + default "gdsys" + +config SYS_SOC + default "mvebu" + +config SYS_CONFIG_NAME + default "controlcenterdc" + +menu "Controlcenter DC board options" + +choice + prompt "Select boot method" + +config SPL_BOOT_DEVICE_SPI + bool "SPI" + +config SPL_BOOT_DEVICE_MMC + bool "MMC" + select SPL_LIBDISK_SUPPORT + +endchoice +board/gdsys/38x/Kconfig line 38
Quoted 10 lines
board/gdsys/38x/Kconfig new file +10
-0+#config SPL_BOOT_DEVICE +# int +# default 1 if SPL_BOOT_DEVICE_SPI +# default 2 if SPL_BOOT_DEVICE_MMC + +config SYS_BOOTIMAGE_DEST_ADDR + hex "Boot image destination address" + default 0x007fffc0 + help + BlahHmmm, the help text is not really "helpful". ;)
Quoted 2 lines
This option is also not referenced, so perhaps you can remove it?
Ahh, that was a leftover from a test I did (hence the very eloquently written help text). Sorry about that.
Will be gone in v2.
Quoted 41 lines
Quoted 41 lines
board/gdsys/38x/Kconfig new file +4
-0+ +endmenu + +endifboard/gdsys/38x/MAINTAINERS new file +7
-0@@ -0,0 +1,7 @@ +38X BOARD +M: Dirk Eibach <[email protected]> +M: Mario Six <[email protected]> +S: Maintained +F: board/gdsys/38x/ +F: include/configs/controlcenterdc.h +F: configs/controlcenterdc_defconfigboard/gdsys/38x/Makefile new file +18
-0@@ -0,0 +1,30 @@ +# +# Copyright (C) 2015 Stefan Roese <[email protected]> +# Copyright (C) 2015 Reinhard Pfau <[email protected]> +# Copyright (C) 2016 Mario Six <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_TARGET_CONTROLCENTERDC) += controlcenterdc.o hre.o spl.o keyprogram.o dt_helpers.o + +ifeq ($(CONFIG_SPL_BUILD),) + +extra-$(CONFIG_TARGET_CONTROLCENTERDC) += kwbimage.cfg + +ifneq ($(CONFIG_TARGET_CONTROLCENTERDC),) +KWB_REPLACE += BOOT_FROM +ifneq ($(CONFIG_SPL_BOOT_DEVICE_SPI),) + KWB_CFG_BOOT_FROM=spi
Quoted 9 lines
board/gdsys/38x/Makefile line 23
Quoted 5 lines
board/gdsys/38x/Makefile new file +5
-0+endif +ifneq ($(CONFIG_SPL_BOOT_DEVICE_MMC),) + KWB_CFG_BOOT_FROM=sdio +endif +endifDo you have multiple build targets for this directory? Do you need to have this check with
CONFIG_TARGET_CONTROLCENTERDC?
No, there is only the one build target atm, so the check is indeed useless; will remove in v2.
Quoted 26 lines
Quoted 26 lines
board/gdsys/38x/Makefile new file +7
-0+ +$(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ + include/config/auto.conf + $(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ + <$< >$@ + +endifboard/gdsys/38x/README new file +13
-0@@ -0,0 +1,18 @@ +Update from original Marvell U-Boot to mainline U-Boot: +------------------------------------------------------- + +The resulting image including the SPL binary with the +full DDR setup is "u-boot-spl.kwb". + +To update the SPI NOR flash, please use the following +command: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf update 2000000 0 60000 + +Note that the original Marvell U-Boot seems to have
Quoted 9 lines
board/gdsys/38x/README line 18
Quoted 5 lines
board/gdsys/38x/README new file +5
-0+problems with the "sf update" command. This does not +work reliable. So here this command should be used: + +=> sf probe;tftpboot 2000000 db-88f6820-gp/u-boot-spl.kwb;\ +sf erase 0 60000;sf write 2000000 0 60000You copied this file from the Marvell directory. Does it really make sense to add it here as well? I suggest to just remove it.
OK, will remove in v2.
Quoted 151 lines
Quoted 151 lines
board/gdsys/38x/controlcenterdc.c new file +145
-0@@ -0,0 +1,717 @@ +/* +* Copyright (C) 2015 Stefan Roese <[email protected]> +* Copyright (C) 2016 Mario Six <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <console.h> /* disable_ctrlc */ +#include <miiphy.h> +#include <tpm.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm-generic/gpio.h> + +#include "../drivers/ddr/marvell/a38x/ddr3_a38x_topology.h" +#include "../arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.h" + +#include "keyprogram.h" +#include "dt_helpers.h" + +DECLARE_GLOBAL_DATA_PTR ; + +#define ETH_PHY_CTRL_REG 0 +#define ETH_PHY_CTRL_POWER_DOWN_BIT 11 +#define ETH_PHY_CTRL_POWER_DOWN_MASK (1 << ETH_PHY_CTRL_POWER_DOWN_BIT) + +#define DB_GP_88F68XX_GPP_OUT_ENA_LOW 0x7fffffff +#define DB_GP_88F68XX_GPP_OUT_ENA_MID 0xffffefff + +#define DB_GP_88F68XX_GPP_OUT_VAL_LOW 0x0 +#define DB_GP_88F68XX_GPP_OUT_VAL_MID 0x00001000 +#define DB_GP_88F68XX_GPP_POL_LOW 0x0 +#define DB_GP_88F68XX_GPP_POL_MID 0x0 + +#ifndef CONFIG_SPL_BUILD +enum { +HWVER_100 =0 , +HWVER_110 =1 , +HWVER_120 =2 , +}; + +enum { +PORTTYPE_MAIN_CAT , +PORTTYPE_TOP_CAT , +PORTTYPE_16C_16F , +PORTTYPE_UNKNOWN +}; + +static struct porttype { +bool phy_invert_in_pol; +bool phy_invert_out_pol; +} porttypes[] = { + { true, false }, + { false, true }, + { false, false }, +}; + +struct ihs_fpga { +u32 reflection_low;/* 0x0000 */ +u32 versions;/* 0x0004 */ +u32 fpga_version;/* 0x0008 */ +u32 fpga_features;/* 0x000c */ +u32 reserved0[4 ];/* 0x0010 */ +u32 control;/* 0x0020 */ +u32 reserved1[375 ];/* 0x0024 */ +u32 qsgmii_port_state[80 ];/* 0x0600 */ +}; + +static struct ihs_fpga *fpga; + +static struct pci_device_id hydra_supported[] = { + {0x6d5e ,0xcdc1 }, + {} +}; +#endif + +/* +* Define the DDR layout / topology here in the board file. This will +* be used by the DDR3 init code in the SPL U-Boot version to configure +* the DDR3 controller. +*/ +static struct hws_topology_map ddr_topology_map = { +0x1 ,/* active interfaces */ +/* cs_mask, mirror, dqs_swap, ck_swap X PUPs */ + { { { {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 }, + {0x1 ,0 ,0 ,0 } }, +SPEED_BIN_DDR_1600K ,/* speed_bin */ +BUS_WIDTH_16 ,/* memory_width */ +MEM_4G ,/* mem_size */ +DDR_FREQ_533 ,/* frequency */ +0 ,0 ,/* cas_l cas_wl */ +HWS_TEMP_LOW } },/* temperature */ +5 ,/* Num Of Bus Per Interface*/ +BUS_MASK_32BIT /* Busses mask */ +}; + +static struct serdes_map serdes_topology_map[] = { + {SGMII0 ,SERDES_SPEED_1_25_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, + {USB3_HOST0 ,SERDES_SPEED_5_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, +/* SATA tx polarity is inverted */ + {SATA1 ,SERDES_SPEED_3_GBPS ,SERDES_DEFAULT_MODE ,0 ,1 }, + {SGMII2 ,SERDES_SPEED_1_25_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, + {DEFAULT_SERDES ,SERDES_SPEED_3_GBPS ,SERDES_DEFAULT_MODE ,0 ,0 }, + {PEX2 ,SERDES_SPEED_5_GBPS ,PEX_ROOT_COMPLEX_X1 ,0 ,0 } +}; + +int hws_board_topology_load (struct serdes_map **serdes_map_array,u8 *count) +{ + *serdes_map_array = serdes_topology_map; + *count =ARRAY_SIZE (serdes_topology_map); +return 0 ; +} + +void board_pex_config (void ) +{ +#ifdef CONFIG_SPL_BUILD +uint k; +struct gpio_desc gpio = {}; + +if (get_gpio ("generic,fpga-program-gpio" , &gpio)) { +/* prepare FPGA reconfiguration */ +dm_gpio_set_dir_flags (&gpio,GPIOD_IS_OUT ); +dm_gpio_set_value (&gpio,0 ); + +/* give lunatic PCIe clock some time to stabilize */ +mdelay (500 ); + +/* start FPGA reconfiguration */ +dm_gpio_set_dir_flags (&gpio,GPIOD_IS_IN ); + } + +/* wait for FPGA done */ +if (get_gpio ("generic,fpga-done-gpio" , &gpio)) { +for (k =0 ; k <20 ; ++k) { +if (dm_gpio_get_value (&gpio)) { +printf ("FPGA done after %u rounds\n" , k); +break ; + } +mdelay (100 ); + }
Quoted 9 lines
board/gdsys/38x/controlcenterdc.c line 150
Quoted 5 lines
board/gdsys/38x/controlcenterdc.c new file +5
-0+ } + +/* disable FPGA reset */ +kw_gpio_set_valid (6 ,GPIO_OUTPUT_OK ); +kw_gpio_direction_output (6 ,1 );Ah, here you use the "old" GPIO infrastucture. Please move to the DM GPIO driver and use the generic API instead.
OK, I'll look into that. I have no idea how well the bitbang MIIPHY functions will work with DM-style GPIOs (they have only ever been used with legacy GPIO interfaces from what I know), so I'll need to experiment with that a little.
Quoted 55 lines
Quoted 55 lines
board/gdsys/38x/controlcenterdc.c new file +55
-0+ +/* wait for FPGA ready */ +if (get_gpio ("generic,fpga-ready-gpio" , &gpio)) { +for (k =0 ; k <2 ; ++k) { +if (!dm_gpio_get_value (&gpio)) +break ; +mdelay (100 ); + } + } +#endif +} + +struct hws_topology_map *ddr3_get_topology_map (void ) +{ +return &ddr_topology_map; +} + +int board_early_init_f (void ) +{ +#ifdef CONFIG_SPL_BUILD +/* Configure MPP */ +writel (0x00111111 ,MVEBU_MPP_BASE +0x00 ); +writel (0x40040000 ,MVEBU_MPP_BASE +0x04 ); +writel (0x00466444 ,MVEBU_MPP_BASE +0x08 ); +writel (0x00043300 ,MVEBU_MPP_BASE +0x0c ); +writel (0x44400000 ,MVEBU_MPP_BASE +0x10 ); +writel (0x20000334 ,MVEBU_MPP_BASE +0x14 ); +writel (0x40000000 ,MVEBU_MPP_BASE +0x18 ); +writel (0x00004444 ,MVEBU_MPP_BASE +0x1c ); + +/* Set GPP Out value */ +writel (DB_GP_88F68XX_GPP_OUT_VAL_LOW ,MVEBU_GPIO0_BASE +0x00 ); +writel (DB_GP_88F68XX_GPP_OUT_VAL_MID ,MVEBU_GPIO1_BASE +0x00 ); + +/* Set GPP Polarity */ +writel (DB_GP_88F68XX_GPP_POL_LOW ,MVEBU_GPIO0_BASE +0x0c ); +writel (DB_GP_88F68XX_GPP_POL_MID ,MVEBU_GPIO1_BASE +0x0c ); + +/* Set GPP Out Enable */ +writel (DB_GP_88F68XX_GPP_OUT_ENA_LOW ,MVEBU_GPIO0_BASE +0x04 ); +writel (DB_GP_88F68XX_GPP_OUT_ENA_MID ,MVEBU_GPIO1_BASE +0x04 ); +#endif + +return 0 ; +} + +int board_init (void ) +{ +/* adress of boot parameters */ + gd->bd->bi_boot_params =mvebu_sdram_bar (0 ) +0x100 ; + +return 0 ; +} + +int checkboard (void )
Quoted 9 lines
board/gdsys/38x/controlcenterdc.c line 210
Quoted 5 lines
board/gdsys/38x/controlcenterdc.c new file +5
-0+{ +puts ("Board: Controlcenter Digital Compact\n" ); + +return 0 ; +}With DT support you should already get the board model printed from the DT. Do yo need this line here as well?
True, that produced two almost identical lines on startup. I'll just remove the checkboard function in v2.
Quoted 92 lines
Quoted 92 lines
board/gdsys/38x/controlcenterdc.c new file +92
-0+ +#ifndef CONFIG_SPL_BUILD +static void ihs_phy_config (struct phy_device *phydev,bool qinpn,bool qoutpn) +{ +u16 reg; + +phy_config (phydev); + +/* enable QSGMII autonegotiation with flow control */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0004 ); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,16 ); + reg |= (3 <<6 ); +phy_write (phydev,MDIO_DEVAD_NONE ,16 , reg); + +/* +* invert QSGMII Q_INP/N and Q_OUTP/N if required +* and perform global reset +*/ + reg =phy_read (phydev,MDIO_DEVAD_NONE ,26 ); +if (qinpn) + reg |= (1 <<13 ); +if (qoutpn) + reg |= (1 <<12 ); + reg |= (1 <<15 ); +phy_write (phydev,MDIO_DEVAD_NONE ,26 , reg); + +/* advertise 1000BASE-T full-duplex only */ +phy_write (phydev,MDIO_DEVAD_NONE ,22 ,0x0000 ); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,4 ); + reg &= ~0x1e0 ; +phy_write (phydev,MDIO_DEVAD_NONE ,4 , reg); + reg =phy_read (phydev,MDIO_DEVAD_NONE ,9 ); + reg = (reg & ~0x300 ) |0x200 ; +phy_write (phydev,MDIO_DEVAD_NONE ,9 , reg); + +/* copper power up */ + reg =phy_read (phydev,MDIO_DEVAD_NONE ,16 ); + reg &= ~0x0004 ; +phy_write (phydev,MDIO_DEVAD_NONE ,16 , reg); +} + +void init_host_phys (struct mii_dev *bus) +{ +uint k; + +for (k =0 ; k <2 ; ++k) { +struct phy_device *phydev; + + phydev =phy_find_by_mask (bus,1 << k, +PHY_INTERFACE_MODE_SGMII ); + +if (phydev) +phy_config (phydev); + } +} + +uint calculate_octo_phy_mask (void ) +{ +uint k; +uint octo_phy_mask =0 ; +struct gpio_desc gpio = {}; +char name[64 ]; + +/* mark all octo phys that should be present */ +for (k =0 ; k <5 ; ++k) { +snprintf (name,64 ,"generic,cat-gpio-%u" , k); + +if (!get_gpio (name, &gpio)) +continue ; + +/* check CAT flag */ +if (dm_gpio_get_value (&gpio)) + octo_phy_mask |= (1 << (k *2 )); +else +/* If CAT == 0, there's no second octo phy -> skip */ +continue ; + +snprintf (name,64 ,"generic,second-octo-gpio-%u" , k); + +if (!get_gpio (name, &gpio)) { +/* default: second octo phy is present */ + octo_phy_mask |= (1 << (k *2 +1 )); +continue ; + } + +if (dm_gpio_get_value (&gpio) ==0 ) + octo_phy_mask |= (1 << (k *2 +1 )); + } + +return octo_phy_mask; +} +
Quoted 9 lines
board/gdsys/38x/controlcenterdc.c line 307
Quoted 5 lines
board/gdsys/38x/controlcenterdc.c new file +5
-0+int register_miiphy_bus (uint k,struct mii_dev **bus) +{ +int retval; +struct mii_dev *mdiodev =mdio_alloc (); +char *name = bb_miiphy_buses[k].name;I'm wondering how this works if "
bb_miiphy_buses" is defined later in this file and you have no header file.
The bb_miiphy_busses array is declared in miiphy.h as extern, and we include this header in controlcenterdc.c, so there's only a bit of magic at work here. :-)
Quoted 51 lines
Quoted 51 lines
board/gdsys/38x/controlcenterdc.c new file +51
-0+ +if (!mdiodev) +return -ENOMEM ; +strncpy (mdiodev->name, + name, +MDIO_NAME_LEN ); + mdiodev->read = bb_miiphy_read; + mdiodev->write = bb_miiphy_write; + + retval =mdio_register (mdiodev); +if (retval <0 ) +return retval; + *bus =miiphy_get_dev_by_name (name); + +return 0 ; +} + +struct porttype *get_porttype (uint octo_phy_mask,uint k) +{ +uint octo_index = k *4 ; + +if (!k) { +if (octo_phy_mask &0x01 ) +return &porttypes[PORTTYPE_MAIN_CAT ]; +else if (!(octo_phy_mask &0x03 )) +return &porttypes[PORTTYPE_16C_16F ]; + }else { +if (octo_phy_mask & (1 << octo_index)) +return &porttypes[PORTTYPE_TOP_CAT ]; + } + +return NULL ; +} + +int init_octo_phys (uint octo_phy_mask) +{ +uint bus_idx; + +/* there are up to four octo-phys on each mdio bus */ +for (bus_idx =0 ; bus_idx < bb_miiphy_buses_num; ++bus_idx) { +uint m; +uint octo_index = bus_idx *4 ; +struct mii_dev *bus =NULL ; +struct porttype *porttype =NULL ; +int ret; + + porttype =get_porttype (octo_phy_mask, bus_idx); + +if (!porttype) +continue ; +
Quoted 9 lines
board/gdsys/38x/controlcenterdc.c line 364
Quoted 6 lines
board/gdsys/38x/controlcenterdc.c new file +6
-0+for (m =0 ; m <4 ; ++m) { +uint phy_idx; + +/* Register a bus device if there is at least one phy +* on the current bus +*/ Multiline comment style please.
OK, will fix in v2.
Quoted 346 lines
Quoted 346 lines
board/gdsys/38x/controlcenterdc.c new file +346
-0+if (!m && octo_phy_mask & (0xf << octo_index)) { + ret =register_miiphy_bus (bus_idx, &bus); +if (ret) +return ret; + } + +if (!(octo_phy_mask & (1 << (octo_index + m)))) +continue ; + +for (phy_idx =0 ; phy_idx <8 ; ++phy_idx) { +struct phy_device *phydev =phy_find_by_mask ( + bus,1 << (m *8 + phy_idx), +PHY_INTERFACE_MODE_MII ); + +printf (" %u" , bus_idx *32 + m *8 + phy_idx); + +ihs_phy_config (phydev, + porttype->phy_invert_in_pol, + porttype->phy_invert_out_pol); + } + } + } + +return 0 ; +} + +int ccdc_eth_init (void ) +{ +uint k; +uint octo_phy_mask =0 ; +int ret; +struct mii_dev *bus; + +/* Init SoC's phys */ + bus =miiphy_get_dev_by_name ("ethernet at 34000" ); + +if (bus) +init_host_phys (bus); + + bus =miiphy_get_dev_by_name ("ethernet at 70000" ); + +if (bus) +init_host_phys (bus); + +/* Init octo phys */ + octo_phy_mask =calculate_octo_phy_mask (); + +printf ("IHS PHYS: %08x" , octo_phy_mask); + + ret =init_octo_phys (octo_phy_mask); + +if (ret) +return ret; + +printf ("\n" ); + +/* reset all FPGA-QSGMII instances */ +for (k =0 ; k <80 ; ++k) +writel (1 <<31 , &fpga->qsgmii_port_state[k]); + +udelay (100 ); + +for (k =0 ; k <80 ; ++k) +writel (0 , &fpga->qsgmii_port_state[k]); +return 0 ; +} + +void print_hydra_version (uint index) +{ +u32 versions =readl (&fpga->versions); +u32 fpga_version =readl (&fpga->fpga_version); + +uint hardware_version = versions &0xf ; + +printf ("FPGA%u: mapped to %p\n " , index, fpga); + +switch (hardware_version) { +case HWVER_100 : +printf ("HW-Ver 1.00\n" ); +break ; + +case HWVER_110 : +printf ("HW-Ver 1.10\n" ); +break ; + +case HWVER_120 : +printf ("HW-Ver 1.20\n" ); +break ; + +default : +printf ("HW-Ver %d(not supported)\n" , + hardware_version); +break ; + } + +printf (" FPGA V %d.%02d\n" , + fpga_version /100 , fpga_version %100 ); +} + +static void hydra_initialize (void ) +{ +uint i; +pci_dev_t devno; + +/* Find and probe all the matching PCI devices */ +for (i =0 ; (devno =pci_find_devices (hydra_supported, i)) >=0 ; i++) { +u32 val; + +/* Try to enable I/O accesses and bus-mastering */ + val =PCI_COMMAND_MEMORY |PCI_COMMAND_MASTER ; +pci_write_config_dword (devno,PCI_COMMAND , val); + +/* Make sure it worked */ +pci_read_config_dword (devno,PCI_COMMAND , &val); +if (!(val &PCI_COMMAND_MEMORY )) { +puts ("Can't enable I/O memory\n" ); +continue ; + } +if (!(val &PCI_COMMAND_MASTER )) { +puts ("Can't enable bus-mastering\n" ); +continue ; + } + +/* read FPGA details */ + fpga =pci_map_bar (devno,PCI_BASE_ADDRESS_0 , +PCI_REGION_MEM ); + +print_hydra_version (i); + } +} +#endif + +int board_late_init (void ) +{ +#ifndef CONFIG_SPL_BUILD +hydra_initialize (); +#endif +return 0 ; +} + +int board_fix_fdt (void ) +{ +struct udevice *bus; +uint k; +char name[64 ]; + + bus =dev_get_by_ofname ("/soc/internal-regs/i2c at 11000" ); + +for (k =0x21 ; k <=0x26 ; k++) { +snprintf (name,64 , +"/soc/internal-regs/i2c at 11000/pca9698@%02x" , k); + +if (!dm_i2c_simple_probe (bus, k)) +fdt_disable_by_ofname (name); + } + +return 0 ; +} + +int last_stage_init (void ) +{ +disable_ctrlc (1 ); + +#ifndef CONFIG_SPL_BUILD +ccdc_eth_init (); +#endif +if (tpm_init () ||tpm_startup (TPM_ST_CLEAR ) || +tpm_continue_self_test ()) { +return 1 ; + } + +mdelay (37 ); + +flush_keys (); +load_and_run_keyprog (); + +return 0 ; +} + +#ifndef CONFIG_SPL_BUILD + +#define REFL_PATTERN (0xdededede) +#define REFL_PATTERN_INV (~REFL_PATTERN) + +int do_hydrate(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + uint k = 0; + void __iomem *pcie2_base = (void __iomem *)(MVEBU_REG_PCIE_BASE + + 0x4000); + + if (!fpga) + return -1; + + while (1) { + u32 res; + + writel(REFL_PATTERN, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN_INV) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN_INV); + writel(REFL_PATTERN_INV, &fpga->reflection_low); + res = readl(&fpga->reflection_low); + if (res != REFL_PATTERN) + printf("round %u: read %08x, expected %08x\n", + k, res, REFL_PATTERN); + + res = readl(pcie2_base + 0x118) & 0x1f; + if (res) + printf("FrstErrPtr %u\n", res); + res = readl(pcie2_base + 0x104); + if (res) { + printf("Uncorrectable Error Status 0x%08x\n", res); + writel(res, pcie2_base + 0x104); + } + + if (!(++k % 10000)) + printf("round %u\n", k); + + if (ctrlc()) + break; + } + + return 0; +} + +U_BOOT_CMD( + hydrate, 1, 0, do_hydrate, + "hydra reflection test", + "hydra reflection test" +); + +/* + * MII GPIO bitbang implementation + * MDC MDIO bus + * 13 14 PHY1-4 + * 25 45 PHY5-8 + * 46 24 PHY9-10 + */ + +struct gpio_mii { + int mdc; + int mdio; + int mdio_value; +} gpio_mii_set[] = { + { 13, 14, 1 }, + { 25, 45, 1 }, + { 46, 24, 1 }, +}; + +static int mii_mdio_init(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_set_valid(gpio_mii->mdc, GPIO_OUTPUT_OK); + kw_gpio_set_valid(gpio_mii->mdio, GPIO_INPUT_OK | GPIO_OUTPUT_OK); + kw_gpio_direction_output(gpio_mii->mdc, 1); + + return 0; +} + +static int mii_mdio_active(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_direction_output(gpio_mii->mdio, gpio_mii->mdio_value); + + return 0; +} + +static int mii_mdio_tristate(struct bb_miiphy_bus *bus) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_direction_input(gpio_mii->mdio); + + return 0; +} + +static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_set_value(gpio_mii->mdio, v); + gpio_mii->mdio_value = v; + + return 0; +} + +static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + *v = (kw_gpio_get_value(gpio_mii->mdio) != 0); + + return 0; +} + +static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) +{ + struct gpio_mii *gpio_mii = bus->priv; + + kw_gpio_set_value(gpio_mii->mdc, v); + + return 0; +} + +static int mii_delay(struct bb_miiphy_bus *bus) +{ + udelay(1); + + return 0; +} + +struct bb_miiphy_bus bb_miiphy_buses[] = { + { + .name = "ihs0", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[0], + }, + { + .name = "ihs1", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &gpio_mii_set[1], + }, + { + .name = "ihs2", + .init = mii_mdio_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay,
Quoted 9 lines
board/gdsys/38x/controlcenterdc.c line 716
Quoted 6 lines
board/gdsys/38x/controlcenterdc.c new file +6
-0+ .priv = &gpio_mii_set[2], + }, +}; + +int bb_miiphy_buses_num =sizeof (bb_miiphy_buses) / +sizeof (bb_miiphy_buses[0 ]);static? And can you use
ARRAY_SIZE()?
Usage of ARRAY_SIZE is OK, but the variable bb_miiphy_buses itself is first declare as extern non-static in include/miiphy.h, so we will have to follow that convention here.
Quoted 6 lines
board/gdsys/38x/controlcenterdc.c line 717
Quoted 1 line
board/gdsys/38x/controlcenterdc.c new file +1
-0+#endif Perhaps its also a good idea to move at least some of this code (especiall the command and perhaps some MDIO stuff) into separate files that are only compiled for non-SPL U-Boot. This will remove some of the #ifdefs as well.
OK, will look into separating out some things for v2.
Quoted 61 lines
Quoted 61 lines
board/gdsys/38x/dt_helpers.c new file +55
-0@@ -0,0 +1,60 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <i2c.h> +#include <dm.h> +#include <fdt_support.h> +#include <asm-generic/gpio.h> + +DECLARE_GLOBAL_DATA_PTR ; + +bool get_gpio (char *name,struct gpio_desc *gpio) +{ +int node =fdt_node_offset_by_compatible (gd->fdt_blob,0 , name); +int ret; + +if (node <0 ) +return false; + + ret =gpio_request_by_name_nodev (gd->fdt_blob, node,"gpios" ,0 , gpio, +0 ); + +if (ret <0 ) +return false; + +return dm_gpio_is_valid (gpio); +} + +int fdt_disable_by_ofname (char *ofname) +{ +void *blob = gd->fdt_blob; +int offset; + + offset =fdt_path_offset (blob, ofname); +return fdt_status_disabled (blob, offset); +} + +struct udevice *dev_get_by_ofname (char *ofname) +{ +void *blob = gd->fdt_blob; +int offset; +struct udevice *dev; + + offset =fdt_path_offset (blob, ofname); +device_get_global_by_of_offset (offset, &dev); + +return dev; +} + +bool dm_i2c_simple_probe (struct udevice *bus,uint chip_addr) +{
Quoted 9 lines
board/gdsys/38x/dt_helpers.c line 60
Quoted 5 lines
board/gdsys/38x/dt_helpers.c new file +5
-0+struct udevice *dev; + +return !dm_i2c_probe (bus, chip_addr,DM_I2C_CHIP_RD_ADDRESS | +DM_I2C_CHIP_WR_ADDRESS , &dev); +}At least some of this might be very helpful as common U-Boot functions available for all boards.
OK, I'll create separate patches for "get_gpio" (with a better name) and "dev_get_by_ofname" and put them in sensible subsystems (possibly "dm_i2c_simple_probe" too). "fdt_disable_by_ofname" is probably a little too special to our use case.
Quoted 379 lines
Quoted 379 lines
board/gdsys/38x/dt_helpers.h new file +16
-0@@ -0,0 +1,16 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __DT_HELPERS_H +#define __DT_HELPERS_H + +bool get_gpio (char *name,struct gpio_desc *gpio); +int fdt_disable_by_ofname (char *ofname); +struct udevice *dev_get_by_ofname (char *ofname); +bool dm_i2c_simple_probe (struct udevice *bus,uint chip_addr); + +#endif /* __DT_HELPERS_H */ board/gdsys/38x/hre.c new file +351
-0@@ -0,0 +1,517 @@ +/* +* (C) Copyright 2013 +* Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <malloc.h> +#include <fs.h> +#include <i2c.h> +#include <mmc.h> +#include <tpm.h> +#include <u-boot/sha1.h> +#include <asm/byteorder.h> +#include <asm/unaligned.h> +#include <pca9698.h> + +#include "hre.h" + +/* other constants */ +enum { +ESDHC_BOOT_IMAGE_SIG_OFS =0x40 , +ESDHC_BOOT_IMAGE_SIZE_OFS =0x48 , +ESDHC_BOOT_IMAGE_ADDR_OFS =0x50 , +ESDHC_BOOT_IMAGE_TARGET_OFS =0x58 , +ESDHC_BOOT_IMAGE_ENTRY_OFS =0x60 , +}; + +enum { +I2C_SOC_0 =0 , +I2C_SOC_1 =1 , +}; + +enum access_mode { +HREG_NONE =0 , +HREG_RD =1 , +HREG_WR =2 , +HREG_RDWR =3 , +}; + +/* register constants */ +enum { +FIX_HREG_DEVICE_ID_HASH =0 , +FIX_HREG_UNUSED1 =1 , +FIX_HREG_UNUSED2 =2 , +FIX_HREG_VENDOR =3 , +COUNT_FIX_HREGS +}; + +static struct h_reg pcr_hregs[24 ]; +static struct h_reg fix_hregs[COUNT_FIX_HREGS ]; +static struct h_reg var_hregs[8 ]; + +/* hre opcodes */ +enum { +/* opcodes w/o data */ +HRE_NOP =0x00 , +HRE_SYNC =HRE_NOP , +HRE_CHECK0 =0x01 , +/* opcodes w/o data, w/ sync dst */ +/* opcodes w/ data */ +HRE_LOAD =0x81 , +/* opcodes w/data, w/sync dst */ +HRE_XOR =0xC1 , +HRE_AND =0xC2 , +HRE_OR =0xC3 , +HRE_EXTEND =0xC4 , +HRE_LOADKEY =0xC5 , +}; + +/* hre errors */ +enum { +HRE_E_OK =0 , +HRE_E_TPM_FAILURE , +HRE_E_INVALID_HREG , +}; + +static uint64_t device_id; +static uint64_t device_cl; +static uint64_t device_type; + +static uint32_t platform_key_handle; + +static uint32_t hre_tpm_err; +static int hre_err =HRE_E_OK ; + +#define IS_PCR_HREG (spec) ((spec) & 0x20) +#define IS_FIX_HREG (spec) (((spec) & 0x38) == 0x08) +#define IS_VAR_HREG (spec) (((spec) & 0x38) == 0x10) +#define HREG_IDX (spec) ((spec) & (IS_PCR_HREG(spec) ? 0x1f : 0x7)) + +static const uint8_t vendor[] ="Guntermann & Drunck" ; + +/** +* @brief get the size of a given (TPM) NV area +* @param index NV index of the area to get size for +* @param size pointer to the size +* @return 0 on success, != 0 on error +*/ +static int get_tpm_nv_size (uint32_t index,uint32_t *size) +{ +uint32_t err; +uint8_t info[72 ]; +uint8_t *ptr; +uint16_t v16; + + err =tpm_get_capability (TPM_CAP_NV_INDEX , index, + info,sizeof (info)); +if (err) { +printf ("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n" , + index, err); +return 1 ; + } + +/* skip tag and nvIndex */ + ptr = info +6 ; +/* skip 2 pcr info fields */ + v16 =get_unaligned_be16 (ptr); + ptr +=2 + v16 +1 +20 ; + v16 =get_unaligned_be16 (ptr); + ptr +=2 + v16 +1 +20 ; +/* skip permission and flags */ + ptr +=6 +3 ; + + *size =get_unaligned_be32 (ptr); +return 0 ; +} + +/** +* @brief search for a key by usage auth and pub key hash. +* @param auth usage auth of the key to search for +* @param pubkey_digest (SHA1) hash of the pub key structure of the key +* @param[out] handle the handle of the key iff found +* @return 0 if key was found in TPM; != 0 if not. +*/ +static int find_key (const uint8_t auth[20 ],const uint8_t pubkey_digest[20 ], +uint32_t *handle) +{ +uint16_t key_count; +uint32_t key_handles[10 ]; +uint8_t buf[288 ]; +uint8_t *ptr; +uint32_t err; +uint8_t digest[20 ]; +size_t buf_len; +unsigned int i; + +/* fetch list of already loaded keys in the TPM */ + err =tpm_get_capability (TPM_CAP_HANDLE ,TPM_RT_KEY , buf,sizeof (buf)); +if (err) +return -1 ; + key_count =get_unaligned_be16 (buf); + ptr = buf +2 ; +for (i =0 ; i < key_count; ++i, ptr +=4 ) + key_handles[i] =get_unaligned_be32 (ptr); + +/* now search a(/ the) key which we can access with the given auth */ +for (i =0 ; i < key_count; ++i) { + buf_len =sizeof (buf); + err =tpm_get_pub_key_oiap (key_handles[i], auth, buf, &buf_len); +if (err && err !=TPM_AUTHFAIL ) +return -1 ; +if (err) +continue ; +sha1_csum (buf, buf_len, digest); +if (!memcmp (digest, pubkey_digest,20 )) { + *handle = key_handles[i]; +return 0 ; + } + } +return 1 ; +} + +/** +* @brief read CCDM common data from TPM NV +* @return 0 if CCDM common data was found and read, !=0 if something failed. +*/ +static int read_common_data (void ) +{ +uint32_t size =0 ; +uint32_t err; +uint8_t buf[256 ]; +sha1_context ctx; + +if (get_tpm_nv_size (NV_COMMON_DATA_INDEX , &size) || + size <NV_COMMON_DATA_MIN_SIZE ) +return 1 ; + err =tpm_nv_read_value (NV_COMMON_DATA_INDEX , + buf,min (sizeof (buf), size)); +if (err) { +printf ("tpm_nv_read_value() failed: %u\n" , err); +return 1 ; + } + + device_id =get_unaligned_be64 (buf); + device_cl =get_unaligned_be64 (buf +8 ); + device_type =get_unaligned_be64 (buf +16 ); + +sha1_starts (&ctx); +sha1_update (&ctx, buf,24 ); +sha1_finish (&ctx, fix_hregs[FIX_HREG_DEVICE_ID_HASH ].digest); + fix_hregs[FIX_HREG_DEVICE_ID_HASH ].valid = true; + + platform_key_handle =get_unaligned_be32 (buf +24 ); + +return 0 ; +} + +/** +* @brief get pointer to hash register by specification +* @param spec specification of a hash register +* @return pointer to hash register or NULL if @a spec does not qualify a +* valid hash register; NULL else. +*/ +static struct h_reg *get_hreg (uint8_t spec) +{ +uint8_t idx; + + idx =HREG_IDX (spec); +if (IS_FIX_HREG (spec)) { +if (idx <ARRAY_SIZE (fix_hregs)) +return fix_hregs + idx; + hre_err =HRE_E_INVALID_HREG ; + }else if (IS_PCR_HREG (spec)) { +if (idx <ARRAY_SIZE (pcr_hregs)) +return pcr_hregs + idx; + hre_err =HRE_E_INVALID_HREG ; + }else if (IS_VAR_HREG (spec)) { +if (idx <ARRAY_SIZE (var_hregs)) +return var_hregs + idx; + hre_err =HRE_E_INVALID_HREG ; + } +return NULL ; +} + +/** +* @brief get pointer of a hash register by specification and usage. +* @param spec specification of a hash register +* @param mode access mode (read or write or read/write) +* @return pointer to hash register if found and valid; NULL else. +* +* This func uses @a get_reg() to determine the hash register for a given spec. +* If a register is found it is validated according to the desired access mode. +* The value of automatic registers (PCR register and fixed registers) is +* loaded or computed on read access. +*/ +static struct h_reg *access_hreg (uint8_t spec,enum access_mode mode) +{ +struct h_reg *result; + + result =get_hreg (spec); +if (!result) +return NULL ; + +if (mode &HREG_WR ) { +if (IS_FIX_HREG (spec)) { + hre_err =HRE_E_INVALID_HREG ; +return NULL ; + } + } +if (mode &HREG_RD ) { +if (!result->valid) { +if (IS_PCR_HREG (spec)) { + hre_tpm_err =tpm_pcr_read (HREG_IDX (spec), + result->digest,20 ); + result->valid = (hre_tpm_err ==TPM_SUCCESS ); + }else if (IS_FIX_HREG (spec)) { +switch (HREG_IDX (spec)) { +case FIX_HREG_DEVICE_ID_HASH : +read_common_data (); +break ; +case FIX_HREG_VENDOR : +memcpy (result->digest, vendor,20 ); + result->valid = true; +break ; + } + }else { + result->valid = true; + } + } +if (!result->valid) { + hre_err =HRE_E_INVALID_HREG ; +return NULL ; + } + } + +return result; +} + +static void *compute_and (void *_dst,const void *_src,size_t n) +{ +uint8_t *dst = _dst; +const uint8_t *src = _src; +size_t i; + +for (i = n; i-- >0 ; ) + *dst++ &= *src++; + +return _dst; +} + +static void *compute_or (void *_dst,const void *_src,size_t n) +{ +uint8_t *dst = _dst; +const uint8_t *src = _src; +size_t i; + +for (i = n; i-- >0 ; ) + *dst++ |= *src++; + +return _dst; +} + +static void *compute_xor (void *_dst,const void *_src,size_t n) +{ +uint8_t *dst = _dst; +const uint8_t *src = _src; +size_t i; + +for (i = n; i-- >0 ; ) + *dst++ ^= *src++; + +return _dst; +} + +static void *compute_extend (void *_dst,const void *_src,size_t n) +{ +uint8_t digest[20 ]; +sha1_context ctx; + +sha1_starts (&ctx); +sha1_update (&ctx, _dst, n); +sha1_update (&ctx, _src, n); +sha1_finish (&ctx, digest); +memcpy (_dst, digest,min (n,sizeof (digest))); + +return _dst; +} + +static int hre_op_loadkey (struct h_reg *src_reg,struct h_reg *dst_reg, +const void *key,size_t key_size) +{ +uint32_t parent_handle; +uint32_t key_handle; + +if (!src_reg || !dst_reg || !src_reg->valid || !dst_reg->valid) +return -1 ; +if (find_key (src_reg->digest, dst_reg->digest, &parent_handle)) +return -1 ; + hre_tpm_err = tpm_load_key2_oiap(parent_handle, key, key_size,
Quoted 9 lines
board/gdsys/38x/hre.c line 357
Quoted 6 lines
board/gdsys/38x/hre.c new file +6
-0+ src_reg->digest, &key_handle); +if (hre_tpm_err) { + hre_err =HRE_E_TPM_FAILURE ; +return -1 ; + } +/* TODO remember key handle somehow? */ Is this comment still valid?
Yes, it is, but it's highly unlikely that it will be addressed. Saving the key handle here would make things easier, but there's no elegant way to do it properly. Besides, the HRE code will most likely be removed from the board files once we use our new method for securely loading TPM keys in the ControlCenter-Compact board.
Hence, I'd say that I'll just remove the TODO in v2.
Quoted 739 lines
Quoted 739 lines
board/gdsys/38x/hre.c new file +160
-0+ +return 0 ; +} + +/** +* @brief executes the next opcode on the hash register engine. +* @param[in,out] ip pointer to the opcode (instruction pointer) +* @param[in,out] code_size (remaining) size of the code +* @return new instruction pointer on success, NULL on error. +*/ +static const uint8_t *hre_execute_op (const uint8_t **ip,size_t *code_size) +{ +bool dst_modified = false; +uint32_t ins; +uint8_t opcode; +uint8_t src_spec; +uint8_t dst_spec; +uint16_t data_size; +struct h_reg *src_reg, *dst_reg; +uint8_t buf[20 ]; +const uint8_t *src_buf, *data; +uint8_t *ptr; +int i; +void * (*bin_func)(void *,const void *,size_t ); + +if (*code_size <4 ) +return NULL ; + + ins =get_unaligned_be32 (*ip); + opcode = **ip; + data = *ip +4 ; + src_spec = (ins >>18 ) &0x3f ; + dst_spec = (ins >>12 ) &0x3f ; + data_size = (ins &0x7ff ); + +debug ("HRE: ins=%08x (op=%02x, s=%02x, d=%02x, L=%d)\n" , ins, + opcode, src_spec, dst_spec, data_size); + +if ((opcode &0x80 ) && (data_size +4 ) > *code_size) +return NULL ; + + src_reg =access_hreg (src_spec,HREG_RD ); +if (hre_err || hre_tpm_err) +return NULL ; + dst_reg =access_hreg (dst_spec, (opcode &0x40 ) ?HREG_RDWR :HREG_WR ); +if (hre_err || hre_tpm_err) +return NULL ; + +switch (opcode) { +case HRE_NOP : + goto end; +case HRE_CHECK0 : +if (src_reg) { +for (i =0 ; i <20 ; ++i) { +if (src_reg->digest[i]) +return NULL ; + } + } +break ; +case HRE_LOAD : + bin_func = memcpy; + goto do_bin_func; +case HRE_XOR : + bin_func = compute_xor; + goto do_bin_func; +case HRE_AND : + bin_func = compute_and; + goto do_bin_func; +case HRE_OR : + bin_func = compute_or; + goto do_bin_func; +case HRE_EXTEND : + bin_func = compute_extend; +do_bin_func: +if (!dst_reg) +return NULL ; +if (src_reg) { + src_buf = src_reg->digest; + }else { +if (!data_size) { +memset (buf,0 ,20 ); + src_buf = buf; + }else if (data_size ==1 ) { +memset (buf, *data,20 ); + src_buf = buf; + }else if (data_size >=20 ) { + src_buf = data; + }else { + src_buf = buf; +for (ptr = (uint8_t *)src_buf, i =20 ; i >0 ; + i -= data_size, ptr += data_size) +memcpy (ptr, data, +min_t (size_t, i, data_size)); + } + } +bin_func (dst_reg->digest, src_buf,20 ); + dst_reg->valid = true; + dst_modified = true; +break ; +case HRE_LOADKEY : +if (hre_op_loadkey (src_reg, dst_reg, data, data_size)) +return NULL ; +break ; +default : +return NULL ; + } + +if (dst_reg && dst_modified &&IS_PCR_HREG (dst_spec)) { + hre_tpm_err =tpm_extend (HREG_IDX (dst_spec), dst_reg->digest, + dst_reg->digest); +if (hre_tpm_err) { + hre_err =HRE_E_TPM_FAILURE ; +return NULL ; + } + } +end: + *ip +=4 ; + *code_size -=4 ; +if (opcode &0x80 ) { + *ip += data_size; + *code_size -= data_size; + } + +return *ip; +} + +/** +* @brief runs a program on the hash register engine. +* @param code pointer to the (HRE) code. +* @param code_size size of the code (in bytes). +* @return 0 on success, != 0 on failure. +*/ +int hre_run_program (const uint8_t *code,size_t code_size) +{ +size_t code_left; +const uint8_t *ip = code; + + code_left = code_size; + hre_tpm_err =0 ; + hre_err =HRE_E_OK ; +while (code_left >0 ) +if (!hre_execute_op (&ip, &code_left)) +return -1 ; + +return hre_err; +} + +int hre_verify_program (struct key_program *prg) +{ +uint32_t crc; + + crc =crc32 (0 , prg->code, prg->code_size); + +if (crc != prg->code_crc) { +printf ("HRC crc mismatch: %08x != %08x\n" , + crc, prg->code_crc); +return 1 ; + } +return 0 ; +}board/gdsys/38x/hre.h new file +38
-0@@ -0,0 +1,38 @@ +/* +* (C) Copyright 2013 +* Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __HRE_H +#define __HRE_H + +struct key_program { +uint32_t magic; +uint32_t code_crc; +uint32_t code_size; +uint8_t code[]; +}; + +struct h_reg { +bool valid; +uint8_t digest[20 ]; +}; + +/* CCDM specific contants */ +enum { +/* NV indices */ +NV_COMMON_DATA_INDEX =0x40000001 , +/* magics for key blob chains */ +MAGIC_KEY_PROGRAM =0x68726500 , +MAGIC_HMAC =0x68616300 , +MAGIC_END_OF_CHAIN =0x00000000 , +/* sizes */ +NV_COMMON_DATA_MIN_SIZE =3 *sizeof (uint64_t ) +2 *sizeof (uint16_t ), +}; + +int hre_verify_program (struct key_program *prg); +int hre_run_program (const uint8_t *code,size_t code_size); + +#endif /* __HRE_H */ board/gdsys/38x/keyprogram.c new file +158
-0@@ -0,0 +1,158 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <tpm.h> +#include <malloc.h> +#include <linux/ctype.h> +#include <asm/unaligned.h> + +#include "hre.h" + +int flush_keys (void ) +{ +u16 key_count; +u8 buf[288 ]; +u8 *ptr; +u32 err; +uint i; + +/* fetch list of already loaded keys in the TPM */ + err =tpm_get_capability (TPM_CAP_HANDLE ,TPM_RT_KEY , buf,sizeof (buf)); +if (err) +return -1 ; + key_count =get_unaligned_be16 (buf); + ptr = buf +2 ; +for (i =0 ; i < key_count; ++i, ptr +=4 ) { + err =tpm_flush_specific (get_unaligned_be32 (ptr),TPM_RT_KEY ); +if (err && err !=TPM_KEY_OWNER_CONTROL ) +return err; + } + +return 0 ; +} + +int decode_hexstr (char *hexstr,u8 **result) +{ +int len =strlen (hexstr); +int bytes = len /2 ; +int i; +u8 acc =0 ; + +if (len %2 ==1 ) +return 1 ; + + *result = (u8 *)malloc (bytes); + +for (i =0 ; i < len; i++) { +char cur =tolower (hexstr[i]); +u8 val; + +if ((cur >='a' && cur <='f' ) || (cur >='0' && cur <='9' )) { + val = cur - (cur >'9' ?87 :48 ); + +if (i %2 ==0 ) + acc =16 * val; +else + (*result)[i /2 ] = acc + val; + }else { +free (*result); +return 1 ; + } + } + +return 0 ; +} + +int extract_subprogram (u8 **progdata,u32 expected_magic, +struct key_program **result) +{ +struct key_program *prog = *result; +u32 magic, code_crc, code_size; + + magic =get_unaligned_be32 (*progdata); + code_crc =get_unaligned_be32 (*progdata +4 ); + code_size =get_unaligned_be32 (*progdata +8 ); + + *progdata +=12 ; + +if (magic != expected_magic) +return -1 ; + + *result =malloc (sizeof (struct key_program ) + code_size); + +if (!*result) +return -1 ; + + prog->magic = magic; + prog->code_crc = code_crc; + prog->code_size = code_size; +memcpy (prog->code, *progdata, code_size); + + *progdata += code_size; + +if (hre_verify_program (prog)) { +free (prog); +return -1 ; + } + +return 0 ; +} + +struct key_program *parse_and_check_keyprog (u8 *progdata) +{ +struct key_program *result =NULL , *hmac =NULL ; + +/* Part 1: Load key program */ + +if (extract_subprogram (&progdata,MAGIC_KEY_PROGRAM , &result)) +return NULL ; + +/* Part 2: Load hmac program */ + +if (extract_subprogram (&progdata,MAGIC_HMAC , &hmac)) +return NULL ; + +free (hmac); + +return result; +} + +int load_and_run_keyprog (void ) +{ +char *cmd =NULL ; +u8 *binprog =NULL ; +char *hexprog; +struct key_program *prog; + + cmd =getenv ("loadkeyprogram" ); + +if (!cmd ||run_command (cmd,0 )) +return 1 ; + + hexprog =getenv ("keyprogram" ); + +if (decode_hexstr (hexprog, &binprog)) +return 1 ; + + prog =parse_and_check_keyprog (binprog); +free (binprog); + +if (!prog) +return 1 ; + +if (hre_run_program (prog->code, prog->code_size)) { +free (prog); +return 1 ; + } + +printf ("\nSD code ran successfully\n" ); + +free (prog); + +return 0 ; +}board/gdsys/38x/keyprogram.h new file +14
-0@@ -0,0 +1,14 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __KEYPROGRAM_H +#define __KEYPROGRAM_H + +int load_and_run_keyprog (void ); +int flush_keys (void ); + +#endif /* __KEYPROGRAM_H */ board/gdsys/38x/kwbimage.cfg.in new file +12
-0@@ -0,0 +1,12 @@ +# +# Copyright (C) 2014 Stefan Roese <[email protected]> +# + +# Armada 38x uses version 1 image format +VERSION 1 + +# Boot Media configurations +#@BOOT_FROM + +# Binary Header (bin_hdr) with DDR3 training code +BINARY spl/u-boot-spl.bin 0000005b 00000068board/gdsys/38x/spl.c new file +21
-0@@ -0,0 +1,21 @@ +/* +* (C) Copyright 2016 +* Mario Six, Guntermann & Drunck GmbH, mario.six at gdsys.cc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <config.h> +#include <asm/arch/cpu.h> + +void spl_board_init (void ) +{ +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SPI_NOR_FLASH +u32 *bootrom_save = (u32 *)CONFIG_SPL_BOOTROM_SAVE ; +u32 *regs = (u32 *)(*bootrom_save); + +printf ("Returning to BootROM (return address %08x)...\n" , regs[13 ]); +return_to_bootrom (); +#endif +}configs/controlcenterdc_defconfig new file +54
-0@@ -0,0 +1,54 @@ +CONFIG_ARM=y +CONFIG_ARCH_MVEBU=y +CONFIG_SPL_GPIO_SUPPORT=y +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_TARGET_CONTROLCENTERDC=y +CONFIG_SPL_SPI_FLASH_SUPPORT=y +CONFIG_SPL_SPI_SUPPORT=y +CONFIG_DEFAULT_DEVICE_TREE="controlcenterdc" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_SPL=y +CONFIG_SPL_SYS_MALLOC_SIMPLE=y +CONFIG_HUSH_PARSER=y +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_GO is not set +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_GPIO=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TPM=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_OF_BOARD_FIXUP=y +CONFIG_SPL_OF_TRANSLATE=y +CONFIG_DM_GPIO=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_DEBUG_UART=y +CONFIG_DEBUG_UART_BASE=0xd0012000 +CONFIG_DEBUG_UART_CLOCK=250000000 +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SYS_NS16550=y +CONFIG_TPM_ATMEL_TWI=y +CONFIG_TPM_AUTH_SESSIONS=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_TPM=y +# CONFIG_EFI_LOADER is not setinclude/configs/controlcenterdc.h new file +240
-0@@ -0,0 +1,244 @@ +/* +* Copyright (C) 2014 Stefan Roese <[email protected]> +* Copyright (C) 2016 Mario Six <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _CONFIG_CONTROLCENTERDC_H +#define _CONFIG_CONTROLCENTERDC_H + +/* +* High Level Configuration Options (easy to change) +*/ +#define CONFIG_CUSTOMER_BOARD_SUPPORT + +#define CONFIG_SKIP_LOWLEVEL_INIT /* disable board lowlevel_init */ +#define CONFIG_DISPLAY_BOARDINFO_LATE +#define CONFIG_BOARD_LATE_INIT +#define CONFIG_LAST_STAGE_INIT +#define CONFIG_SPL_BOARD_INIT + +/* +* TEXT_BASE needs to be below 16MiB, since this area is scrubbed +* for DDR ECC byte filling in the SPL before loading the main +* U-Boot into it. +*/ +#define CONFIG_SYS_TEXT_BASE 0x00800000 + +#define CONFIG_SYS_TCLK 250000000/* 250MHz */ + +#define CONFIG_LOADADDR 1000000 + +#define CONFIG_SYS_NO_FLASH /* Declare no flash (NOR/SPI) */ + +/* +* Commands configuration +*/ +#define CONFIG_CMD_ENV +#define CONFIG_CMD_I2C +#define CONFIG_CMD_PCI +#define CONFIG_CMD_SCSI +#define CONFIG_CMD_SPI + +/* SPI NOR flash default params, used by sf commands */ +#define CONFIG_SF_DEFAULT_BUS 1 +#define CONFIG_SF_DEFAULT_SPEED 1000000 +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 + +/* +* SDIO/MMC Card Configuration +*/ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_SDHCI +#define CONFIG_MV_SDHCI +#define CONFIG_SYS_MMC_BASE MVEBU_SDIO_BASE + +/* +* SATA/SCSI/AHCI configuration +*/ +#define CONFIG_LIBATA +#define CONFIG_SCSI +#define CONFIG_SCSI_AHCI +#define CONFIG_SCSI_AHCI_PLAT +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 +#define CONFIG_SYS_SCSI_MAX_LUN 1 +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) + +/* Partition support */ +#define CONFIG_DOS_PARTITION +#define CONFIG_EFI_PARTITION + +/* Additional FS support/configuration */ +#define CONFIG_SUPPORT_VFAT + +/* USB/EHCI configuration */ +#define CONFIG_EHCI_IS_TDI + +/* Environment in SPI NOR flash */ +#define CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_SPI_BUS 1 +#define CONFIG_ENV_OFFSET (1 << 20)/* 1MiB in */ +#define CONFIG_ENV_SIZE (64 << 10)/* 64KiB */ +#define CONFIG_ENV_SECT_SIZE (256 << 10)/* 256KiB sectors */ + +#define CONFIG_PHY_MARVELL /* there is a marvell phy */ +#define PHY_ANEG_TIMEOUT 8000/* PHY needs a longer aneg time */ + +/* PCIe support */ +#ifndef CONFIG_SPL_BUILD +#define CONFIG_PCI +#define CONFIG_PCI_MVEBU +#define CONFIG_PCI_PNP +#define CONFIG_PCI_SCAN_SHOW +#endif + +#define CONFIG_SYS_ALT_MEMTEST + +/* +* Software (bit-bang) MII driver configuration +*/ +#define CONFIG_BITBANGMII /* bit-bang MII PHY management */ +#define CONFIG_BITBANGMII_MULTI + +/* +* GPIO +*/ +#define CONFIG_KIRKWOOD_GPIO + +/* SPL */ +/* +* Select the boot device here +* +* Currently supported are: +* SPL_BOOT_SPI_NOR_FLASH - Booting via SPI NOR flash +* SPL_BOOT_SDIO_MMC_CARD - Booting via SDIO/MMC card (partition 1) +*/ +#define SPL_BOOT_SPI_NOR_FLASH 1 +#define SPL_BOOT_SDIO_MMC_CARD 2 +#define CONFIG_SPL_BOOT_DEVICE SPL_BOOT_SPI_NOR_FLASH + +/* Defines for SPL */ +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_SIZE (160 << 10) + +#if defined(CONFIG_SECURED_MODE_IMAGE ) +#define CONFIG_SPL_TEXT_BASE 0x40002614 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x2614) +#else +#define CONFIG_SPL_TEXT_BASE 0x40000030 +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x30) +#endif + +#define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) +#define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MALLOC_SIMPLE +#endif + +#define CONFIG_SPL_STACK (0x40000000 + ((212 - 16) << 10)) +#define CONFIG_SPL_BOOTROM_SAVE (CONFIG_SPL_STACK + 4) + +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT + +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SPI_NOR_FLASH +/* SPL related SPI defines */ +#define CONFIG_SPL_SPI_LOAD +#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x30000 +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_SPI_U_BOOT_OFFS +#endif + +#if CONFIG_SPL_BOOT_DEVICE ==SPL_BOOT_SDIO_MMC_CARD +/* SPL related MMC defines */ +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION 1 +#define CONFIG_SYS_MMC_U_BOOT_OFFS (168 << 10) +#define CONFIG_SYS_U_BOOT_OFFS CONFIG_SYS_MMC_U_BOOT_OFFS +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR (CONFIG_SYS_U_BOOT_OFFS / 512) +#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS ((512 << 10) / 512)/* 512KiB */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER 0x00180000/* in SDRAM */ +#endif +#endif + +/* +* Environment Configuration +*/ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_BAUDRATE 115200 + +#define CONFIG_HOSTNAME ccdc +#define CONFIG_ROOTPATH "/opt/nfsroot" +#define CONFIG_BOOTFILE "ccdc.img" + +#define CONFIG_PREBOOT /* enable preboot variable */ + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth1\0" \ + "consoledev=ttyS1\0" \ + "u-boot=u-boot.bin\0" \ + "bootfile_addr=1000000\0" \ + "keyprogram_addr=3000000\0" \ + "keyprogram_file=keyprogram.img\0" \ + "fdtfile=controlcenterdc.dtb\0" \ + "load=tftpboot ${loadaddr} ${u-boot}\0" \ + "mmcdev=0:2\0" \ + "update=sf probe 1:0;" \ + " sf erase 0 +${filesize};" \ + " sf write ${fileaddr} 0 ${filesize}\0" \ + "upd=run load update\0" \ + "fdt_high=0x10000000\0" \ + "initrd_high=0x10000000\0" \ + "loadkeyprogram=tpm flush_keys;" \ + " mmc rescan;" \ + " ext4load mmc ${mmcdev} ${keyprogram_addr} ${keyprogram_file};"\ + " source ${keyprogram_addr}:script at 1\0" \ + "gpio1=gpio at 22_25\0" \ + "gpio2=A29\0" \ + "blinkseq='0 0 0 0 2 0 2 2 3 1 3 1 0 0 2 2 3 1 3 3 2 0 2 2 3 1 1 1 " \ + "2 0 2 2 3 1 3 1 0 0 2 0 3 3 3 1 2 0 0 0 3 1 1 1 0 0 0 0'\0" \ + "bootfail=for i in ${blinkseq}; do" \ + " if test $i -eq 0; then" \ + " gpio clear ${gpio1}; gpio set ${gpio2};" \ + " elif test $i -eq 1; then" \ + " gpio clear ${gpio1}; gpio clear ${gpio2};" \ + " elif test $i -eq 2; then" \ + " gpio set ${gpio1}; gpio set ${gpio2};" \ + " else;" \ + " gpio clear ${gpio1}; gpio set ${gpio2};" \ + " fi; sleep 0.12; done\0" + +#define CONFIG_NFSBOOTCOMMAND \ + "setenv bootargs root=/dev/nfs rw " \ + "nfsroot=${serverip}:${rootpath} " \ + "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off " \ + "console=${consoledev},${baudrate} ${othbootargs}; " \ + "tftpboot ${bootfile_addr} ${bootfile}; " \ + "bootm ${bootfile_addr}" + +#define CONFIG_MMCBOOTCOMMAND \ + "setenv bootargs root=/dev/mmcblk0p3 rw rootwait " \ + "console=${consoledev},${baudrate} ${othbootargs}; " \ + "ext2load mmc 0:2 ${bootfile_addr} ${bootfile}; " \ + "bootm ${bootfile_addr}" + +#define CONFIG_BOOTCOMMAND \ + "if env exists keyprogram; then;" \ + " setenv keyprogram; run nfsboot;" \ + " fi;" \ + " run dobootfail" + +/* +* mv-common.h should be defined after CMD configs since it used them +* to enable certain macros
Quoted 8 lines
include/configs/controlcenterdc.h line 244
Quoted 5 lines
include/configs/controlcenterdc.h new file +4
-0+*/ +#include "mv-common.h" + +#endif /* _CONFIG_CONTROLCENTERDC_H */ Thanks,
Stefan
Thanks for the review!
Best regards,
Mario
PATCH 17/17 controlcenterdc: Make secure boot available
In reply to Mario SixMake secure booting available for the controlcenterdc board (disabled by default).
--- board/gdsys/38x/Kconfig | 9 +++++++++ board/gdsys/38x/Makefile | 15 +++++++++++++++ board/gdsys/38x/kwbimage.cfg.in | 28 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+)
board/gdsys/38x/Kconfig +9 -0
@@ -39,4 +39,13 @@ config SYS_BOOTIMAGE_DEST_ADDR endmenu +config SECURED_MODE_IMAGE + bool "build image for secured mode" + default false + +config SECURED_MODE_CSK_INDEX + int "index of active CSK" + default 0 + depends on SECURED_MODE_IMAGE + endif
board/gdsys/38x/Makefile +15 -0
@@ -20,6 +20,21 @@ endif ifneq ($(CONFIG_SPL_BOOT_DEVICE_MMC),) KWB_CFG_BOOT_FROM=sdio endif + +ifneq ($(CONFIG_SECURED_MODE_IMAGE),) +KWB_REPLACE += CSK_INDEX +KWB_CFG_CSK_INDEX = $(CONFIG_SECURED_MODE_CSK_INDEX) + +KWB_REPLACE += SEC_BOOT_DEV +KWB_CFG_SEC_BOOT_DEV=$(patsubst "%",%, \ + $(if $(findstring BOOT_SPI_NOR_FLASH,$(CONFIG_SPL_BOOT_DEVICE)),0x34) \ + $(if $(findstring BOOT_SDIO_MMC_CARD,$(CONFIG_SPL_BOOT_DEVICE)),0x31) \ + ) + +KWB_REPLACE += SEC_FUSE_DUMP +KWB_CFG_SEC_FUSE_DUMP = a38x +endif + endif $(src)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
board/gdsys/38x/kwbimage.cfg.in +28 -0
@@ -1,5 +1,6 @@ # # Copyright (C) 2014 Stefan Roese <[email protected]> +# Copyright (C) 2015-2016 Reinhard Pfau <[email protected]> # # Armada 38x uses version 1 image format
@@ -10,3 +11,30 @@ VERSION 1 # Binary Header (bin_hdr) with DDR3 training code BINARY spl/u-boot-spl.bin 0000005b 00000068 + +# Name of KAK +KAK kwb_kak + +# Name of (active) CSK +CSK kwb_csk + +# BoxID +BOX_ID 0x1 + +# FlashID +FLASH_ID 0x1 + +# JTAG delay +JTAG_DELAY 5 + +# active CSK index +#@CSK_INDEX + +# whether to encode box ID and flash ID into image +#SEC_SPECIALIZED_IMG + +# secured mode boot device +#@SEC_BOOT_DEV + +# secured mode: dump fuse commands +#@SEC_FUSE_DUMP
Signature · 1 line
2.9.0