* [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II @ 2018-07-20 1:03 Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 01/12] ARM: nxp-imx8mq-evk: Update DDR initialization code Andrey Smirnov ` (12 more replies) 0 siblings, 13 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Everyone: This is part II of i.MX8MQ EVK board support patches. This time this is bits and pieces that were necessary in order to allow booting vendor Linux kernel availible here (tag: rel_imx_4.9.51_8mq_ga): https://source.codeaurora.org/external/imx/linux-imx Sources for ATF were taken from here (tag: rel_imx_4.9.51_8mq_ga): https://source.codeaurora.org/external/imx/imx-atf This patchest is also availible at: https://github.com/ndreys/barebox/tree/imx8m-support-part-II-v2 Feedback is welcome! Changes since [v1]: - Opcode patching is replaced with placing barebox image at the right spot - ATF loading code is converted into a function (was a macro originally) - It is now up to the user to check current EL when calling imx8mq_atf_load_bl31() - Other various small change as per Sascha's feedback [v1] http://lists.infradead.org/pipermail/barebox/2018-June/033922.html Thanks, Andrey Smirnov Andrey Smirnov (12): ARM: nxp-imx8mq-evk: Update DDR initialization code ARM: Add code to support SMCCC on AArch64 ARM: i.MX8MQ: Configure cntfrq only in EL3 ARM: i.MX8MQ: Add code to load BL31 ATF blob ARM: i.MX: fimware: Add pre-built BL31 ATF blob ARM: i.MX: Move i.MX header definitions to mach-imx ARM: i.MX: xload-esdhc: Make use of <mach/imx-header.h> ARM: i.MX: xload-esdhc: Allow placing image to align its etnry point ARM: nxp-imx8mq-evk: Add code to load ATF BL31 blob ARM: i.MX8MQ: Query and display ATF fimware hash if availible ARM: nxp-imx8mq-evk: Add bootflow comments firmware: Fix copy-paste comment mistake arch/arm/Kconfig | 4 + arch/arm/boards/nxp-imx8mq-evk/ddr_init.c | 120 +++++----- arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c | 219 +++++------------- arch/arm/boards/nxp-imx8mq-evk/lowlevel.c | 50 +++- arch/arm/cpu/Makefile | 4 +- arch/arm/cpu/smccc-call_64.S | 52 +++++ arch/arm/include/asm/asm-offsets.h | 1 + arch/arm/lib/asm-offsets.c | 7 +- arch/arm/mach-imx/Kconfig | 2 + arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/atf.c | 41 ++++ arch/arm/mach-imx/imx8mq.c | 29 ++- arch/arm/mach-imx/include/mach/atf.h | 13 ++ arch/arm/mach-imx/include/mach/imx-header.h | 128 ++++++++++ arch/arm/mach-imx/xload-esdhc.c | 51 +++- firmware/Kconfig | 3 + firmware/Makefile | 6 +- firmware/imx/imx8m-bl31.bin | Bin 0 -> 46744 bytes include/linux/arm-smccc.h | 135 +++++++++++ scripts/imx/imx.h | 114 +-------- 20 files changed, 631 insertions(+), 350 deletions(-) create mode 100644 arch/arm/cpu/smccc-call_64.S create mode 100644 arch/arm/include/asm/asm-offsets.h create mode 100644 arch/arm/mach-imx/atf.c create mode 100644 arch/arm/mach-imx/include/mach/atf.h create mode 100644 arch/arm/mach-imx/include/mach/imx-header.h create mode 100755 firmware/imx/imx8m-bl31.bin create mode 100644 include/linux/arm-smccc.h -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 01/12] ARM: nxp-imx8mq-evk: Update DDR initialization code 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 02/12] ARM: Add code to support SMCCC on AArch64 Andrey Smirnov ` (11 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Previous version of DDR initialization code was generated by a beta version of MX8_DDR_tool. This updates the code to the output of MX8_DDR_tool v1.0, which seem to fix the vendor Linux kernel hang* that was happening with the previous version. * The kernel would hang as soon as it tried to utilize DDR's DVFS features and switch DDR frequency (disabling busfreq-imx8mq.c would fix the problem). Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/boards/nxp-imx8mq-evk/ddr_init.c | 120 +++++----- arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c | 219 +++++------------- 2 files changed, 125 insertions(+), 214 deletions(-) diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c b/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c index 81691b2fa..44103b5e2 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c +++ b/arch/arm/boards/nxp-imx8mq-evk/ddr_init.c @@ -2,7 +2,8 @@ * Copyright 2017 NXP * * SPDX-License-Identifier: GPL-2.0+ - * Generated code from MX8_DDR_tool + * + * Generated code from MX8M_DDR_tool */ #include "ddr.h" @@ -21,7 +22,7 @@ void ddr_init(void) reg32_write(0x303a00f8,tmp); reg32_write(0x30391000,0x8f000000); reg32_write(0x30391004,0x8f000000); - reg32_write(0x30360068,0xbbe580); + reg32_write(0x30360068,0xece580); tmp=reg32_read(0x30360060); tmp &= ~0x80; reg32_write(0x30360060,tmp); @@ -41,18 +42,19 @@ void ddr_init(void) reg32_write(0x30391000,0x8f000006); reg32_write(0x3d400304,0x1); reg32_write(0x3d400030,0x1); - reg32_write(0x3d400000,0x83080020); + reg32_write(0x3d400000,0xa3080020); + reg32_write(0x3d400028,0x0); + reg32_write(0x3d400020,0x203); + reg32_write(0x3d400024,0x186a000); reg32_write(0x3d400064,0x6100e0); reg32_write(0x3d4000d0,0xc003061c); reg32_write(0x3d4000d4,0x9e0000); reg32_write(0x3d4000dc,0xd4002d); reg32_write(0x3d4000e0,0x310008); - reg32_write(0x3d4000e8,0x46004d); - reg32_write(0x3d4000ec,0x15004d); - reg32_write(0x3d4000f4,0x639); + reg32_write(0x3d4000e8,0x66004a); + reg32_write(0x3d4000ec,0x16004a); reg32_write(0x3d400100,0x1a201b22); reg32_write(0x3d400104,0x60633); - reg32_write(0x3d400108,0x70e1214); reg32_write(0x3d40010c,0xc0c000); reg32_write(0x3d400110,0xf04080f); reg32_write(0x3d400114,0x2040c0c); @@ -64,78 +66,77 @@ void ddr_init(void) reg32_write(0x3d400144,0xa00050); reg32_write(0x3d400180,0x3200018); reg32_write(0x3d400184,0x28061a8); + reg32_write(0x3d400188,0x0); reg32_write(0x3d400190,0x497820a); reg32_write(0x3d400194,0x80303); - reg32_write(0x3d4001b4,0x170a); - reg32_write(0x3d4001b0,0x11); reg32_write(0x3d4001a0,0xe0400018); reg32_write(0x3d4001a4,0xdf00e4); - reg32_write(0x3d4001a8,0x0); + reg32_write(0x3d4001a8,0x80000000); + reg32_write(0x3d4001b0,0x11); + reg32_write(0x3d4001b4,0x170a); reg32_write(0x3d4001c0,0x1); reg32_write(0x3d4001c4,0x1); + reg32_write(0x3d4000f4,0x639); + reg32_write(0x3d400108,0x70e1214); reg32_write(0x3d400200,0x15); reg32_write(0x3d40020c,0x0); reg32_write(0x3d400210,0x1f1f); reg32_write(0x3d400204,0x80808); reg32_write(0x3d400214,0x7070707); reg32_write(0x3d400218,0x48080707); + reg32_write(0x3d402020,0x1); + reg32_write(0x3d402024,0x518b00); + reg32_write(0x3d402050,0x20d040); + reg32_write(0x3d402064,0x14002f); + reg32_write(0x3d4020dc,0x940009); + reg32_write(0x3d4020e0,0x310000); + reg32_write(0x3d4020e8,0x66004a); + reg32_write(0x3d4020ec,0x16004a); + reg32_write(0x3d402100,0xb070508); + reg32_write(0x3d402104,0x3040b); + reg32_write(0x3d402108,0x305090c); + reg32_write(0x3d40210c,0x505000); + reg32_write(0x3d402110,0x4040204); + reg32_write(0x3d402114,0x2030303); + reg32_write(0x3d402118,0x1010004); + reg32_write(0x3d40211c,0x301); + reg32_write(0x3d402130,0x20300); + reg32_write(0x3d402134,0xa100002); + reg32_write(0x3d402138,0x31); + reg32_write(0x3d402144,0x220011); + reg32_write(0x3d402180,0xa70006); + reg32_write(0x3d402190,0x3858202); + reg32_write(0x3d402194,0x80303); + reg32_write(0x3d4021b4,0x502); reg32_write(0x3d400244,0x0); - reg32_write(0x3d400490,0x1); - reg32_write(0x3d400250,0x29001f01); + reg32_write(0x3d400250,0x29001505); reg32_write(0x3d400254,0x2c); - reg32_write(0x3d400264,0x900093e7); + reg32_write(0x3d40025c,0x5900575b); + reg32_write(0x3d400264,0x9); reg32_write(0x3d40026c,0x2005574); - reg32_write(0x3d400400,0x400); + reg32_write(0x3d400300,0x16); + reg32_write(0x3d400304,0x0); + reg32_write(0x3d40030c,0x0); + reg32_write(0x3d400320,0x1); + reg32_write(0x3d40036c,0x11); + reg32_write(0x3d400400,0x111); + reg32_write(0x3d400404,0x10f3); reg32_write(0x3d400408,0x72ff); - reg32_write(0x3d400494,0x10e00); - reg32_write(0x3d400498,0x620096); - reg32_write(0x3d40049c,0x10e00); - reg32_write(0x3d4004a0,0x12c); + reg32_write(0x3d400490,0x1); + reg32_write(0x3d400494,0x1110d00); + reg32_write(0x3d400498,0x620790); + reg32_write(0x3d40049c,0x100001); + reg32_write(0x3d4004a0,0x41f); reg32_write(0x30391000,0x8f000004); reg32_write(0x30391000,0x8f000000); - reg32_write(0x3d400304,0x0); reg32_write(0x3d400030,0xa8); + do{ + tmp=reg32_read(0x3d400004); + if(tmp&0x223) break; + }while(1); reg32_write(0x3d400320,0x0); reg32_write(0x3d000000,0x1); reg32_write(0x3d4001b0,0x10); - reg32_write(0x3d402100,0xa040305); - reg32_write(0x3d402104,0x30407); - reg32_write(0x3d402108,0x203060b); - reg32_write(0x3d40210c,0x505000); - reg32_write(0x3d402110,0x2040202); - reg32_write(0x3d402114,0x2030202); - reg32_write(0x3d402118,0x1010004); - reg32_write(0x3d40211c,0x301); - reg32_write(0x3d402138,0x1d); - reg32_write(0x3d402144,0x14000a); - reg32_write(0x3d403024,0x30d400); - reg32_write(0x3d402050,0x20d040); - reg32_write(0x3d402190,0x3818200); - reg32_write(0x3d4021b4,0x100); - reg32_write(0x3d402064,0xc001c); - reg32_write(0x3d4020dc,0x840000); - reg32_write(0x3d4020e8,0x46004d); - reg32_write(0x3d4020ec,0x15004d); - reg32_write(0x3d4020e0,0x310000); - reg32_write(0x3d403100,0x6010102); - reg32_write(0x3d403104,0x30404); - reg32_write(0x3d403108,0x203060b); - reg32_write(0x3d40310c,0x505000); - reg32_write(0x3d403110,0x2040202); - reg32_write(0x3d403114,0x2030202); - reg32_write(0x3d403118,0x1010004); - reg32_write(0x3d40311c,0x301); - reg32_write(0x3d403138,0x8); - reg32_write(0x3d403144,0x50003); - reg32_write(0x3d403024,0xc3500); - reg32_write(0x3d403050,0x20d040); - reg32_write(0x3d403190,0x3818200); - reg32_write(0x3d4031b4,0x100); - reg32_write(0x3d403064,0x30007); - reg32_write(0x3d4030dc,0x840000); - reg32_write(0x3d4030e8,0x46004d); - reg32_write(0x3d4030ec,0x15004d); - reg32_write(0x3d4030e0,0x310000); reg32_write(0x3c040280,0x0); reg32_write(0x3c040284,0x1); reg32_write(0x3c040288,0x2); @@ -218,6 +219,7 @@ void ddr_init(void) /* enable port 0 */ reg32_write(DDRC_PCTRL_0(0), 0x00000001); - tmp = reg32_read(DDRC_CRCPARSTAT(0)); - reg32_write(DDRC_RFSHCTL3(0), 0x00000000); + /* enable DDR auto-refresh mode */ + tmp = reg32_read(DDRC_RFSHCTL3(0)) & ~0x1; + reg32_write(DDRC_RFSHCTL3(0), tmp); } \ No newline at end of file diff --git a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c index 156d7cf87..1b30ff725 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c +++ b/arch/arm/boards/nxp-imx8mq-evk/ddrphy_train.c @@ -2,6 +2,8 @@ * Copyright 2017 NXP * * SPDX-License-Identifier: GPL-2.0+ + * + * Generated code from MX8M_DDR_tool */ #include "ddr.h" @@ -32,14 +34,6 @@ void ddr_cfg_phy(void) { reg32_write(0x3c44857c,0x1ff); reg32_write(0x3c44c17c,0x1ff); reg32_write(0x3c44c57c,0x1ff); - reg32_write(0x3c84017c,0x1ff); - reg32_write(0x3c84057c,0x1ff); - reg32_write(0x3c84417c,0x1ff); - reg32_write(0x3c84457c,0x1ff); - reg32_write(0x3c84817c,0x1ff); - reg32_write(0x3c84857c,0x1ff); - reg32_write(0x3c84c17c,0x1ff); - reg32_write(0x3c84c57c,0x1ff); reg32_write(0x3c000154,0x1ff); reg32_write(0x3c004154,0x1ff); reg32_write(0x3c008154,0x1ff); @@ -52,22 +46,16 @@ void ddr_cfg_phy(void) { reg32_write(0x3c024154,0x1ff); reg32_write(0x3c080314,0x19); reg32_write(0x3c480314,0x7); - reg32_write(0x3c880314,0x7); reg32_write(0x3c0800b8,0x2); - reg32_write(0x3c4800b8,0x2); - reg32_write(0x3c8800b8,0x2); + reg32_write(0x3c4800b8,0x1); reg32_write(0x3c240810,0x0); reg32_write(0x3c640810,0x0); - reg32_write(0x3ca40810,0x0); reg32_write(0x3c080090,0xab); reg32_write(0x3c0800e8,0x0); reg32_write(0x3c480090,0xab); reg32_write(0x3c0800e8,0x0); - reg32_write(0x3c880090,0xab); - reg32_write(0x3c0800e8,0x0); - reg32_write(0x3c080158,0x7); + reg32_write(0x3c080158,0x3); reg32_write(0x3c480158,0xa); - reg32_write(0x3c880158,0xa); reg32_write(0x3c040134,0xe00); reg32_write(0x3c040534,0xe00); reg32_write(0x3c044134,0xe00); @@ -84,14 +72,6 @@ void ddr_cfg_phy(void) { reg32_write(0x3c448534,0xe00); reg32_write(0x3c44c134,0xe00); reg32_write(0x3c44c534,0xe00); - reg32_write(0x3c840134,0xe00); - reg32_write(0x3c840534,0xe00); - reg32_write(0x3c844134,0xe00); - reg32_write(0x3c844534,0xe00); - reg32_write(0x3c848134,0xe00); - reg32_write(0x3c848534,0xe00); - reg32_write(0x3c84c134,0xe00); - reg32_write(0x3c84c534,0xe00); reg32_write(0x3c040124,0xfbe); reg32_write(0x3c040524,0xfbe); reg32_write(0x3c044124,0xfbe); @@ -108,14 +88,6 @@ void ddr_cfg_phy(void) { reg32_write(0x3c448524,0xfbe); reg32_write(0x3c44c124,0xfbe); reg32_write(0x3c44c524,0xfbe); - reg32_write(0x3c840124,0xfbe); - reg32_write(0x3c840524,0xfbe); - reg32_write(0x3c844124,0xfbe); - reg32_write(0x3c844524,0xfbe); - reg32_write(0x3c848124,0xfbe); - reg32_write(0x3c848524,0xfbe); - reg32_write(0x3c84c124,0xfbe); - reg32_write(0x3c84c524,0xfbe); reg32_write(0x3c00010c,0x63); reg32_write(0x3c00410c,0x63); reg32_write(0x3c00810c,0x63); @@ -130,8 +102,7 @@ void ddr_cfg_phy(void) { reg32_write(0x3c0801d4,0x4); reg32_write(0x3c080140,0x0); reg32_write(0x3c080020,0x320); - reg32_write(0x3c480020,0x64); - reg32_write(0x3c880020,0x19); + reg32_write(0x3c480020,0xa7); reg32_write(0x3c080220,0x9); reg32_write(0x3c0802c8,0xdc); reg32_write(0x3c04010c,0x5a1); @@ -151,33 +122,21 @@ void ddr_cfg_phy(void) { reg32_write(0x3c44850c,0x5a1); reg32_write(0x3c44c10c,0x5a1); reg32_write(0x3c44c50c,0x5a1); - reg32_write(0x3c8802c8,0xdc); - reg32_write(0x3c84010c,0x5a1); - reg32_write(0x3c84050c,0x5a1); - reg32_write(0x3c84410c,0x5a1); - reg32_write(0x3c84450c,0x5a1); - reg32_write(0x3c84810c,0x5a1); - reg32_write(0x3c84850c,0x5a1); - reg32_write(0x3c84c10c,0x5a1); - reg32_write(0x3c84c50c,0x5a1); reg32_write(0x3c0803e8,0x1); reg32_write(0x3c4803e8,0x1); - reg32_write(0x3c8803e8,0x1); reg32_write(0x3c080064,0x1); reg32_write(0x3c480064,0x1); - reg32_write(0x3c880064,0x1); - reg32_write(0x3c0803c0,0x660); + reg32_write(0x3c0803c0,0x0); reg32_write(0x3c0803c4,0x0); reg32_write(0x3c0803c8,0x4444); reg32_write(0x3c0803cc,0x8888); - reg32_write(0x3c0803d0,0x5665); + reg32_write(0x3c0803d0,0x5555); reg32_write(0x3c0803d4,0x0); reg32_write(0x3c0803d8,0x0); reg32_write(0x3c0803dc,0xf000); reg32_write(0x3c080094,0x0); reg32_write(0x3c0800b4,0x0); reg32_write(0x3c4800b4,0x0); - reg32_write(0x3c8800b4,0x0); reg32_write(0x3c080180,0x2); //enable APB bus to access DDRPHY RAM @@ -195,31 +154,32 @@ void ddr_cfg_phy(void) { reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54008,0x131f); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54009,0xc8); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400b,0x2); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400d,0x100); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4d46); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4d08); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x15); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4a66); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4d46); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4d08); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x15); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4a66); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x4600); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1500); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x6600); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x4600); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1500); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x6600); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600); //disable APB bus to access DDRPHY RAM reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1); @@ -233,96 +193,57 @@ void ddr_cfg_phy(void) { reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1); //set the PHY input clock to the desired frequency for pstate 1 - reg32_write(0x3038a008,0x7070000); - reg32_write(0x3038a004,0x5000000); - reg32_write(0x3038a088,0x7070000); - reg32_write(0x3038a084,0x2010000); - reg32_write(0x303a00ec,0xffff); - tmp=reg32_read(0x303a00f8); - tmp |= 0x20; - reg32_write(0x303a00f8,tmp); - reg32_write(0x30389804,0x1000000); - - //enable APB bus to access DDRPHY RAM - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0); - - reg32_write(0x3c150008,0x101); - reg32_write(0x3c15000c,0x190); - reg32_write(0x3c150020,0x121f); - reg32_write(0x3c150064,0x84); - reg32_write(0x3c150068,0x31); - reg32_write(0x3c15006c,0x4d46); - reg32_write(0x3c150070,0x4d08); - reg32_write(0x3c150074,0x0); - reg32_write(0x3c150078,0x15); - reg32_write(0x3c15007c,0x84); - reg32_write(0x3c150080,0x31); - reg32_write(0x3c150084,0x4d46); - reg32_write(0x3c150088,0x4d08); - reg32_write(0x3c15008c,0x0); - reg32_write(0x3c150090,0x15); - reg32_write(0x3c1500c8,0x8400); - reg32_write(0x3c1500cc,0x3100); - reg32_write(0x3c1500d0,0x4600); - reg32_write(0x3c1500d4,0x84d); - reg32_write(0x3c1500d8,0x4d); - reg32_write(0x3c1500dc,0x1500); - reg32_write(0x3c1500e0,0x8400); - reg32_write(0x3c1500e4,0x3100); - reg32_write(0x3c1500e8,0x4600); - reg32_write(0x3c1500ec,0x84d); - reg32_write(0x3c1500f0,0x4d); - reg32_write(0x3c1500f4,0x1500); - reg32_write(0x3c1500f8,0x0); - - //disable APB bus to access DDRPHY RAM - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1); - //Reset MPU and run - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0); - wait_ddrphy_training_complete(); - - //configure DDRPHY-FW DMEM structure @clock2... - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1); - - //set the PHY input clock to the desired frequency for pstate 2 - reg32_write(0x3038a008,0x7070000); - reg32_write(0x3038a004,0x2000000); reg32_write(0x3038a088,0x7070000); - reg32_write(0x3038a084,0x2010000); + reg32_write(0x3038a084,0x4030000); reg32_write(0x303a00ec,0xffff); tmp=reg32_read(0x303a00f8); tmp |= 0x20; reg32_write(0x303a00f8,tmp); - reg32_write(0x30389804,0x1000000); + reg32_write(0x30360068,0xf5a406); + tmp=reg32_read(0x30360060); + tmp &= ~0x80; + reg32_write(0x30360060,tmp); + tmp=reg32_read(0x30360060); + tmp |= 0x200; + reg32_write(0x30360060,tmp); + tmp=reg32_read(0x30360060); + tmp &= ~0x20; + reg32_write(0x30360060,tmp); + tmp=reg32_read(0x30360060); + tmp &= ~0x10; + reg32_write(0x30360060,tmp); + do{ + tmp=reg32_read(0x30360060); + if(tmp&0x80000000) break; + }while(1); + reg32_write(0x30389808,0x1000000); //enable APB bus to access DDRPHY RAM reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0); - reg32_write(0x3c150008,0x102); - reg32_write(0x3c15000c,0x64); + reg32_write(0x3c150008,0x1); + reg32_write(0x3c15000c,0x29c); reg32_write(0x3c150020,0x121f); - reg32_write(0x3c150064,0x84); + reg32_write(0x3c150064,0x994); reg32_write(0x3c150068,0x31); reg32_write(0x3c15006c,0x4d46); reg32_write(0x3c150070,0x4d08); reg32_write(0x3c150074,0x0); reg32_write(0x3c150078,0x15); - reg32_write(0x3c15007c,0x84); + reg32_write(0x3c15007c,0x994); reg32_write(0x3c150080,0x31); reg32_write(0x3c150084,0x4d46); reg32_write(0x3c150088,0x4d08); reg32_write(0x3c15008c,0x0); reg32_write(0x3c150090,0x15); - reg32_write(0x3c1500c8,0x8400); - reg32_write(0x3c1500cc,0x3100); + reg32_write(0x3c1500c8,0x9400); + reg32_write(0x3c1500cc,0x3109); reg32_write(0x3c1500d0,0x4600); reg32_write(0x3c1500d4,0x84d); reg32_write(0x3c1500d8,0x4d); reg32_write(0x3c1500dc,0x1500); - reg32_write(0x3c1500e0,0x8400); - reg32_write(0x3c1500e4,0x3100); + reg32_write(0x3c1500e0,0x9400); + reg32_write(0x3c1500e4,0x3109); reg32_write(0x3c1500e8,0x4600); reg32_write(0x3c1500ec,0x84d); reg32_write(0x3c1500f0,0x4d); @@ -344,7 +265,7 @@ void ddr_cfg_phy(void) { tmp=reg32_read(0x303a00f8); tmp |= 0x20; reg32_write(0x303a00f8,tmp); - reg32_write(0x30360068,0xbbe580); + reg32_write(0x30360068,0xece580); tmp=reg32_read(0x30360060); tmp &= ~0x80; reg32_write(0x30360060,tmp); @@ -380,28 +301,28 @@ void ddr_cfg_phy(void) { reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4d46); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4d08); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x15); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4a66); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4d46); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4d08); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x15); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4a66); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x4600); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1500); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x6600); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400); reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x4600); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4d); - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1500); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x6600); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a); + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600); //disable APB bus to access DDRPHY RAM reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1); @@ -912,10 +833,6 @@ void ddr_cfg_phy(void) { reg32_write(0x3c480030,0xc9); reg32_write(0x3c480034,0x7d1); reg32_write(0x3c480038,0x2c); - reg32_write(0x3c88002c,0x65); - reg32_write(0x3c880030,0xc9); - reg32_write(0x3c880034,0x7d1); - reg32_write(0x3c880038,0x2c); reg32_write(0x3c240030,0x0); reg32_write(0x3c240034,0x173); reg32_write(0x3c240038,0x60); @@ -928,8 +845,6 @@ void ddr_cfg_phy(void) { reg32_write(0x3c080044,0x3); reg32_write(0x3c480040,0x5a); reg32_write(0x3c480044,0x3); - reg32_write(0x3c880040,0x5a); - reg32_write(0x3c880044,0x3); reg32_write(0x3c100200,0xe0); reg32_write(0x3c100204,0x12); reg32_write(0x3c100208,0xe0); @@ -942,12 +857,6 @@ void ddr_cfg_phy(void) { reg32_write(0x3c50020c,0x12); reg32_write(0x3c500210,0xe0); reg32_write(0x3c500214,0x12); - reg32_write(0x3c900200,0xe0); - reg32_write(0x3c900204,0x12); - reg32_write(0x3c900208,0xe0); - reg32_write(0x3c90020c,0x12); - reg32_write(0x3c900210,0xe0); - reg32_write(0x3c900214,0x12); reg32_write(0x3c1003f4,0xf); reg32_write(0x3c040044,0x1); reg32_write(0x3c040048,0x1); -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 02/12] ARM: Add code to support SMCCC on AArch64 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 01/12] ARM: nxp-imx8mq-evk: Update DDR initialization code Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 03/12] ARM: i.MX8MQ: Configure cntfrq only in EL3 Andrey Smirnov ` (10 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Port SMCCC code from Linux kernel. To accomodate that: - Introduce CONFIG_ARM_SMCCC, to allow enabling the code independent of CONFIG_ARM_SECURE_MONITOR - Bring <linux/arm-smccc.h> in - Add necessary constants to arch/arm/asm-offsets.c Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/Kconfig | 4 + arch/arm/cpu/Makefile | 4 +- arch/arm/cpu/smccc-call_64.S | 52 +++++++++++ arch/arm/include/asm/asm-offsets.h | 1 + arch/arm/lib/asm-offsets.c | 7 +- include/linux/arm-smccc.h | 135 +++++++++++++++++++++++++++++ 6 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 arch/arm/cpu/smccc-call_64.S create mode 100644 arch/arm/include/asm/asm-offsets.h create mode 100644 include/linux/arm-smccc.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3555b4ee5..00c893bd0 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -388,7 +388,11 @@ config ARM_SEMIHOSTING the data on the host computer connected to the target via debugging channel (JTAG, SWD). If unsure say N +config ARM_SMCCC + bool + config ARM_SECURE_MONITOR + select ARM_SMCCC bool config ARM_PSCI diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile index 5b4b832e8..874d723e2 100644 --- a/arch/arm/cpu/Makefile +++ b/arch/arm/cpu/Makefile @@ -21,8 +21,8 @@ obj-$(CONFIG_CPU_32v7) += no-mmu.o endif obj-$(CONFIG_ARM_PSCI) += psci.o -obj-$(CONFIG_ARM_SECURE_MONITOR) += smccc-call.o -AFLAGS_smccc-call.o :=-Wa,-march=armv7-a +obj-pbl-$(CONFIG_ARM_SMCCC) += smccc-call$(S64).o +AFLAGS_smccc-call$(S64).o :=-Wa,-march=armv$(if $(S64),8,7)-a obj-$(CONFIG_ARM_SECURE_MONITOR) += sm.o sm_as.o AFLAGS_sm_as.o :=-Wa,-march=armv7-a diff --git a/arch/arm/cpu/smccc-call_64.S b/arch/arm/cpu/smccc-call_64.S new file mode 100644 index 000000000..44888fb59 --- /dev/null +++ b/arch/arm/cpu/smccc-call_64.S @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/linkage.h> +#include <linux/arm-smccc.h> +#include <asm/asm-offsets.h> + + .macro SMCCC instr + .cfi_startproc + \instr #0 + ldr x4, [sp] + stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] + stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] + ldr x4, [sp, #8] + cbz x4, 1f /* no quirk structure */ + ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS] + cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6 + b.ne 1f + str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS] +1: ret + .cfi_endproc + .endm + +/* + * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, + * struct arm_smccc_quirk *quirk) + */ +ENTRY(__arm_smccc_smc) + SMCCC smc +ENDPROC(__arm_smccc_smc) + +/* + * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, + * struct arm_smccc_quirk *quirk) + */ +ENTRY(__arm_smccc_hvc) + SMCCC hvc +ENDPROC(__arm_smccc_hvc) \ No newline at end of file diff --git a/arch/arm/include/asm/asm-offsets.h b/arch/arm/include/asm/asm-offsets.h new file mode 100644 index 000000000..2f84e8399 --- /dev/null +++ b/arch/arm/include/asm/asm-offsets.h @@ -0,0 +1 @@ +#include <generated/asm-offsets.h> \ No newline at end of file diff --git a/arch/arm/lib/asm-offsets.c b/arch/arm/lib/asm-offsets.c index 7bf6d129c..cdff6f782 100644 --- a/arch/arm/lib/asm-offsets.c +++ b/arch/arm/lib/asm-offsets.c @@ -9,8 +9,13 @@ */ #include <linux/kbuild.h> +#include <linux/arm-smccc.h> int main(void) { - return 0; + DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); + DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); + DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); + DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); + return 0; } diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h new file mode 100644 index 000000000..1b38b7b37 --- /dev/null +++ b/include/linux/arm-smccc.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __LINUX_ARM_SMCCC_H +#define __LINUX_ARM_SMCCC_H + +/* + * This file provides common defines for ARM SMC Calling Convention as + * specified in + * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + */ + +/* This constant is shifted by 31, make sure it's of an unsigned type */ +#define ARM_SMCCC_STD_CALL 0UL +#define ARM_SMCCC_FAST_CALL 1UL +#define ARM_SMCCC_TYPE_SHIFT 31 + +#define ARM_SMCCC_SMC_32 0 +#define ARM_SMCCC_SMC_64 1 +#define ARM_SMCCC_CALL_CONV_SHIFT 30 + +#define ARM_SMCCC_OWNER_MASK 0x3F +#define ARM_SMCCC_OWNER_SHIFT 24 + +#define ARM_SMCCC_FUNC_MASK 0xFFFF + +#define ARM_SMCCC_IS_FAST_CALL(smc_val) \ + ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT)) +#define ARM_SMCCC_IS_64(smc_val) \ + ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT)) +#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK) +#define ARM_SMCCC_OWNER_NUM(smc_val) \ + (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK) + +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ + ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ + (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \ + ((func_num) & ARM_SMCCC_FUNC_MASK)) + +#define ARM_SMCCC_OWNER_ARCH 0 +#define ARM_SMCCC_OWNER_CPU 1 +#define ARM_SMCCC_OWNER_SIP 2 +#define ARM_SMCCC_OWNER_OEM 3 +#define ARM_SMCCC_OWNER_STANDARD 4 +#define ARM_SMCCC_OWNER_TRUSTED_APP 48 +#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 +#define ARM_SMCCC_OWNER_TRUSTED_OS 50 +#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63 + +#define ARM_SMCCC_QUIRK_NONE 0 +#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */ + +#ifndef __ASSEMBLY__ + +#include <linux/linkage.h> +#include <linux/types.h> +/** + * struct arm_smccc_res - Result from SMC/HVC call + * @a0-a3 result values from registers 0 to 3 + */ +struct arm_smccc_res { + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; +}; + +/** + * struct arm_smccc_quirk - Contains quirk information + * @id: quirk identification + * @state: quirk specific information + * @a6: Qualcomm quirk entry for returning post-smc call contents of a6 + */ +struct arm_smccc_quirk { + int id; + union { + unsigned long a6; + } state; +}; + +/** + * __arm_smccc_smc() - make SMC calls + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required. + * + * This function is used to make SMC calls following SMC Calling Convention. + * The content of the supplied param are copied to registers 0 to 7 prior + * to the SMC instruction. The return values are updated with the content + * from register 0 to 3 on return from the SMC instruction. An optional + * quirk structure provides vendor specific behavior. + */ +asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); + +/** + * __arm_smccc_hvc() - make HVC calls + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required. + * + * This function is used to make HVC calls following SMC Calling + * Convention. The content of the supplied param are copied to registers 0 + * to 7 prior to the HVC instruction. The return values are updated with + * the content from register 0 to 3 on return from the HVC instruction. An + * optional quirk structure provides vendor specific behavior. + */ +asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); + +#define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL) + +#define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__) + +#define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL) + +#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__) + +#endif /*__ASSEMBLY__*/ +#endif /*__LINUX_ARM_SMCCC_H*/ -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 03/12] ARM: i.MX8MQ: Configure cntfrq only in EL3 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 01/12] ARM: nxp-imx8mq-evk: Update DDR initialization code Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 02/12] ARM: Add code to support SMCCC on AArch64 Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 04/12] ARM: i.MX8MQ: Add code to load BL31 ATF blob Andrey Smirnov ` (9 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov We only can (and should only need to) configure cntfrq when running in EL3 and executing this code in any other exception level will result in exception. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/mach-imx/imx8mq.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-imx/imx8mq.c b/arch/arm/mach-imx/imx8mq.c index f3246e437..dbcf4fa59 100644 --- a/arch/arm/mach-imx/imx8mq.c +++ b/arch/arm/mach-imx/imx8mq.c @@ -62,12 +62,14 @@ static void imx8mq_silicon_revision(void) static int imx8mq_init_syscnt_frequency(void) { - void __iomem *syscnt = IOMEM(MX8MQ_SYSCNT_CTRL_BASE_ADDR); - /* - * Update with accurate clock frequency - */ - set_cntfrq(syscnt_get_cntfrq(syscnt)); - syscnt_enable(syscnt); + if (current_el() == 3) { + void __iomem *syscnt = IOMEM(MX8MQ_SYSCNT_CTRL_BASE_ADDR); + /* + * Update with accurate clock frequency + */ + set_cntfrq(syscnt_get_cntfrq(syscnt)); + syscnt_enable(syscnt); + } return 0; } -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 04/12] ARM: i.MX8MQ: Add code to load BL31 ATF blob 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (2 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 03/12] ARM: i.MX8MQ: Configure cntfrq only in EL3 Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 05/12] ARM: i.MX: fimware: Add pre-built " Andrey Smirnov ` (8 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Add imx8mq_atf_load_bl31() containing all of the code needed to load and transfer control to BL31 ATF blob on i.MX8M. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/atf.c | 41 ++++++++++++++++++++++++++++ arch/arm/mach-imx/include/mach/atf.h | 13 +++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/atf.c create mode 100644 arch/arm/mach-imx/include/mach/atf.h diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 28fe60dba..595a7512c 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -17,7 +17,7 @@ lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o obj-$(CONFIG_ARCH_IMX7) += imx7.o obj-$(CONFIG_ARCH_VF610) += vf610.o obj-$(CONFIG_ARCH_IMX8MQ) += imx8mq.o -lwl-$(CONFIG_ARCH_IMX8MQ) += imx8-ddrc.o +lwl-$(CONFIG_ARCH_IMX8MQ) += imx8-ddrc.o atf.o obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o obj-$(CONFIG_IMX_IIM) += iim.o obj-$(CONFIG_NAND_IMX) += nand.o diff --git a/arch/arm/mach-imx/atf.c b/arch/arm/mach-imx/atf.c new file mode 100644 index 000000000..2b956b6bd --- /dev/null +++ b/arch/arm/mach-imx/atf.c @@ -0,0 +1,41 @@ +#include <common.h> +#include <mach/atf.h> + +/** + * imx8mq_atf_load_bl31 - Load ATF BL31 blob and transfer contol to it + * + * @fw: Pointer to the BL31 blob + * @fw_size: Size of the BL31 blob + * + * This function: + + * 1. Copies built-in BL31 blob to an address i.MX8M's BL31 + * expects to be placed + * + * 2. Sets up temporary stack pointer for EL2, which is execution + * level that BL31 will drop us off at after it completes its + * initialization routine + * + * 3. Transfers control to BL31 + * + * NOTE: This function expects NXP's implementation of ATF that can be + * found at: + * https://source.codeaurora.org/external/imx/imx-atf + * + * any other implementation may or may not work + * + */ +void imx8mq_atf_load_bl31(const void *fw, size_t fw_size) +{ + void __noreturn (*bl31)(void) = (void *)MX8MQ_ATF_BL31_BASE_ADDR; + + if (WARN_ON(fw_size > MX8MQ_ATF_BL31_SIZE_LIMIT)) + return; + + memcpy(bl31, fw, fw_size); + + asm volatile("msr sp_el2, %0" : : + "r" (MX8MQ_ATF_BL33_BASE_ADDR - 16) : + "cc"); + bl31(); +} \ No newline at end of file diff --git a/arch/arm/mach-imx/include/mach/atf.h b/arch/arm/mach-imx/include/mach/atf.h new file mode 100644 index 000000000..aeb24bad0 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/atf.h @@ -0,0 +1,13 @@ +#ifndef __IMX_ATF_H__ +#define __IMX_ATF_H__ + +#include <linux/sizes.h> +#include <asm/system.h> + +#define MX8MQ_ATF_BL31_SIZE_LIMIT SZ_64K +#define MX8MQ_ATF_BL31_BASE_ADDR 0x00910000 +#define MX8MQ_ATF_BL33_BASE_ADDR 0x40200000 + +void imx8mq_atf_load_bl31(const void *fw, size_t fw_size); + +#endif \ No newline at end of file -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 05/12] ARM: i.MX: fimware: Add pre-built BL31 ATF blob 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (3 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 04/12] ARM: i.MX8MQ: Add code to load BL31 ATF blob Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 06/12] ARM: i.MX: Move i.MX header definitions to mach-imx Andrey Smirnov ` (7 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Running Linux on i.MX8M requires us to use and proerly set up a ARM Trusted Firmware blob. For the sake of convenience, add a pre-built blob to our firmware tree, so it can be used by individual boards. This blob was built using Buildroot: - commit: 6b02b8210acb18773f2c4b26cfc11d1f9bc4fb88 - defconig: freescale_imx8mqevk_defconfig The resulting file of interest is output/images/bl31.bin Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- firmware/Kconfig | 3 +++ firmware/Makefile | 2 ++ firmware/imx/imx8m-bl31.bin | Bin 0 -> 46744 bytes 3 files changed, 5 insertions(+) create mode 100755 firmware/imx/imx8m-bl31.bin diff --git a/firmware/Kconfig b/firmware/Kconfig index b6449644b..a6f79e8a9 100644 --- a/firmware/Kconfig +++ b/firmware/Kconfig @@ -7,4 +7,7 @@ config EXTRA_FIRMWARE_DIR config FIRMWARE_IMX_LPDDR4_PMU_TRAIN bool +config FIRMWARE_IMX8MQ_ATF + bool + endmenu diff --git a/firmware/Makefile b/firmware/Makefile index c82e81ae4..62124933d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -9,6 +9,8 @@ firmware-$(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) += \ imx/lpddr4_pmu_train_2d_dmem.bin \ imx/lpddr4_pmu_train_2d_imem.bin +firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx/imx8m-bl31.bin + # Create $(fwabs) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a # leading /, it's relative to $(srctree). fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR)) diff --git a/firmware/imx/imx8m-bl31.bin b/firmware/imx/imx8m-bl31.bin new file mode 100755 index 0000000000000000000000000000000000000000..b2310e4334c498686550a2ecab796ba905a13ebe GIT binary patch literal 46744 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 T1f8H0bnadH=+w{g^6$?d>FQ|r literal 0 HcmV?d00001 -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 06/12] ARM: i.MX: Move i.MX header definitions to mach-imx 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (4 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 05/12] ARM: i.MX: fimware: Add pre-built " Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 07/12] ARM: i.MX: xload-esdhc: Make use of <mach/imx-header.h> Andrey Smirnov ` (6 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Move i.MX header definitions from scripts to mach-imx in order to make it availible to both script and bootloader code. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/mach-imx/include/mach/imx-header.h | 118 ++++++++++++++++++++ scripts/imx/imx.h | 114 +------------------ 2 files changed, 119 insertions(+), 113 deletions(-) create mode 100644 arch/arm/mach-imx/include/mach/imx-header.h diff --git a/arch/arm/mach-imx/include/mach/imx-header.h b/arch/arm/mach-imx/include/mach/imx-header.h new file mode 100644 index 000000000..4fedba7ad --- /dev/null +++ b/arch/arm/mach-imx/include/mach/imx-header.h @@ -0,0 +1,118 @@ +#ifndef __IMX_HEADER_H__ +#define __IMX_HEADER_H__ + +#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ + +/* + * ============================================================================ + * i.MX flash header v1 handling. Found on i.MX35 and i.MX51 + * ============================================================================ + */ +#define DCD_BARKER 0xb17219e9 + +struct imx_flash_header { + uint32_t app_code_jump_vector; + uint32_t app_code_barker; + uint32_t app_code_csf; + uint32_t dcd_ptr_ptr; + uint32_t super_root_key; + uint32_t dcd; + uint32_t app_dest; + uint32_t dcd_barker; + uint32_t dcd_block_len; +} __attribute__((packed)); + +struct imx_boot_data { + uint32_t start; + uint32_t size; + uint32_t plugin; +} __attribute__((packed)); + +struct imx_dcd_rec_v1 { + uint32_t type; + uint32_t addr; + uint32_t val; +} __attribute__((packed)); + +#define TAG_IVT_HEADER 0xd1 +#define IVT_VERSION 0x40 +#define TAG_DCD_HEADER 0xd2 +#define DCD_VERSION 0x40 +#define TAG_UNLOCK 0xb2 +#define TAG_NOP 0xc0 +#define TAG_WRITE 0xcc +#define TAG_CHECK 0xcf +#define PARAMETER_FLAG_MASK (1 << 3) +#define PARAMETER_FLAG_SET (1 << 4) + +struct imx_ivt_header { + uint8_t tag; + uint16_t length; + uint8_t version; +} __attribute__((packed)); + +struct imx_flash_header_v2 { + struct imx_ivt_header header; + + uint32_t entry; + uint32_t reserved1; + uint32_t dcd_ptr; + uint32_t boot_data_ptr; + uint32_t self; + uint32_t csf; + uint32_t reserved2; + + struct imx_boot_data boot_data; + struct imx_ivt_header dcd_header; +} __attribute__((packed)); + +struct config_data { + uint32_t image_load_addr; + uint32_t image_dcd_offset; + uint32_t image_size; + uint32_t load_size; + char *outfile; + char *srkfile; + int header_version; + off_t header_gap; + uint32_t first_opcode; + int cpu_type; + int (*check)(const struct config_data *data, uint32_t cmd, + uint32_t addr, uint32_t mask); + int (*write_mem)(const struct config_data *data, uint32_t addr, + uint32_t val, int width, int set_bits, int clear_bits); + int (*nop)(const struct config_data *data); + int csf_space; + char *csf; +}; + +#define MAX_RECORDS_DCD_V2 1024 +struct imx_dcd_v2_write_rec { + uint32_t addr; + uint32_t val; +} __attribute__((packed)); + +struct imx_dcd_v2_write { + uint8_t tag; + uint16_t length; + uint8_t param; + struct imx_dcd_v2_write_rec data[MAX_RECORDS_DCD_V2]; +} __attribute__((packed)); + +struct imx_dcd_v2_check { + uint8_t tag; + uint16_t length; + uint8_t param; + uint32_t addr; + uint32_t mask; + uint32_t count; +} __attribute__((packed)); + +enum imx_dcd_v2_check_cond { + until_all_bits_clear = 0, /* until ((*address & mask) == 0) { ...} */ + until_any_bit_clear = 1, /* until ((*address & mask) != mask) { ...} */ + until_all_bits_set = 2, /* until ((*address & mask) == mask) { ...} */ + until_any_bit_set = 3, /* until ((*address & mask) != 0) { ...} */ +} __attribute__((packed)); + +#endif diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h index 92a3fd316..20fb1e876 100644 --- a/scripts/imx/imx.h +++ b/scripts/imx/imx.h @@ -1,116 +1,4 @@ -#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ - -/* - * ============================================================================ - * i.MX flash header v1 handling. Found on i.MX35 and i.MX51 - * ============================================================================ - */ -#define DCD_BARKER 0xb17219e9 - -struct imx_flash_header { - uint32_t app_code_jump_vector; - uint32_t app_code_barker; - uint32_t app_code_csf; - uint32_t dcd_ptr_ptr; - uint32_t super_root_key; - uint32_t dcd; - uint32_t app_dest; - uint32_t dcd_barker; - uint32_t dcd_block_len; -} __attribute__((packed)); - -struct imx_boot_data { - uint32_t start; - uint32_t size; - uint32_t plugin; -} __attribute__((packed)); - -struct imx_dcd_rec_v1 { - uint32_t type; - uint32_t addr; - uint32_t val; -} __attribute__((packed)); - -#define TAG_IVT_HEADER 0xd1 -#define IVT_VERSION 0x40 -#define TAG_DCD_HEADER 0xd2 -#define DCD_VERSION 0x40 -#define TAG_UNLOCK 0xb2 -#define TAG_NOP 0xc0 -#define TAG_WRITE 0xcc -#define TAG_CHECK 0xcf -#define PARAMETER_FLAG_MASK (1 << 3) -#define PARAMETER_FLAG_SET (1 << 4) - -struct imx_ivt_header { - uint8_t tag; - uint16_t length; - uint8_t version; -} __attribute__((packed)); - -struct imx_flash_header_v2 { - struct imx_ivt_header header; - - uint32_t entry; - uint32_t reserved1; - uint32_t dcd_ptr; - uint32_t boot_data_ptr; - uint32_t self; - uint32_t csf; - uint32_t reserved2; - - struct imx_boot_data boot_data; - struct imx_ivt_header dcd_header; -} __attribute__((packed)); - -struct config_data { - uint32_t image_load_addr; - uint32_t image_dcd_offset; - uint32_t image_size; - uint32_t load_size; - char *outfile; - char *srkfile; - int header_version; - off_t header_gap; - uint32_t first_opcode; - int cpu_type; - int (*check)(const struct config_data *data, uint32_t cmd, - uint32_t addr, uint32_t mask); - int (*write_mem)(const struct config_data *data, uint32_t addr, - uint32_t val, int width, int set_bits, int clear_bits); - int (*nop)(const struct config_data *data); - int csf_space; - char *csf; -}; - -#define MAX_RECORDS_DCD_V2 1024 -struct imx_dcd_v2_write_rec { - uint32_t addr; - uint32_t val; -} __attribute__((packed)); - -struct imx_dcd_v2_write { - uint8_t tag; - uint16_t length; - uint8_t param; - struct imx_dcd_v2_write_rec data[MAX_RECORDS_DCD_V2]; -} __attribute__((packed)); - -struct imx_dcd_v2_check { - uint8_t tag; - uint16_t length; - uint8_t param; - uint32_t addr; - uint32_t mask; - uint32_t count; -} __attribute__((packed)); - -enum imx_dcd_v2_check_cond { - until_all_bits_clear = 0, /* until ((*address & mask) == 0) { ...} */ - until_any_bit_clear = 1, /* until ((*address & mask) != mask) { ...} */ - until_all_bits_set = 2, /* until ((*address & mask) == mask) { ...} */ - until_any_bit_set = 3, /* until ((*address & mask) != 0) { ...} */ -} __attribute__((packed)); +#include <mach/imx-header.h> int parse_config(struct config_data *data, const char *filename); -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 07/12] ARM: i.MX: xload-esdhc: Make use of <mach/imx-header.h> 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (5 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 06/12] ARM: i.MX: Move i.MX header definitions to mach-imx Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 08/12] ARM: i.MX: xload-esdhc: Allow placing image to align its etnry point Andrey Smirnov ` (5 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Convert esdhc_start_image() to use constants and data types from <mach/imx-header.h>. Also, while at it, define a simple inline function to test if an arbitrary binary blob is i.MX flash header v2. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/mach-imx/include/mach/imx-header.h | 10 ++++++++++ arch/arm/mach-imx/xload-esdhc.c | 14 +++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-imx/include/mach/imx-header.h b/arch/arm/mach-imx/include/mach/imx-header.h index 4fedba7ad..c9b2a5881 100644 --- a/arch/arm/mach-imx/include/mach/imx-header.h +++ b/arch/arm/mach-imx/include/mach/imx-header.h @@ -1,6 +1,8 @@ #ifndef __IMX_HEADER_H__ #define __IMX_HEADER_H__ +#include <linux/types.h> + #define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ /* @@ -66,6 +68,14 @@ struct imx_flash_header_v2 { struct imx_ivt_header dcd_header; } __attribute__((packed)); +static inline bool is_imx_flash_header_v2(const void *blob) +{ + const struct imx_flash_header_v2 *hdr = blob; + + return hdr->header.tag == TAG_IVT_HEADER && + hdr->header.version >= IVT_VERSION; +} + struct config_data { uint32_t image_load_addr; uint32_t image_dcd_offset; diff --git a/arch/arm/mach-imx/xload-esdhc.c b/arch/arm/mach-imx/xload-esdhc.c index 08ba9b08d..5ce83b0bf 100644 --- a/arch/arm/mach-imx/xload-esdhc.c +++ b/arch/arm/mach-imx/xload-esdhc.c @@ -18,6 +18,7 @@ #include <mach/imx8mq-regs.h> #include <mach/xload.h> #include <linux/sizes.h> +#include <mach/imx-header.h> #include "../../../drivers/mci/sdhci.h" #include "../../../drivers/mci/imx-esdhc.h" @@ -220,8 +221,9 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len) static int esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset) { + void *buf = (void *)address; - u32 *ivt = buf + offset + SZ_1K; + struct imx_flash_header_v2 *hdr = buf + offset + SZ_1K; int ret, len; void __noreturn (*bb)(void); unsigned int ofs; @@ -233,9 +235,11 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset) if (ret) return ret; - if (*(u32 *)(ivt) != 0x402000d1) { - pr_debug("IVT header not found on SD card. Found 0x%08x instead of 0x402000d1\n", - *ivt); + if (!is_imx_flash_header_v2(hdr)) { + pr_debug("IVT header not found on SD card. " + "Found tag: 0x%02x length: 0x%04x version: %02x\n", + hdr->header.tag, hdr->header.length, + hdr->header.version); return -EINVAL; } @@ -249,7 +253,7 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset) pr_debug("Image loaded successfully\n"); - ofs = offset + *(ivt + 1) - *(ivt + 8); + ofs = offset + hdr->entry - hdr->boot_data.start; bb = buf + ofs; -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 08/12] ARM: i.MX: xload-esdhc: Allow placing image to align its etnry point 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (6 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 07/12] ARM: i.MX: xload-esdhc: Make use of <mach/imx-header.h> Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 09/12] ARM: nxp-imx8mq-evk: Add code to load ATF BL31 blob Andrey Smirnov ` (4 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Allow placing image to align its etnry point with a particular entry point address. This is needed for SoC's like i.MX8M where vendor-provided ARM Trusted Firmware blob will exit at specific pre-determined address and we need to be able to pick execution up form there. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/mach-imx/xload-esdhc.c | 39 ++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-imx/xload-esdhc.c b/arch/arm/mach-imx/xload-esdhc.c index 5ce83b0bf..55d6c6929 100644 --- a/arch/arm/mach-imx/xload-esdhc.c +++ b/arch/arm/mach-imx/xload-esdhc.c @@ -14,6 +14,7 @@ #include <common.h> #include <io.h> #include <mci.h> +#include <mach/atf.h> #include <mach/imx6-regs.h> #include <mach/imx8mq-regs.h> #include <mach/xload.h> @@ -219,7 +220,7 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len) } static int -esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset) +esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry, u32 offset) { void *buf = (void *)address; @@ -245,6 +246,35 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset) pr_debug("Check ok, loading image\n"); + ofs = offset + hdr->entry - hdr->boot_data.start; + + if (entry != address) { + /* + * Passing entry different from address is interpreted + * as a request to place the image such that its entry + * point would be exactly at 'entry', that is: + * + * buf + ofs = entry + * + * solving the above for 'buf' gvies us the + * adjustement that needs to be made: + * + * buf = entry - ofs + * + */ + if (WARN_ON(entry - ofs < address)) { + /* + * We want to make sure we won't try to place + * the start of the image before the beginning + * of the memory buffer we were given in + * address. + */ + return -EINVAL; + } + + buf = (void *)(entry - ofs); + } + ret = esdhc_read_blocks(esdhc, buf, offset + len); if (ret) { pr_err("Loading image failed with %d\n", ret); @@ -253,8 +283,6 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, u32 offset) pr_debug("Image loaded successfully\n"); - ofs = offset + hdr->entry - hdr->boot_data.start; - bb = buf + ofs; bb(); @@ -295,7 +323,7 @@ int imx6_esdhc_start_image(int instance) esdhc.is_mx6 = 1; - return esdhc_start_image(&esdhc, 0x10000000, 0); + return esdhc_start_image(&esdhc, 0x10000000, 0x10000000, 0); } /** @@ -327,5 +355,6 @@ int imx8_esdhc_start_image(int instance) esdhc.is_mx6 = 1; - return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR, SZ_32K); + return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR, + MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K); } \ No newline at end of file -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 09/12] ARM: nxp-imx8mq-evk: Add code to load ATF BL31 blob 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (7 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 08/12] ARM: i.MX: xload-esdhc: Allow placing image to align its etnry point Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 10/12] ARM: i.MX8MQ: Query and display ATF fimware hash if availible Andrey Smirnov ` (3 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/boards/nxp-imx8mq-evk/lowlevel.c | 9 +++++++++ arch/arm/mach-imx/Kconfig | 2 ++ 2 files changed, 11 insertions(+) diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c index 1ed918ee0..db746bb94 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c +++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c @@ -23,6 +23,7 @@ #include <asm/cache.h> #include <asm/sections.h> #include <asm/mmu.h> +#include <mach/atf.h> #include "ddr.h" @@ -75,6 +76,14 @@ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) nxp_imx8mq_evk_sram_setup(); + if (current_el() == 3) { + const u8 *bl31; + size_t bl31_size; + + get_builtin_firmware(imx_imx8m_bl31_bin, &bl31, &bl31_size); + imx8mq_atf_load_bl31(bl31, bl31_size); + } + barebox_arm_entry(MX8MQ_DDR_CSD1_BASE_ADDR, SZ_2G + SZ_1G, __dtb_imx8mq_evk_start); } diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 73b7ea1b6..7cb9138d2 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -461,6 +461,8 @@ config MACH_NXP_IMX8MQ_EVK bool "NXP i.MX8MQ EVK Board" select ARCH_IMX8MQ select FIRMWARE_IMX_LPDDR4_PMU_TRAIN + select FIRMWARE_IMX8MQ_ATF + select ARM_SMCCC endif -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 10/12] ARM: i.MX8MQ: Query and display ATF fimware hash if availible 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (8 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 09/12] ARM: nxp-imx8mq-evk: Add code to load ATF BL31 blob Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 11/12] ARM: nxp-imx8mq-evk: Add bootflow comments Andrey Smirnov ` (2 subsequent siblings) 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/mach-imx/imx8mq.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/mach-imx/imx8mq.c b/arch/arm/mach-imx/imx8mq.c index dbcf4fa59..152f07bc1 100644 --- a/arch/arm/mach-imx/imx8mq.c +++ b/arch/arm/mach-imx/imx8mq.c @@ -20,11 +20,16 @@ #include <mach/revision.h> #include <mach/imx8mq-regs.h> +#include <linux/arm-smccc.h> + #define IMX8MQ_ROM_VERSION_A0 0x800 #define IMX8MQ_ROM_VERSION_B0 0x83C #define MX8MQ_ANATOP_DIGPROG 0x6c +#define FSL_SIP_BUILDINFO 0xC2000003 +#define FSL_SIP_BUILDINFO_GET_COMMITHASH 0x00 + static void imx8mq_silicon_revision(void) { void __iomem *anatop = IOMEM(MX8MQ_ANATOP_BASE_ADDR); @@ -81,7 +86,17 @@ core_initcall(imx8mq_init_syscnt_frequency); int imx8mq_init(void) { + struct arm_smccc_res res; + imx8mq_silicon_revision(); + if (IS_ENABLED(CONFIG_ARM_SMCCC) && + IS_ENABLED(CONFIG_FIRMWARE_IMX8MQ_ATF)) { + arm_smccc_smc(FSL_SIP_BUILDINFO, + FSL_SIP_BUILDINFO_GET_COMMITHASH, + 0, 0, 0, 0, 0, 0, &res); + pr_info("i.MX ARM Trusted Firmware: %s\n", (char *)&res.a0); + } + return 0; } -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 11/12] ARM: nxp-imx8mq-evk: Add bootflow comments 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (9 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 10/12] ARM: i.MX8MQ: Query and display ATF fimware hash if availible Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 12/12] firmware: Fix copy-paste comment mistake Andrey Smirnov 2018-08-08 6:34 ` [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Sascha Hauer 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Add some notes on how the boot-flow goes while I still remember it. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- arch/arm/boards/nxp-imx8mq-evk/lowlevel.c | 41 +++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c index db746bb94..fdc964ac9 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c +++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c @@ -66,6 +66,26 @@ static void nxp_imx8mq_evk_sram_setup(void) BUG_ON(ret); } +/* + * Power-on execution flow of start_nxp_imx8mq_evk() might not be + * obvious for a very frist read, so here's, hopefully helpful, + * summary: + * + * 1. MaskROM uploads PBL into OCRAM and that's where this function is + * executed for the first time + * + * 2. DDR is initialized and full i.MX image is loaded to the + * beginning of RAM + * + * 3. start_nxp_imx8mq_evk, now in RAM, is executed again + * + * 4. BL31 blob is uploaded to OCRAM and the control is transfer to it + * + * 5. BL31 exits EL3 into EL2 at address MX8MQ_ATF_BL33_BASE_ADDR, + * executing start_nxp_imx8mq_evk() the third time + * + * 6. Standard barebox boot flow continues + */ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) { arm_cpu_lowlevel_init(); @@ -73,9 +93,23 @@ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) if (IS_ENABLED(CONFIG_DEBUG_LL)) setup_uart(); - if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) + if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) { + /* + * We assume that we were just loaded by MaskROM into + * SRAM if we are not running from DDR. We also assume + * that means DDR needs to be initialized for the + * first time. + */ nxp_imx8mq_evk_sram_setup(); - + } + /* + * Straight from the power-on we are at EL3, so the following + * code _will_ load and jump to ATF. + * + * However when we are re-executed upon exit from ATF's + * initialization routine, it is EL2 which means we'll skip + * loadting ATF blob again + */ if (current_el() == 3) { const u8 *bl31; size_t bl31_size; @@ -84,6 +118,9 @@ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) imx8mq_atf_load_bl31(bl31, bl31_size); } + /* + * Standard entry we hit once we initialized both DDR and ATF + */ barebox_arm_entry(MX8MQ_DDR_CSD1_BASE_ADDR, SZ_2G + SZ_1G, __dtb_imx8mq_evk_start); } -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 12/12] firmware: Fix copy-paste comment mistake 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (10 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 11/12] ARM: nxp-imx8mq-evk: Add bootflow comments Andrey Smirnov @ 2018-07-20 1:03 ` Andrey Smirnov 2018-08-08 6:34 ` [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Sascha Hauer 12 siblings, 0 replies; 14+ messages in thread From: Andrey Smirnov @ 2018-07-20 1:03 UTC (permalink / raw) To: barebox; +Cc: Andrey Smirnov Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> --- firmware/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 62124933d..7f4dc4932 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -57,6 +57,6 @@ endif targets := $(patsubst $(obj)/%,%, \ $(shell find $(obj) -name \*.gen.S 2>/dev/null)) -# just to build a built-in.o. Otherwise compilation fails when no devicetree is -# created. +# just to build a built-in.o. Otherwise compilation fails when no +# firmware is built. obj- += dummy.o -- 2.17.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov ` (11 preceding siblings ...) 2018-07-20 1:03 ` [PATCH v2 12/12] firmware: Fix copy-paste comment mistake Andrey Smirnov @ 2018-08-08 6:34 ` Sascha Hauer 12 siblings, 0 replies; 14+ messages in thread From: Sascha Hauer @ 2018-08-08 6:34 UTC (permalink / raw) To: Andrey Smirnov; +Cc: barebox On Thu, Jul 19, 2018 at 06:03:45PM -0700, Andrey Smirnov wrote: > Everyone: > > This is part II of i.MX8MQ EVK board support patches. This time this > is bits and pieces that were necessary in order to allow booting > vendor Linux kernel availible here (tag: rel_imx_4.9.51_8mq_ga): > > https://source.codeaurora.org/external/imx/linux-imx > > Sources for ATF were taken from here (tag: rel_imx_4.9.51_8mq_ga): > > https://source.codeaurora.org/external/imx/imx-atf > > This patchest is also availible at: > > https://github.com/ndreys/barebox/tree/imx8m-support-part-II-v2 > > Feedback is welcome! > > Changes since [v1]: > > - Opcode patching is replaced with placing barebox image at the > right spot > > - ATF loading code is converted into a function (was a macro > originally) > > - It is now up to the user to check current EL when calling > imx8mq_atf_load_bl31() > > - Other various small change as per Sascha's feedback > > [v1] http://lists.infradead.org/pipermail/barebox/2018-June/033922.html > > Thanks, > Andrey Smirnov Applied with some typos fixed, thanks Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2018-08-08 6:34 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-07-20 1:03 [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 01/12] ARM: nxp-imx8mq-evk: Update DDR initialization code Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 02/12] ARM: Add code to support SMCCC on AArch64 Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 03/12] ARM: i.MX8MQ: Configure cntfrq only in EL3 Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 04/12] ARM: i.MX8MQ: Add code to load BL31 ATF blob Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 05/12] ARM: i.MX: fimware: Add pre-built " Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 06/12] ARM: i.MX: Move i.MX header definitions to mach-imx Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 07/12] ARM: i.MX: xload-esdhc: Make use of <mach/imx-header.h> Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 08/12] ARM: i.MX: xload-esdhc: Allow placing image to align its etnry point Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 09/12] ARM: nxp-imx8mq-evk: Add code to load ATF BL31 blob Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 10/12] ARM: i.MX8MQ: Query and display ATF fimware hash if availible Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 11/12] ARM: nxp-imx8mq-evk: Add bootflow comments Andrey Smirnov 2018-07-20 1:03 ` [PATCH v2 12/12] firmware: Fix copy-paste comment mistake Andrey Smirnov 2018-08-08 6:34 ` [PATCH v2 00/12] ARM: i.MX8MQ and EVK support, part II Sascha Hauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox