From c85389468d5ee9f06de67f10783bc015117caf67 Mon Sep 17 00:00:00 2001 From: Romuald JEANNE Date: Mon, 15 Mar 2021 17:27:07 +0100 Subject: [PATCH] 3.12.0-stm32mp-r1 Signed-off-by: Romuald JEANNE --- CONTRIBUTING.md | 30 + core/arch/arm/dts/stm32mp15-pinctrl.dtsi | 957 ++---------- core/arch/arm/dts/stm32mp151.dtsi | 1368 +++-------------- core/arch/arm/dts/stm32mp153.dtsi | 31 +- core/arch/arm/dts/stm32mp157.dtsi | 24 - core/arch/arm/dts/stm32mp157a-dk1.dts | 29 +- core/arch/arm/dts/stm32mp157a-ed1.dts | 38 + core/arch/arm/dts/stm32mp157a-ev1.dts | 24 + core/arch/arm/dts/stm32mp157c-dk2.dts | 95 +- core/arch/arm/dts/stm32mp157c-ed1.dts | 377 +---- core/arch/arm/dts/stm32mp157c-ev1.dts | 349 +---- core/arch/arm/dts/stm32mp157d-dk1.dts | 45 + core/arch/arm/dts/stm32mp157d-ed1.dts | 39 + core/arch/arm/dts/stm32mp157d-ev1.dts | 23 + core/arch/arm/dts/stm32mp157f-dk2.dts | 51 + core/arch/arm/dts/stm32mp157f-ed1.dts | 43 + core/arch/arm/dts/stm32mp157f-ev1.dts | 23 + core/arch/arm/dts/stm32mp15xa.dtsi | 13 + core/arch/arm/dts/stm32mp15xc.dtsi | 3 + core/arch/arm/dts/stm32mp15xd.dtsi | 19 + core/arch/arm/dts/stm32mp15xf.dtsi | 21 + core/arch/arm/dts/stm32mp15xx-dkx.dtsi | 708 ++++----- core/arch/arm/dts/stm32mp15xx-edx.dtsi | 517 +++++++ core/arch/arm/dts/stm32mp15xx-evx.dtsi | 73 + core/arch/arm/dts/stm32mp15xxaa-pinctrl.dtsi | 1 + core/arch/arm/dts/stm32mp15xxac-pinctrl.dtsi | 1 + core/arch/arm/include/arm32.h | 11 +- core/arch/arm/include/kernel/tlb_helpers.h | 9 +- core/arch/arm/include/mm/core_mmu.h | 15 + core/arch/arm/include/mm/pgt_cache.h | 5 +- core/arch/arm/include/sm/pm.h | 4 + core/arch/arm/mm/core_mmu.c | 35 +- core/arch/arm/mm/mobj.c | 5 +- core/arch/arm/mm/pgt_cache.c | 56 +- core/arch/arm/plat-stm32mp1/boot_api.h | 2 + core/arch/arm/plat-stm32mp1/conf.mk | 74 +- .../plat-stm32mp1/drivers/stm32mp1_calib.c | 507 ++++++ .../arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c | 469 ++++++ .../arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h | 219 +++ .../arm/plat-stm32mp1/drivers/stm32mp1_pmic.c | 50 +- .../arm/plat-stm32mp1/drivers/stm32mp1_pmic.h | 8 +- .../arm/plat-stm32mp1/drivers/stm32mp1_pwr.h | 33 +- .../plat-stm32mp1/drivers/stm32mp1_syscfg.c | 14 +- core/arch/arm/plat-stm32mp1/drivers/sub.mk | 3 +- core/arch/arm/plat-stm32mp1/link.mk | 2 + core/arch/arm/plat-stm32mp1/main.c | 354 ++++- .../nsec-service/low_power_svc.c | 152 ++ .../nsec-service/low_power_svc.h | 55 + .../arm/plat-stm32mp1/nsec-service/pwr_svc.c | 89 ++ .../arm/plat-stm32mp1/nsec-service/pwr_svc.h | 22 + .../arm/plat-stm32mp1/nsec-service/rcc_svc.c | 139 ++ .../arm/plat-stm32mp1/nsec-service/rcc_svc.h | 30 + .../plat-stm32mp1/nsec-service/stm32mp1_smc.h | 196 ++- .../nsec-service/stm32mp1_svc_setup.c | 79 +- .../arm/plat-stm32mp1/nsec-service/sub.mk | 3 + core/arch/arm/plat-stm32mp1/plat_tzc400.c | 52 +- core/arch/arm/plat-stm32mp1/platform_config.h | 139 +- core/arch/arm/plat-stm32mp1/pm/context.c | 522 +++++++ core/arch/arm/plat-stm32mp1/pm/context.h | 102 ++ .../plat-stm32mp1/pm/context_asm_defines.c | 28 + core/arch/arm/plat-stm32mp1/pm/low_power.c | 626 ++++++++ core/arch/arm/plat-stm32mp1/pm/pm_helpers.S | 729 +++++++++ core/arch/arm/plat-stm32mp1/pm/power.h | 27 + core/arch/arm/plat-stm32mp1/pm/power_config.c | 252 +++ core/arch/arm/plat-stm32mp1/pm/psci.c | 234 ++- core/arch/arm/plat-stm32mp1/pm/sub.mk | 6 + core/arch/arm/plat-stm32mp1/remoteproc_pta.c | 528 +++++++ core/arch/arm/plat-stm32mp1/reset.S | 28 +- core/arch/arm/plat-stm32mp1/rproc_pub_key.h | 16 + core/arch/arm/plat-stm32mp1/scmi_server.c | 96 +- .../arch/arm/plat-stm32mp1/shared_resources.c | 156 +- core/arch/arm/plat-stm32mp1/stm32_util.h | 77 +- core/arch/arm/plat-stm32mp1/stm32mp_pm.h | 21 + core/arch/arm/plat-stm32mp1/sub.mk | 9 + core/arch/arm/sm/pm_a32.S | 83 +- core/arch/arm/tee/entry_std.c | 2 +- .../clk/clk-stm32mp15.c} | 1345 +++++++++++++++- core/drivers/clk/clk.c | 58 + core/drivers/clk/sub.mk | 2 + core/drivers/gic.c | 225 ++- core/drivers/scmi-msg/clock.c | 4 +- core/drivers/stm32_bsec.c | 111 +- core/drivers/stm32_etzpc.c | 47 + core/drivers/stm32_gpio.c | 23 +- core/drivers/stm32_i2c.c | 37 +- core/drivers/stm32_iwdg.c | 314 ++++ core/drivers/stm32_rng.c | 7 +- core/drivers/stm32_rtc.c | 446 ++++++ core/drivers/stm32_tim.c | 298 ++++ core/drivers/sub.mk | 4 + core/include/drivers/clk.h | 35 + core/include/drivers/gic.h | 24 + core/include/drivers/stm32_bsec.h | 16 + core/include/drivers/stm32_iwdg.h | 17 + core/include/drivers/stm32_rtc.h | 60 + core/include/drivers/stm32_tim.h | 25 + .../drivers/stm32mp1_rcc.h | 38 +- .../dt-bindings/clock/stm32mp1-clksrc.h | 284 ++++ .../dt-bindings/power/stm32mp1-power.h | 19 + .../dt-bindings/soc/st,stm32-etzpc.h} | 35 +- core/include/kernel/interrupt.h | 15 + core/include/kernel/panic.h | 6 + core/kernel/interrupt.c | 10 + core/kernel/panic.c | 23 +- core/mm/vm.c | 42 +- core/sub.mk | 7 +- keys/default_rproc.pem | 27 + lib/libutee/include/remoteproc_pta.h | 157 ++ mk/config.mk | 4 + mk/gcc.mk | 6 +- scripts/sign_rproc_fw.py | 416 +++++ ta/remoteproc/Makefile | 18 + ta/remoteproc/elf_parser.c | 186 +++ ta/remoteproc/include/elf32.h | 243 +++ ta/remoteproc/include/elf_common.h | 1014 ++++++++++++ ta/remoteproc/include/elf_parser.h | 59 + ta/remoteproc/include/ta_remoteproc.h | 65 + .../include/user_ta_header_defines.h | 29 + ta/remoteproc/remoteproc_core.c | 781 ++++++++++ ta/remoteproc/sub.mk | 3 + ta/remoteproc/user_ta.mk | 1 + 121 files changed, 14243 insertions(+), 3618 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 core/arch/arm/dts/stm32mp157a-ed1.dts create mode 100644 core/arch/arm/dts/stm32mp157a-ev1.dts create mode 100644 core/arch/arm/dts/stm32mp157d-dk1.dts create mode 100644 core/arch/arm/dts/stm32mp157d-ed1.dts create mode 100644 core/arch/arm/dts/stm32mp157d-ev1.dts create mode 100644 core/arch/arm/dts/stm32mp157f-dk2.dts create mode 100644 core/arch/arm/dts/stm32mp157f-ed1.dts create mode 100644 core/arch/arm/dts/stm32mp157f-ev1.dts create mode 100644 core/arch/arm/dts/stm32mp15xa.dtsi create mode 100644 core/arch/arm/dts/stm32mp15xd.dtsi create mode 100644 core/arch/arm/dts/stm32mp15xf.dtsi create mode 100644 core/arch/arm/dts/stm32mp15xx-edx.dtsi create mode 100644 core/arch/arm/dts/stm32mp15xx-evx.dtsi create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h create mode 100644 core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.c create mode 100644 core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.h create mode 100644 core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.c create mode 100644 core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.h create mode 100644 core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.c create mode 100644 core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.h create mode 100644 core/arch/arm/plat-stm32mp1/pm/context.c create mode 100644 core/arch/arm/plat-stm32mp1/pm/context.h create mode 100644 core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c create mode 100644 core/arch/arm/plat-stm32mp1/pm/low_power.c create mode 100644 core/arch/arm/plat-stm32mp1/pm/pm_helpers.S create mode 100644 core/arch/arm/plat-stm32mp1/pm/power.h create mode 100644 core/arch/arm/plat-stm32mp1/pm/power_config.c create mode 100644 core/arch/arm/plat-stm32mp1/remoteproc_pta.c create mode 100644 core/arch/arm/plat-stm32mp1/rproc_pub_key.h create mode 100644 core/arch/arm/plat-stm32mp1/stm32mp_pm.h rename core/{arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c => drivers/clk/clk-stm32mp15.c} (50%) create mode 100644 core/drivers/clk/clk.c create mode 100644 core/drivers/clk/sub.mk create mode 100644 core/drivers/stm32_iwdg.c create mode 100644 core/drivers/stm32_rtc.c create mode 100644 core/drivers/stm32_tim.c create mode 100644 core/include/drivers/clk.h create mode 100644 core/include/drivers/stm32_iwdg.h create mode 100644 core/include/drivers/stm32_rtc.h create mode 100644 core/include/drivers/stm32_tim.h rename core/{arch/arm/plat-stm32mp1 => include}/drivers/stm32mp1_rcc.h (95%) create mode 100644 core/include/dt-bindings/clock/stm32mp1-clksrc.h create mode 100644 core/include/dt-bindings/power/stm32mp1-power.h rename core/{arch/arm/plat-stm32mp1/drivers/stm32mp1_etzpc.h => include/dt-bindings/soc/st,stm32-etzpc.h} (83%) create mode 100644 keys/default_rproc.pem create mode 100644 lib/libutee/include/remoteproc_pta.h create mode 100755 scripts/sign_rproc_fw.py create mode 100644 ta/remoteproc/Makefile create mode 100644 ta/remoteproc/elf_parser.c create mode 100644 ta/remoteproc/include/elf32.h create mode 100644 ta/remoteproc/include/elf_common.h create mode 100644 ta/remoteproc/include/elf_parser.h create mode 100644 ta/remoteproc/include/ta_remoteproc.h create mode 100644 ta/remoteproc/include/user_ta_header_defines.h create mode 100644 ta/remoteproc/remoteproc_core.c create mode 100644 ta/remoteproc/sub.mk create mode 100644 ta/remoteproc/user_ta.mk diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..3d1bacd78 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing guide + +This document serves as a checklist before contributing to this repository. It includes links to read up on if topics are unclear to you. + +This guide mainly focuses on the proper use of Git. + +## 1. Issues + +STM32MPU projects do not activate "Github issues" feature for the time being. If you need to report an issue or question about this project deliverables, you can report them using [ ST Support Center ](https://my.st.com/ols#/ols/newrequest) or [ ST Community MPU Forum ](https://community.st.com/s/topic/0TO0X0000003u2AWAQ/stm32-mpus). + +## 2. Pull Requests + +STMicrolectronics is happy to receive contributions from the community, based on an initial Contributor License Agreement (CLA) procedure. + +* If you are an individual writing original source code and you are sure **you own the intellectual property**, then you need to sign an Individual CLA (https://cla.st.com). +* If you work for a company that wants also to allow you to contribute with your work, your company needs to provide a Corporate CLA (https://cla.st.com) mentioning your GitHub account name. +* If you are not sure that a CLA (Individual or Corporate) has been signed for your GitHub account you can check here (https://cla.st.com). + +Please note that: +* The Corporate CLA will always take precedence over the Individual CLA. +* One CLA submission is sufficient, for any project proposed by STMicroelectronics. + +__How to proceed__ + +* We recommend to fork the project in your GitHub account to further develop your contribution. Please use the latest commit version. +* Please, submit one Pull Request for one new feature or proposal. This will ease the analysis and final merge if accepted. + +__Note__ + +Merge will not be done directly in GitHub but it will need first to follow internal integration process before public deliver in a standard release. The Pull request will stay open until it is merged and delivered. diff --git a/core/arch/arm/dts/stm32mp15-pinctrl.dtsi b/core/arch/arm/dts/stm32mp15-pinctrl.dtsi index 0237d4dda..16c40cbff 100644 --- a/core/arch/arm/dts/stm32mp15-pinctrl.dtsi +++ b/core/arch/arm/dts/stm32mp15-pinctrl.dtsi @@ -6,162 +6,6 @@ #include &pinctrl { - adc1_in6_pins_a: adc1-in6 { - pins { - pinmux = ; - }; - }; - - adc12_ain_pins_a: adc12-ain-0 { - pins { - pinmux = , /* ADC1 in13 */ - , /* ADC1 in6 */ - , /* ADC2 in2 */ - ; /* ADC2 in6 */ - }; - }; - - adc12_usb_cc_pins_a: adc12-usb-cc-pins-0 { - pins { - pinmux = , /* ADC12 in18 */ - ; /* ADC12 in19 */ - }; - }; - - cec_pins_a: cec-0 { - pins { - pinmux = ; - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - cec_pins_sleep_a: cec-sleep-0 { - pins { - pinmux = ; /* HDMI_CEC */ - }; - }; - - cec_pins_b: cec-1 { - pins { - pinmux = ; - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - cec_pins_sleep_b: cec-sleep-1 { - pins { - pinmux = ; /* HDMI_CEC */ - }; - }; - - dac_ch1_pins_a: dac-ch1 { - pins { - pinmux = ; - }; - }; - - dac_ch2_pins_a: dac-ch2 { - pins { - pinmux = ; - }; - }; - - dcmi_pins_a: dcmi-0 { - pins { - pinmux = ,/* DCMI_HSYNC */ - ,/* DCMI_VSYNC */ - ,/* DCMI_PIXCLK */ - ,/* DCMI_D0 */ - ,/* DCMI_D1 */ - ,/* DCMI_D2 */ - ,/* DCMI_D3 */ - ,/* DCMI_D4 */ - ,/* DCMI_D5 */ - ,/* DCMI_D6 */ - ,/* DCMI_D7 */ - ,/* DCMI_D8 */ - ,/* DCMI_D9 */ - ,/* DCMI_D10 */ - ;/* DCMI_D11 */ - bias-disable; - }; - }; - - dcmi_sleep_pins_a: dcmi-sleep-0 { - pins { - pinmux = ,/* DCMI_HSYNC */ - ,/* DCMI_VSYNC */ - ,/* DCMI_PIXCLK */ - ,/* DCMI_D0 */ - ,/* DCMI_D1 */ - ,/* DCMI_D2 */ - ,/* DCMI_D3 */ - ,/* DCMI_D4 */ - ,/* DCMI_D5 */ - ,/* DCMI_D6 */ - ,/* DCMI_D7 */ - ,/* DCMI_D8 */ - ,/* DCMI_D9 */ - ,/* DCMI_D10 */ - ;/* DCMI_D11 */ - }; - }; - - ethernet0_rgmii_pins_a: rgmii-0 { - pins1 { - pinmux = , /* ETH_RGMII_CLK125 */ - , /* ETH_RGMII_GTX_CLK */ - , /* ETH_RGMII_TXD0 */ - , /* ETH_RGMII_TXD1 */ - , /* ETH_RGMII_TXD2 */ - , /* ETH_RGMII_TXD3 */ - , /* ETH_RGMII_TX_CTL */ - ; /* ETH_MDC */ - bias-disable; - drive-push-pull; - slew-rate = <2>; - }; - pins2 { - pinmux = ; /* ETH_MDIO */ - bias-disable; - drive-push-pull; - slew-rate = <0>; - }; - pins3 { - pinmux = , /* ETH_RGMII_RXD0 */ - , /* ETH_RGMII_RXD1 */ - , /* ETH_RGMII_RXD2 */ - , /* ETH_RGMII_RXD3 */ - , /* ETH_RGMII_RX_CLK */ - ; /* ETH_RGMII_RX_CTL */ - bias-disable; - }; - }; - - ethernet0_rgmii_pins_sleep_a: rgmii-sleep-0 { - pins1 { - pinmux = , /* ETH_RGMII_CLK125 */ - , /* ETH_RGMII_GTX_CLK */ - , /* ETH_RGMII_TXD0 */ - , /* ETH_RGMII_TXD1 */ - , /* ETH_RGMII_TXD2 */ - , /* ETH_RGMII_TXD3 */ - , /* ETH_RGMII_TX_CTL */ - , /* ETH_MDIO */ - , /* ETH_MDC */ - , /* ETH_RGMII_RXD0 */ - , /* ETH_RGMII_RXD1 */ - , /* ETH_RGMII_RXD2 */ - , /* ETH_RGMII_RXD3 */ - , /* ETH_RGMII_RX_CLK */ - ; /* ETH_RGMII_RX_CTL */ - }; - }; - fmc_pins_a: fmc-0 { pins1 { pinmux = , /* FMC_NOE */ @@ -187,412 +31,6 @@ }; }; - fmc_sleep_pins_a: fmc-sleep-0 { - pins { - pinmux = , /* FMC_NOE */ - , /* FMC_NWE */ - , /* FMC_A16_FMC_CLE */ - , /* FMC_A17_FMC_ALE */ - , /* FMC_D0 */ - , /* FMC_D1 */ - , /* FMC_D2 */ - , /* FMC_D3 */ - , /* FMC_D4 */ - , /* FMC_D5 */ - , /* FMC_D6 */ - , /* FMC_D7 */ - , /* FMC_NWAIT */ - ; /* FMC_NE2_FMC_NCE */ - }; - }; - - i2c1_pins_a: i2c1-0 { - pins { - pinmux = , /* I2C1_SCL */ - ; /* I2C1_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - i2c1_pins_sleep_a: i2c1-1 { - pins { - pinmux = , /* I2C1_SCL */ - ; /* I2C1_SDA */ - }; - }; - - i2c1_pins_b: i2c1-2 { - pins { - pinmux = , /* I2C1_SCL */ - ; /* I2C1_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - i2c1_pins_sleep_b: i2c1-3 { - pins { - pinmux = , /* I2C1_SCL */ - ; /* I2C1_SDA */ - }; - }; - - i2c2_pins_a: i2c2-0 { - pins { - pinmux = , /* I2C2_SCL */ - ; /* I2C2_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - i2c2_pins_sleep_a: i2c2-1 { - pins { - pinmux = , /* I2C2_SCL */ - ; /* I2C2_SDA */ - }; - }; - - i2c2_pins_b1: i2c2-2 { - pins { - pinmux = ; /* I2C2_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - i2c2_pins_sleep_b1: i2c2-3 { - pins { - pinmux = ; /* I2C2_SDA */ - }; - }; - - i2c5_pins_a: i2c5-0 { - pins { - pinmux = , /* I2C5_SCL */ - ; /* I2C5_SDA */ - bias-disable; - drive-open-drain; - slew-rate = <0>; - }; - }; - - i2c5_pins_sleep_a: i2c5-1 { - pins { - pinmux = , /* I2C5_SCL */ - ; /* I2C5_SDA */ - - }; - }; - - i2s2_pins_a: i2s2-0 { - pins { - pinmux = , /* I2S2_SDO */ - , /* I2S2_WS */ - ; /* I2S2_CK */ - slew-rate = <1>; - drive-push-pull; - bias-disable; - }; - }; - - i2s2_pins_sleep_a: i2s2-1 { - pins { - pinmux = , /* I2S2_SDO */ - , /* I2S2_WS */ - ; /* I2S2_CK */ - }; - }; - - ltdc_pins_a: ltdc-a-0 { - pins { - pinmux = , /* LCD_CLK */ - , /* LCD_HSYNC */ - , /* LCD_VSYNC */ - , /* LCD_DE */ - , /* LCD_R0 */ - , /* LCD_R1 */ - , /* LCD_R2 */ - , /* LCD_R3 */ - , /* LCD_R4 */ - , /* LCD_R5 */ - , /* LCD_R6 */ - , /* LCD_R7 */ - , /* LCD_G0 */ - , /* LCD_G1 */ - , /* LCD_G2 */ - , /* LCD_G3 */ - , /* LCD_G4 */ - , /* LCD_G5 */ - , /* LCD_G6 */ - , /* LCD_G7 */ - , /* LCD_B0 */ - , /* LCD_B1 */ - , /* LCD_B2 */ - , /* LCD_B3 */ - , /* LCD_B4 */ - , /* LCD_B5 */ - , /* LCD_B6 */ - ; /* LCD_B7 */ - bias-disable; - drive-push-pull; - slew-rate = <1>; - }; - }; - - ltdc_pins_sleep_a: ltdc-a-1 { - pins { - pinmux = , /* LCD_CLK */ - , /* LCD_HSYNC */ - , /* LCD_VSYNC */ - , /* LCD_DE */ - , /* LCD_R0 */ - , /* LCD_R1 */ - , /* LCD_R2 */ - , /* LCD_R3 */ - , /* LCD_R4 */ - , /* LCD_R5 */ - , /* LCD_R6 */ - , /* LCD_R7 */ - , /* LCD_G0 */ - , /* LCD_G1 */ - , /* LCD_G2 */ - , /* LCD_G3 */ - , /* LCD_G4 */ - , /* LCD_G5 */ - , /* LCD_G6 */ - , /* LCD_G7 */ - , /* LCD_B0 */ - , /* LCD_B1 */ - , /* LCD_B2 */ - , /* LCD_B3 */ - , /* LCD_B4 */ - , /* LCD_B5 */ - , /* LCD_B6 */ - ; /* LCD_B7 */ - }; - }; - - ltdc_pins_b: ltdc-b-0 { - pins { - pinmux = , /* LCD_CLK */ - , /* LCD_HSYNC */ - , /* LCD_VSYNC */ - , /* LCD_DE */ - , /* LCD_R0 */ - , /* LCD_R1 */ - , /* LCD_R2 */ - , /* LCD_R3 */ - , /* LCD_R4 */ - , /* LCD_R5 */ - , /* LCD_R6 */ - , /* LCD_R7 */ - , /* LCD_G0 */ - , /* LCD_G1 */ - , /* LCD_G2 */ - , /* LCD_G3 */ - , /* LCD_G4 */ - , /* LCD_G5 */ - , /* LCD_G6 */ - , /* LCD_G7 */ - , /* LCD_B0 */ - , /* LCD_B1 */ - , /* LCD_B2 */ - , /* LCD_B3 */ - , /* LCD_B4 */ - , /* LCD_B5 */ - , /* LCD_B6 */ - ; /* LCD_B7 */ - bias-disable; - drive-push-pull; - slew-rate = <1>; - }; - }; - - ltdc_pins_sleep_b: ltdc-b-1 { - pins { - pinmux = , /* LCD_CLK */ - , /* LCD_HSYNC */ - , /* LCD_VSYNC */ - , /* LCD_DE */ - , /* LCD_R0 */ - , /* LCD_R1 */ - , /* LCD_R2 */ - , /* LCD_R3 */ - , /* LCD_R4 */ - , /* LCD_R5 */ - , /* LCD_R6 */ - , /* LCD_R7 */ - , /* LCD_G0 */ - , /* LCD_G1 */ - , /* LCD_G2 */ - , /* LCD_G3 */ - , /* LCD_G4 */ - , /* LCD_G5 */ - , /* LCD_G6 */ - , /* LCD_G7 */ - , /* LCD_B0 */ - , /* LCD_B1 */ - , /* LCD_B2 */ - , /* LCD_B3 */ - , /* LCD_B4 */ - , /* LCD_B5 */ - , /* LCD_B6 */ - ; /* LCD_B7 */ - }; - }; - - m_can1_pins_a: m-can1-0 { - pins1 { - pinmux = ; /* CAN1_TX */ - slew-rate = <1>; - drive-push-pull; - bias-disable; - }; - pins2 { - pinmux = ; /* CAN1_RX */ - bias-disable; - }; - }; - - m_can1_sleep_pins_a: m_can1-sleep-0 { - pins { - pinmux = , /* CAN1_TX */ - ; /* CAN1_RX */ - }; - }; - - pwm1_pins_a: pwm1-0 { - pins { - pinmux = , /* TIM1_CH1 */ - , /* TIM1_CH2 */ - ; /* TIM1_CH4 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm1_sleep_pins_a: pwm1-sleep-0 { - pins { - pinmux = , /* TIM1_CH1 */ - , /* TIM1_CH2 */ - ; /* TIM1_CH4 */ - }; - }; - - pwm2_pins_a: pwm2-0 { - pins { - pinmux = ; /* TIM2_CH4 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm2_sleep_pins_a: pwm2-sleep-0 { - pins { - pinmux = ; /* TIM2_CH4 */ - }; - }; - - pwm3_pins_a: pwm3-0 { - pins { - pinmux = ; /* TIM3_CH2 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm3_sleep_pins_a: pwm3-sleep-0 { - pins { - pinmux = ; /* TIM3_CH2 */ - }; - }; - - pwm4_pins_a: pwm4-0 { - pins { - pinmux = , /* TIM4_CH3 */ - ; /* TIM4_CH4 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm4_sleep_pins_a: pwm4-sleep-0 { - pins { - pinmux = , /* TIM4_CH3 */ - ; /* TIM4_CH4 */ - }; - }; - - pwm4_pins_b: pwm4-1 { - pins { - pinmux = ; /* TIM4_CH2 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm4_sleep_pins_b: pwm4-sleep-1 { - pins { - pinmux = ; /* TIM4_CH2 */ - }; - }; - - pwm5_pins_a: pwm5-0 { - pins { - pinmux = ; /* TIM5_CH2 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm5_sleep_pins_a: pwm5-sleep-0 { - pins { - pinmux = ; /* TIM5_CH2 */ - }; - }; - - pwm8_pins_a: pwm8-0 { - pins { - pinmux = ; /* TIM8_CH4 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm8_sleep_pins_a: pwm8-sleep-0 { - pins { - pinmux = ; /* TIM8_CH4 */ - }; - }; - - pwm12_pins_a: pwm12-0 { - pins { - pinmux = ; /* TIM12_CH1 */ - bias-pull-down; - drive-push-pull; - slew-rate = <0>; - }; - }; - - pwm12_sleep_pins_a: pwm12-sleep-0 { - pins { - pinmux = ; /* TIM12_CH1 */ - }; - }; - qspi_clk_pins_a: qspi-clk-0 { pins { pinmux = ; /* QSPI_CLK */ @@ -602,12 +40,6 @@ }; }; - qspi_clk_sleep_pins_a: qspi-clk-sleep-0 { - pins { - pinmux = ; /* QSPI_CLK */ - }; - }; - qspi_bk1_pins_a: qspi-bk1-0 { pins1 { pinmux = , /* QSPI_BK1_IO0 */ @@ -626,16 +58,6 @@ }; }; - qspi_bk1_sleep_pins_a: qspi-bk1-sleep-0 { - pins { - pinmux = , /* QSPI_BK1_IO0 */ - , /* QSPI_BK1_IO1 */ - , /* QSPI_BK1_IO2 */ - , /* QSPI_BK1_IO3 */ - ; /* QSPI_BK1_NCS */ - }; - }; - qspi_bk2_pins_a: qspi-bk2-0 { pins1 { pinmux = , /* QSPI_BK2_IO0 */ @@ -654,86 +76,9 @@ }; }; - qspi_bk2_sleep_pins_a: qspi-bk2-sleep-0 { + rtc_out2_rmp_pins_a: rtc-out2-rmp-pins-0 { pins { - pinmux = , /* QSPI_BK2_IO0 */ - , /* QSPI_BK2_IO1 */ - , /* QSPI_BK2_IO2 */ - , /* QSPI_BK2_IO3 */ - ; /* QSPI_BK2_NCS */ - }; - }; - - sai2a_pins_a: sai2a-0 { - pins { - pinmux = , /* SAI2_SCK_A */ - , /* SAI2_SD_A */ - , /* SAI2_FS_A */ - ; /* SAI2_MCLK_A */ - slew-rate = <0>; - drive-push-pull; - bias-disable; - }; - }; - - sai2a_sleep_pins_a: sai2a-1 { - pins { - pinmux = , /* SAI2_SCK_A */ - , /* SAI2_SD_A */ - , /* SAI2_FS_A */ - ; /* SAI2_MCLK_A */ - }; - }; - - sai2b_pins_a: sai2b-0 { - pins1 { - pinmux = , /* SAI2_SCK_B */ - , /* SAI2_FS_B */ - ; /* SAI2_MCLK_B */ - slew-rate = <0>; - drive-push-pull; - bias-disable; - }; - pins2 { - pinmux = ; /* SAI2_SD_B */ - bias-disable; - }; - }; - - sai2b_sleep_pins_a: sai2b-1 { - pins { - pinmux = , /* SAI2_SD_B */ - , /* SAI2_SCK_B */ - , /* SAI2_FS_B */ - ; /* SAI2_MCLK_B */ - }; - }; - - sai2b_pins_b: sai2b-2 { - pins { - pinmux = ; /* SAI2_SD_B */ - bias-disable; - }; - }; - - sai2b_sleep_pins_b: sai2b-3 { - pins { - pinmux = ; /* SAI2_SD_B */ - }; - }; - - sai4a_pins_a: sai4a-0 { - pins { - pinmux = ; /* SAI4_SD_A */ - slew-rate = <0>; - drive-push-pull; - bias-disable; - }; - }; - - sai4a_sleep_pins_a: sai4a-1 { - pins { - pinmux = ; /* SAI4_SD_A */ + pinmux = ; /* RTC_OUT2_RMP */ }; }; @@ -756,41 +101,6 @@ }; }; - sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 { - pins1 { - pinmux = , /* SDMMC1_D0 */ - , /* SDMMC1_D1 */ - , /* SDMMC1_D2 */ - ; /* SDMMC1_D3 */ - slew-rate = <1>; - drive-push-pull; - bias-disable; - }; - pins2 { - pinmux = ; /* SDMMC1_CK */ - slew-rate = <2>; - drive-push-pull; - bias-disable; - }; - pins3 { - pinmux = ; /* SDMMC1_CMD */ - slew-rate = <1>; - drive-open-drain; - bias-disable; - }; - }; - - sdmmc1_b4_sleep_pins_a: sdmmc1-b4-sleep-0 { - pins { - pinmux = , /* SDMMC1_D0 */ - , /* SDMMC1_D1 */ - , /* SDMMC1_D2 */ - , /* SDMMC1_D3 */ - , /* SDMMC1_CK */ - ; /* SDMMC1_CMD */ - }; - }; - sdmmc1_dir_pins_a: sdmmc1-dir-0 { pins1 { pinmux = , /* SDMMC1_D0DIR */ @@ -806,15 +116,6 @@ }; }; - sdmmc1_dir_sleep_pins_a: sdmmc1-dir-sleep-0 { - pins { - pinmux = , /* SDMMC1_D0DIR */ - , /* SDMMC1_D123DIR */ - , /* SDMMC1_CDIR */ - ; /* SDMMC1_CKIN */ - }; - }; - sdmmc2_b4_pins_a: sdmmc2-b4-0 { pins1 { pinmux = , /* SDMMC2_D0 */ @@ -834,230 +135,220 @@ }; }; - sdmmc2_b4_od_pins_a: sdmmc2-b4-od-0 { + sdmmc2_b4_pins_b: sdmmc2-b4-1 { pins1 { pinmux = , /* SDMMC2_D0 */ , /* SDMMC2_D1 */ , /* SDMMC2_D2 */ - ; /* SDMMC2_D3 */ + , /* SDMMC2_D3 */ + ; /* SDMMC2_CMD */ slew-rate = <1>; drive-push-pull; - bias-pull-up; + bias-disable; }; pins2 { pinmux = ; /* SDMMC2_CK */ slew-rate = <2>; drive-push-pull; - bias-pull-up; - }; - pins3 { - pinmux = ; /* SDMMC2_CMD */ - slew-rate = <1>; - drive-open-drain; - bias-pull-up; + bias-disable; }; }; - sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 { + sdmmc2_d47_pins_a: sdmmc2-d47-0 { pins { - pinmux = , /* SDMMC2_D0 */ - , /* SDMMC2_D1 */ - , /* SDMMC2_D2 */ - , /* SDMMC2_D3 */ - , /* SDMMC2_CK */ - ; /* SDMMC2_CMD */ + pinmux = , /* SDMMC2_D4 */ + , /* SDMMC2_D5 */ + , /* SDMMC2_D6 */ + ; /* SDMMC2_D7 */ + slew-rate = <1>; + drive-push-pull; + bias-pull-up; }; }; - sdmmc2_b4_pins_b: sdmmc2-b4-1 { + uart4_pins_a: uart4-0 { pins1 { - pinmux = , /* SDMMC2_D0 */ - , /* SDMMC2_D1 */ - , /* SDMMC2_D2 */ - , /* SDMMC2_D3 */ - ; /* SDMMC2_CMD */ - slew-rate = <1>; - drive-push-pull; + pinmux = ; /* UART4_TX */ bias-disable; + drive-push-pull; + slew-rate = <0>; }; pins2 { - pinmux = ; /* SDMMC2_CK */ - slew-rate = <2>; - drive-push-pull; + pinmux = ; /* UART4_RX */ bias-disable; }; }; - sdmmc2_b4_od_pins_b: sdmmc2-b4-od-1 { + uart4_pins_b: uart4-1 { pins1 { - pinmux = , /* SDMMC2_D0 */ - , /* SDMMC2_D1 */ - , /* SDMMC2_D2 */ - ; /* SDMMC2_D3 */ - slew-rate = <1>; - drive-push-pull; + pinmux = ; /* UART4_TX */ bias-disable; - }; - pins2 { - pinmux = ; /* SDMMC2_CK */ - slew-rate = <2>; drive-push-pull; - bias-disable; + slew-rate = <0>; }; - pins3 { - pinmux = ; /* SDMMC2_CMD */ - slew-rate = <1>; - drive-open-drain; + pins2 { + pinmux = ; /* UART4_RX */ bias-disable; }; }; - sdmmc2_d47_pins_a: sdmmc2-d47-0 { - pins { - pinmux = , /* SDMMC2_D4 */ - , /* SDMMC2_D5 */ - , /* SDMMC2_D6 */ - ; /* SDMMC2_D7 */ - slew-rate = <1>; + uart7_pins_a: uart7-0 { + pins1 { + pinmux = ; /* UART7_TX */ + bias-disable; drive-push-pull; - bias-pull-up; + slew-rate = <0>; + }; + pins2 { + pinmux = , /* UART7_RX */ + , /* UART7_CTS */ + ; /* UART7_RTS */ + bias-disable; }; }; - sdmmc2_d47_sleep_pins_a: sdmmc2-d47-sleep-0 { - pins { - pinmux = , /* SDMMC2_D4 */ - , /* SDMMC2_D5 */ - , /* SDMMC2_D6 */ - ; /* SDMMC2_D7 */ + uart7_pins_b: uart7-1 { + pins1 { + pinmux = ; /* UART7_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; /* UART7_RX */ + bias-disable; }; }; - sdmmc3_b4_pins_a: sdmmc3-b4-0 { + uart7_pins_c: uart7-2 { pins1 { - pinmux = , /* SDMMC3_D0 */ - , /* SDMMC3_D1 */ - , /* SDMMC3_D2 */ - , /* SDMMC3_D3 */ - ; /* SDMMC3_CMD */ - slew-rate = <1>; + pinmux = ; /* UART7_TX */ + bias-disable; drive-push-pull; - bias-pull-up; + slew-rate = <0>; }; pins2 { - pinmux = ; /* SDMMC3_CK */ - slew-rate = <2>; - drive-push-pull; + pinmux = ; /* UART7_RX */ bias-pull-up; }; }; - sdmmc3_b4_od_pins_a: sdmmc3-b4-od-0 { + uart8_pins_a: uart8-0 { pins1 { - pinmux = , /* SDMMC3_D0 */ - , /* SDMMC3_D1 */ - , /* SDMMC3_D2 */ - ; /* SDMMC3_D3 */ - slew-rate = <1>; + pinmux = ; /* UART8_TX */ + bias-disable; drive-push-pull; - bias-pull-up; + slew-rate = <0>; }; pins2 { - pinmux = ; /* SDMMC3_CK */ - slew-rate = <2>; - drive-push-pull; - bias-pull-up; - }; - pins3 { - pinmux = ; /* SDMMC2_CMD */ - slew-rate = <1>; - drive-open-drain; - bias-pull-up; + pinmux = ; /* UART8_RX */ + bias-disable; }; }; - sdmmc3_b4_sleep_pins_a: sdmmc3-b4-sleep-0 { - pins { - pinmux = , /* SDMMC3_D0 */ - , /* SDMMC3_D1 */ - , /* SDMMC3_D2 */ - , /* SDMMC3_D3 */ - , /* SDMMC3_CK */ - ; /* SDMMC3_CMD */ + usart2_pins_a: usart2-0 { + pins1 { + pinmux = , /* USART2_TX */ + ; /* USART2_RTS */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = , /* USART2_RX */ + ; /* USART2_CTS_NSS */ + bias-disable; }; }; - spdifrx_pins_a: spdifrx-0 { - pins { - pinmux = ; /* SPDIF_IN1 */ + usart2_pins_b: usart2-1 { + pins1 { + pinmux = , /* USART2_TX */ + ; /* USART2_RTS */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = , /* USART2_RX */ + ; /* USART2_CTS_NSS */ bias-disable; }; }; - spdifrx_sleep_pins_a: spdifrx-1 { - pins { - pinmux = ; /* SPDIF_IN1 */ + usart2_pins_c: usart2-2 { + pins1 { + pinmux = , /* USART2_TX */ + ; /* USART2_RTS */ + bias-disable; + drive-push-pull; + slew-rate = <3>; + }; + pins2 { + pinmux = , /* USART2_RX */ + ; /* USART2_CTS_NSS */ + bias-disable; }; }; - uart4_pins_a: uart4-0 { + usart3_pins_a: usart3-0 { pins1 { - pinmux = ; /* UART4_TX */ + pinmux = ; /* USART3_TX */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { - pinmux = ; /* UART4_RX */ + pinmux = ; /* USART3_RX */ bias-disable; }; }; - uart4_pins_b: uart4-1 { + usart3_pins_b: usart3-1 { pins1 { - pinmux = ; /* UART4_TX */ + pinmux = , /* USART3_TX */ + ; /* USART3_RTS */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { - pinmux = ; /* UART4_RX */ + pinmux = , /* USART3_RX */ + ; /* USART3_CTS_NSS */ bias-disable; }; }; - uart7_pins_a: uart7-0 { + usart3_pins_c: usart3-2 { pins1 { - pinmux = ; /* UART4_TX */ + pinmux = , /* USART3_TX */ + ; /* USART3_RTS */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { - pinmux = , /* UART4_RX */ - , /* UART4_CTS */ - ; /* UART4_RTS */ - bias-disable; + pinmux = , /* USART3_RX */ + ; /* USART3_CTS_NSS */ + bias-pull-up; }; }; -}; -&pinctrl_z { - i2c2_pins_b2: i2c2-0 { + usbotg_hs_pins_a: usbotg-hs-0 { pins { - pinmux = ; /* I2C2_SCL */ - bias-disable; - drive-open-drain; - slew-rate = <0>; + pinmux = ; /* OTG_ID */ }; }; - i2c2_pins_sleep_b2: i2c2-1 { + usbotg_fs_dp_dm_pins_a: usbotg-fs-dp-dm-0 { pins { - pinmux = ; /* I2C2_SCL */ + pinmux = , /* OTG_FS_DM */ + ; /* OTG_FS_DP */ }; }; +}; +&pinctrl_z { i2c4_pins_a: i2c4-0 { pins { pinmux = , /* I2C4_SCL */ @@ -1067,26 +358,4 @@ slew-rate = <0>; }; }; - - i2c4_pins_sleep_a: i2c4-1 { - pins { - pinmux = , /* I2C4_SCL */ - ; /* I2C4_SDA */ - }; - }; - - spi1_pins_a: spi1-0 { - pins1 { - pinmux = , /* SPI1_SCK */ - ; /* SPI1_MOSI */ - bias-disable; - drive-push-pull; - slew-rate = <1>; - }; - - pins2 { - pinmux = ; /* SPI1_MISO */ - bias-disable; - }; - }; }; diff --git a/core/arch/arm/dts/stm32mp151.dtsi b/core/arch/arm/dts/stm32mp151.dtsi index d8ac70292..714d94710 100644 --- a/core/arch/arm/dts/stm32mp151.dtsi +++ b/core/arch/arm/dts/stm32mp151.dtsi @@ -19,9 +19,41 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; + clocks = <&rcc CK_MPU>; + clock-names = "cpu"; + operating-points-v2 = <&cpu0_opp_table>; + nvmem-cells = <&part_number_otp>; + nvmem-cell-names = "part_number"; }; }; + cpu0_opp_table: cpu0-opp-table { + compatible = "operating-points-v2"; + opp-shared; + }; + + nvmem_layout: nvmem_layout@0 { + compatible = "st,stm32-nvmem-layout"; + + nvmem-cells = <&cfg0_otp>, + <&part_number_otp>, + <&monotonic_otp>, + <&nand_otp>, + <&uid_otp>, + <&package_otp>, + <&hw2_otp>, + <&pkh_otp>; + + nvmem-cell-names = "cfg0_otp", + "part_number_otp", + "monotonic_otp", + "nand_otp", + "uid_otp", + "package_otp", + "hw2_otp", + "pkh_otp"; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -35,15 +67,6 @@ <0xa0022000 0x2000>; }; - timer { - compatible = "arm,armv7-timer"; - interrupts = , - , - , - ; - interrupt-parent = <&intc>; - }; - clocks { clk_hse: clk-hse { #clock-cells = <0>; @@ -76,37 +99,6 @@ }; }; - thermal-zones { - cpu_thermal: cpu-thermal { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&dts>; - - trips { - cpu_alert1: cpu-alert1 { - temperature = <85000>; - hysteresis = <0>; - type = "passive"; - }; - - cpu-crit { - temperature = <120000>; - hysteresis = <0>; - type = "critical"; - }; - }; - - cooling-maps { - }; - }; - }; - - booster: regulator-booster { - compatible = "st,stm32mp1-booster"; - st,syscfg = <&syscfg>; - status = "disabled"; - }; - soc { compatible = "simple-bus"; #address-cells = <1>; @@ -114,175 +106,6 @@ interrupt-parent = <&intc>; ranges; - timers2: timer@40000000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40000000 0x400>; - clocks = <&rcc TIM2_K>; - clock-names = "int"; - dmas = <&dmamux1 18 0x400 0x1>, - <&dmamux1 19 0x400 0x1>, - <&dmamux1 20 0x400 0x1>, - <&dmamux1 21 0x400 0x1>, - <&dmamux1 22 0x400 0x1>; - dma-names = "ch1", "ch2", "ch3", "ch4", "up"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@1 { - compatible = "st,stm32h7-timer-trigger"; - reg = <1>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-timer-counter"; - status = "disabled"; - }; - }; - - timers3: timer@40001000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40001000 0x400>; - clocks = <&rcc TIM3_K>; - clock-names = "int"; - dmas = <&dmamux1 23 0x400 0x1>, - <&dmamux1 24 0x400 0x1>, - <&dmamux1 25 0x400 0x1>, - <&dmamux1 26 0x400 0x1>, - <&dmamux1 27 0x400 0x1>, - <&dmamux1 28 0x400 0x1>; - dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@2 { - compatible = "st,stm32h7-timer-trigger"; - reg = <2>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-timer-counter"; - status = "disabled"; - }; - }; - - timers4: timer@40002000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40002000 0x400>; - clocks = <&rcc TIM4_K>; - clock-names = "int"; - dmas = <&dmamux1 29 0x400 0x1>, - <&dmamux1 30 0x400 0x1>, - <&dmamux1 31 0x400 0x1>, - <&dmamux1 32 0x400 0x1>; - dma-names = "ch1", "ch2", "ch3", "ch4"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@3 { - compatible = "st,stm32h7-timer-trigger"; - reg = <3>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-timer-counter"; - status = "disabled"; - }; - }; - - timers5: timer@40003000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40003000 0x400>; - clocks = <&rcc TIM5_K>; - clock-names = "int"; - dmas = <&dmamux1 55 0x400 0x1>, - <&dmamux1 56 0x400 0x1>, - <&dmamux1 57 0x400 0x1>, - <&dmamux1 58 0x400 0x1>, - <&dmamux1 59 0x400 0x1>, - <&dmamux1 60 0x400 0x1>; - dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@4 { - compatible = "st,stm32h7-timer-trigger"; - reg = <4>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-timer-counter"; - status = "disabled"; - }; - }; - - timers6: timer@40004000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40004000 0x400>; - clocks = <&rcc TIM6_K>; - clock-names = "int"; - dmas = <&dmamux1 69 0x400 0x1>; - dma-names = "up"; - status = "disabled"; - - timer@5 { - compatible = "st,stm32h7-timer-trigger"; - reg = <5>; - status = "disabled"; - }; - }; - - timers7: timer@40005000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40005000 0x400>; - clocks = <&rcc TIM7_K>; - clock-names = "int"; - dmas = <&dmamux1 70 0x400 0x1>; - dma-names = "up"; - status = "disabled"; - - timer@6 { - compatible = "st,stm32h7-timer-trigger"; - reg = <6>; - status = "disabled"; - }; - }; - timers12: timer@40006000 { #address-cells = <1>; #size-cells = <0>; @@ -291,152 +114,7 @@ clocks = <&rcc TIM12_K>; clock-names = "int"; status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@11 { - compatible = "st,stm32h7-timer-trigger"; - reg = <11>; - status = "disabled"; - }; - }; - - timers13: timer@40007000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40007000 0x400>; - clocks = <&rcc TIM13_K>; - clock-names = "int"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@12 { - compatible = "st,stm32h7-timer-trigger"; - reg = <12>; - status = "disabled"; - }; - }; - - timers14: timer@40008000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x40008000 0x400>; - clocks = <&rcc TIM14_K>; - clock-names = "int"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@13 { - compatible = "st,stm32h7-timer-trigger"; - reg = <13>; - status = "disabled"; - }; - }; - - lptimer1: timer@40009000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-lptimer"; - reg = <0x40009000 0x400>; - clocks = <&rcc LPTIM1_K>; - clock-names = "mux"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm-lp"; - #pwm-cells = <3>; - status = "disabled"; - }; - - trigger@0 { - compatible = "st,stm32-lptimer-trigger"; - reg = <0>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-lptimer-counter"; - status = "disabled"; - }; - }; - - spi2: spi@4000b000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32h7-spi"; - reg = <0x4000b000 0x400>; - interrupts = ; - clocks = <&rcc SPI2_K>; - resets = <&rcc SPI2_R>; - dmas = <&dmamux1 39 0x400 0x05>, - <&dmamux1 40 0x400 0x05>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2s2: audio-controller@4000b000 { - compatible = "st,stm32h7-i2s"; - #sound-dai-cells = <0>; - reg = <0x4000b000 0x400>; - interrupts = ; - dmas = <&dmamux1 39 0x400 0x01>, - <&dmamux1 40 0x400 0x01>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi3: spi@4000c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32h7-spi"; - reg = <0x4000c000 0x400>; - interrupts = ; - clocks = <&rcc SPI3_K>; - resets = <&rcc SPI3_R>; - dmas = <&dmamux1 61 0x400 0x05>, - <&dmamux1 62 0x400 0x05>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2s3: audio-controller@4000c000 { - compatible = "st,stm32h7-i2s"; - #sound-dai-cells = <0>; - reg = <0x4000c000 0x400>; - interrupts = ; - dmas = <&dmamux1 61 0x400 0x01>, - <&dmamux1 62 0x400 0x01>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spdifrx: audio-controller@4000d000 { - compatible = "st,stm32h7-spdifrx"; - #sound-dai-cells = <0>; - reg = <0x4000d000 0x400>; - clocks = <&rcc SPDIF_K>; - clock-names = "kclk"; - interrupts = ; - dmas = <&dmamux1 93 0x400 0x01>, - <&dmamux1 94 0x400 0x01>; - dma-names = "rx", "rx-ctrl"; - status = "disabled"; + secure-status = "disabled"; }; usart2: serial@4000e000 { @@ -444,6 +122,7 @@ reg = <0x4000e000 0x400>; interrupts = ; clocks = <&rcc USART2_K>; + resets = <&rcc USART2_R>; status = "disabled"; }; @@ -452,14 +131,17 @@ reg = <0x4000f000 0x400>; interrupts = ; clocks = <&rcc USART3_K>; + resets = <&rcc USART3_R>; status = "disabled"; }; uart4: serial@40010000 { compatible = "st,stm32h7-uart"; reg = <0x40010000 0x400>; - interrupts = ; + interrupts-extended = <&exti 30 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART4_K>; + resets = <&rcc UART4_R>; + wakeup-source; status = "disabled"; }; @@ -468,99 +150,16 @@ reg = <0x40011000 0x400>; interrupts = ; clocks = <&rcc UART5_K>; + resets = <&rcc UART5_R>; status = "disabled"; }; - i2c1: i2c@40012000 { - compatible = "st,stm32f7-i2c"; - reg = <0x40012000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; - clocks = <&rcc I2C1_K>; - resets = <&rcc I2C1_R>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c2: i2c@40013000 { - compatible = "st,stm32f7-i2c"; - reg = <0x40013000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; - clocks = <&rcc I2C2_K>; - resets = <&rcc I2C2_R>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c3: i2c@40014000 { - compatible = "st,stm32f7-i2c"; - reg = <0x40014000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; - clocks = <&rcc I2C3_K>; - resets = <&rcc I2C3_R>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c5: i2c@40015000 { - compatible = "st,stm32f7-i2c"; - reg = <0x40015000 0x400>; - interrupt-names = "event", "error"; - interrupts = , - ; - clocks = <&rcc I2C5_K>; - resets = <&rcc I2C5_R>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - cec: cec@40016000 { - compatible = "st,stm32-cec"; - reg = <0x40016000 0x400>; - interrupts = ; - clocks = <&rcc CEC_K>, <&clk_lse>; - clock-names = "cec", "hdmi-cec"; - status = "disabled"; - }; - - dac: dac@40017000 { - compatible = "st,stm32h7-dac-core"; - reg = <0x40017000 0x400>; - clocks = <&rcc DAC12>; - clock-names = "pclk"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - - dac1: dac@1 { - compatible = "st,stm32-dac"; - #io-channels-cells = <1>; - reg = <1>; - status = "disabled"; - }; - - dac2: dac@2 { - compatible = "st,stm32-dac"; - #io-channels-cells = <1>; - reg = <2>; - status = "disabled"; - }; - }; - uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; interrupts = ; clocks = <&rcc UART7_K>; + resets = <&rcc UART7_R>; status = "disabled"; }; @@ -569,125 +168,16 @@ reg = <0x40019000 0x400>; interrupts = ; clocks = <&rcc UART8_K>; + resets = <&rcc UART8_R>; status = "disabled"; }; - timers1: timer@44000000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x44000000 0x400>; - clocks = <&rcc TIM1_K>; - clock-names = "int"; - dmas = <&dmamux1 11 0x400 0x1>, - <&dmamux1 12 0x400 0x1>, - <&dmamux1 13 0x400 0x1>, - <&dmamux1 14 0x400 0x1>, - <&dmamux1 15 0x400 0x1>, - <&dmamux1 16 0x400 0x1>, - <&dmamux1 17 0x400 0x1>; - dma-names = "ch1", "ch2", "ch3", "ch4", - "up", "trig", "com"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@0 { - compatible = "st,stm32h7-timer-trigger"; - reg = <0>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-timer-counter"; - status = "disabled"; - }; - }; - - timers8: timer@44001000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x44001000 0x400>; - clocks = <&rcc TIM8_K>; - clock-names = "int"; - dmas = <&dmamux1 47 0x400 0x1>, - <&dmamux1 48 0x400 0x1>, - <&dmamux1 49 0x400 0x1>, - <&dmamux1 50 0x400 0x1>, - <&dmamux1 51 0x400 0x1>, - <&dmamux1 52 0x400 0x1>, - <&dmamux1 53 0x400 0x1>; - dma-names = "ch1", "ch2", "ch3", "ch4", - "up", "trig", "com"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@7 { - compatible = "st,stm32h7-timer-trigger"; - reg = <7>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-timer-counter"; - status = "disabled"; - }; - }; - usart6: serial@44003000 { compatible = "st,stm32h7-uart"; reg = <0x44003000 0x400>; interrupts = ; clocks = <&rcc USART6_K>; - status = "disabled"; - }; - - spi1: spi@44004000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32h7-spi"; - reg = <0x44004000 0x400>; - interrupts = ; - clocks = <&rcc SPI1_K>; - resets = <&rcc SPI1_R>; - dmas = <&dmamux1 37 0x400 0x05>, - <&dmamux1 38 0x400 0x05>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2s1: audio-controller@44004000 { - compatible = "st,stm32h7-i2s"; - #sound-dai-cells = <0>; - reg = <0x44004000 0x400>; - interrupts = ; - dmas = <&dmamux1 37 0x400 0x01>, - <&dmamux1 38 0x400 0x01>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - spi4: spi@44005000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32h7-spi"; - reg = <0x44005000 0x400>; - interrupts = ; - clocks = <&rcc SPI4_K>; - resets = <&rcc SPI4_R>; - dmas = <&dmamux1 83 0x400 0x05>, - <&dmamux1 84 0x400 0x05>; - dma-names = "rx", "tx"; + resets = <&rcc USART6_R>; status = "disabled"; }; @@ -698,401 +188,42 @@ reg = <0x44006000 0x400>; clocks = <&rcc TIM15_K>; clock-names = "int"; - dmas = <&dmamux1 105 0x400 0x1>, - <&dmamux1 106 0x400 0x1>, - <&dmamux1 107 0x400 0x1>, - <&dmamux1 108 0x400 0x1>; - dma-names = "ch1", "up", "trig", "com"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@14 { - compatible = "st,stm32h7-timer-trigger"; - reg = <14>; - status = "disabled"; - }; - }; - - timers16: timer@44007000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x44007000 0x400>; - clocks = <&rcc TIM16_K>; - clock-names = "int"; - dmas = <&dmamux1 109 0x400 0x1>, - <&dmamux1 110 0x400 0x1>; - dma-names = "ch1", "up"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - timer@15 { - compatible = "st,stm32h7-timer-trigger"; - reg = <15>; - status = "disabled"; - }; - }; - - timers17: timer@44008000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-timers"; - reg = <0x44008000 0x400>; - clocks = <&rcc TIM17_K>; - clock-names = "int"; - dmas = <&dmamux1 111 0x400 0x1>, - <&dmamux1 112 0x400 0x1>; - dma-names = "ch1", "up"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - status = "disabled"; - }; - - timer@16 { - compatible = "st,stm32h7-timer-trigger"; - reg = <16>; - status = "disabled"; - }; - }; - - spi5: spi@44009000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32h7-spi"; - reg = <0x44009000 0x400>; - interrupts = ; - clocks = <&rcc SPI5_K>; - resets = <&rcc SPI5_R>; - dmas = <&dmamux1 85 0x400 0x05>, - <&dmamux1 86 0x400 0x05>; - dma-names = "rx", "tx"; - status = "disabled"; - }; - - sai1: sai@4400a000 { - compatible = "st,stm32h7-sai"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x4400a000 0x400>; - reg = <0x4400a000 0x4>, <0x4400a3f0 0x10>; - interrupts = ; - resets = <&rcc SAI1_R>; - status = "disabled"; - - sai1a: audio-controller@4400a004 { - #sound-dai-cells = <0>; - - compatible = "st,stm32-sai-sub-a"; - reg = <0x4 0x1c>; - clocks = <&rcc SAI1_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 87 0x400 0x01>; - status = "disabled"; - }; - - sai1b: audio-controller@4400a024 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; - clocks = <&rcc SAI1_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 88 0x400 0x01>; - status = "disabled"; - }; - }; - - sai2: sai@4400b000 { - compatible = "st,stm32h7-sai"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x4400b000 0x400>; - reg = <0x4400b000 0x4>, <0x4400b3f0 0x10>; - interrupts = ; - resets = <&rcc SAI2_R>; - status = "disabled"; - - sai2a: audio-controller@4400b004 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-a"; - reg = <0x4 0x1c>; - clocks = <&rcc SAI2_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 89 0x400 0x01>; - status = "disabled"; - }; - - sai2b: audio-controller@4400b024 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; - clocks = <&rcc SAI2_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 90 0x400 0x01>; - status = "disabled"; - }; - }; - - sai3: sai@4400c000 { - compatible = "st,stm32h7-sai"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x4400c000 0x400>; - reg = <0x4400c000 0x4>, <0x4400c3f0 0x10>; - interrupts = ; - resets = <&rcc SAI3_R>; - status = "disabled"; - - sai3a: audio-controller@4400c004 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-a"; - reg = <0x04 0x1c>; - clocks = <&rcc SAI3_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 113 0x400 0x01>; - status = "disabled"; - }; - - sai3b: audio-controller@4400c024 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; - clocks = <&rcc SAI3_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 114 0x400 0x01>; - status = "disabled"; - }; - }; - - dfsdm: dfsdm@4400d000 { - compatible = "st,stm32mp1-dfsdm"; - reg = <0x4400d000 0x800>; - clocks = <&rcc DFSDM_K>; - clock-names = "dfsdm"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - - dfsdm0: filter@0 { - compatible = "st,stm32-dfsdm-adc"; - #io-channel-cells = <1>; - reg = <0>; - interrupts = ; - dmas = <&dmamux1 101 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - - dfsdm1: filter@1 { - compatible = "st,stm32-dfsdm-adc"; - #io-channel-cells = <1>; - reg = <1>; - interrupts = ; - dmas = <&dmamux1 102 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - - dfsdm2: filter@2 { - compatible = "st,stm32-dfsdm-adc"; - #io-channel-cells = <1>; - reg = <2>; - interrupts = ; - dmas = <&dmamux1 103 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - - dfsdm3: filter@3 { - compatible = "st,stm32-dfsdm-adc"; - #io-channel-cells = <1>; - reg = <3>; - interrupts = ; - dmas = <&dmamux1 104 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - - dfsdm4: filter@4 { - compatible = "st,stm32-dfsdm-adc"; - #io-channel-cells = <1>; - reg = <4>; - interrupts = ; - dmas = <&dmamux1 91 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - - dfsdm5: filter@5 { - compatible = "st,stm32-dfsdm-adc"; - #io-channel-cells = <1>; - reg = <5>; - interrupts = ; - dmas = <&dmamux1 92 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - }; - - dma1: dma-controller@48000000 { - compatible = "st,stm32-dma"; - reg = <0x48000000 0x400>; - interrupts = , - , - , - , - , - , - , - ; - clocks = <&rcc DMA1>; - #dma-cells = <4>; - st,mem2mem; - dma-requests = <8>; - }; - - dma2: dma-controller@48001000 { - compatible = "st,stm32-dma"; - reg = <0x48001000 0x400>; - interrupts = , - , - , - , - , - , - , - ; - clocks = <&rcc DMA2>; - #dma-cells = <4>; - st,mem2mem; - dma-requests = <8>; - }; - - dmamux1: dma-router@48002000 { - compatible = "st,stm32h7-dmamux"; - reg = <0x48002000 0x1c>; - #dma-cells = <3>; - dma-requests = <128>; - dma-masters = <&dma1 &dma2>; - dma-channels = <16>; - clocks = <&rcc DMAMUX>; - }; - - adc: adc@48003000 { - compatible = "st,stm32mp1-adc-core"; - reg = <0x48003000 0x400>; - interrupts = , - ; - clocks = <&rcc ADC12>, <&rcc ADC12_K>; - clock-names = "bus", "adc"; - interrupt-controller; - st,syscfg = <&syscfg>; - #interrupt-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - - adc1: adc@0 { - compatible = "st,stm32mp1-adc"; - #io-channel-cells = <1>; - reg = <0x0>; - interrupt-parent = <&adc>; - interrupts = <0>; - dmas = <&dmamux1 9 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - - adc2: adc@100 { - compatible = "st,stm32mp1-adc"; - #io-channel-cells = <1>; - reg = <0x100>; - interrupt-parent = <&adc>; - interrupts = <1>; - dmas = <&dmamux1 10 0x400 0x01>; - dma-names = "rx"; - status = "disabled"; - }; - }; - - sdmmc3: sdmmc@48004000 { - compatible = "arm,pl18x", "arm,primecell"; - arm,primecell-periphid = <0x10153180>; - reg = <0x48004000 0x400>; - interrupts = ; - interrupt-names = "cmd_irq"; - clocks = <&rcc SDMMC3_K>; - clock-names = "apb_pclk"; - resets = <&rcc SDMMC3_R>; - cap-sd-highspeed; - cap-mmc-highspeed; - max-frequency = <120000000>; status = "disabled"; + secure-status = "disabled"; }; usbotg_hs: usb-otg@49000000 { - compatible = "snps,dwc2"; + compatible = "st,stm32mp15-hsotg", "snps,dwc2"; reg = <0x49000000 0x10000>; clocks = <&rcc USBO_K>; clock-names = "otg"; resets = <&rcc USBO_R>; reset-names = "dwc2"; interrupts = ; - g-rx-fifo-size = <256>; + g-rx-fifo-size = <512>; g-np-tx-fifo-size = <32>; - g-tx-fifo-size = <128 128 64 64 64 64 32 32>; + g-tx-fifo-size = <256 16 16 16 16 16 16 16>; dr_mode = "otg"; - status = "disabled"; - }; - - ipcc: mailbox@4c001000 { - compatible = "st,stm32mp1-ipcc"; - #mbox-cells = <1>; - reg = <0x4c001000 0x400>; - st,proc-id = <0>; - interrupts-extended = - <&intc GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, - <&intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, - <&exti 61 1>; - interrupt-names = "rx", "tx", "wakeup"; - clocks = <&rcc IPCC>; - wakeup-source; - status = "disabled"; - }; - - dcmi: dcmi@4c006000 { - compatible = "st,stm32-dcmi"; - reg = <0x4c006000 0x400>; - interrupts = ; - resets = <&rcc CAMITF_R>; - clocks = <&rcc DCMI>; - clock-names = "mclk"; - dmas = <&dmamux1 75 0x400 0x0d>; - dma-names = "tx"; + usb33d-supply = <&usb33>; status = "disabled"; }; rcc: rcc@50000000 { - compatible = "st,stm32mp1-rcc", "syscon"; + compatible = "st,stm32mp1-rcc-secure", "st,stm32mp1-rcc", "syscon"; reg = <0x50000000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; #clock-cells = <1>; #reset-cells = <1>; + interrupts = ; + secure-interrupts = ; + secure-interrupt-names = "wakeup"; }; pwr_regulators: pwr@50001000 { compatible = "st,stm32mp1,pwr-reg"; reg = <0x50001000 0x10>; + st,tzcr = <&rcc 0x0 0x1>; reg11: reg11 { regulator-name = "reg11"; @@ -1113,11 +244,35 @@ }; }; + pwr_mcu: pwr_mcu@50001014 { + compatible = "st,stm32mp151-pwr-mcu", "syscon"; + reg = <0x50001014 0x4>; + }; + + pwr_irq: pwr@50001020 { + compatible = "st,stm32mp1-pwr"; + reg = <0x50001020 0x100>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + }; + exti: interrupt-controller@5000d000 { compatible = "st,stm32mp1-exti", "syscon"; interrupt-controller; #interrupt-cells = <2>; reg = <0x5000d000 0x400>; + + /* exti_pwr is an extra interrupt controller used for + * EXTI 55 to 60. It's mapped on pwr interrupt + * controller. + */ + exti_pwr: exti-pwr { + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&pwr_irq>; + st,irq-number = <6>; + }; }; syscfg: syscon@50020000 { @@ -1126,143 +281,14 @@ clocks = <&rcc SYSCFG>; }; - lptimer2: timer@50021000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-lptimer"; - reg = <0x50021000 0x400>; - clocks = <&rcc LPTIM2_K>; - clock-names = "mux"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm-lp"; - #pwm-cells = <3>; - status = "disabled"; - }; - - trigger@1 { - compatible = "st,stm32-lptimer-trigger"; - reg = <1>; - status = "disabled"; - }; - - counter { - compatible = "st,stm32-lptimer-counter"; - status = "disabled"; - }; - }; - - lptimer3: timer@50022000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32-lptimer"; - reg = <0x50022000 0x400>; - clocks = <&rcc LPTIM3_K>; - clock-names = "mux"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm-lp"; - #pwm-cells = <3>; - status = "disabled"; - }; - - trigger@2 { - compatible = "st,stm32-lptimer-trigger"; - reg = <2>; - status = "disabled"; - }; - }; - - lptimer4: timer@50023000 { - compatible = "st,stm32-lptimer"; - reg = <0x50023000 0x400>; - clocks = <&rcc LPTIM4_K>; - clock-names = "mux"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm-lp"; - #pwm-cells = <3>; - status = "disabled"; - }; - }; - - lptimer5: timer@50024000 { - compatible = "st,stm32-lptimer"; - reg = <0x50024000 0x400>; - clocks = <&rcc LPTIM5_K>; - clock-names = "mux"; - status = "disabled"; - - pwm { - compatible = "st,stm32-pwm-lp"; - #pwm-cells = <3>; - status = "disabled"; - }; - }; - - vrefbuf: vrefbuf@50025000 { - compatible = "st,stm32-vrefbuf"; - reg = <0x50025000 0x8>; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <2500000>; - clocks = <&rcc VREF>; - status = "disabled"; - }; - - sai4: sai@50027000 { - compatible = "st,stm32h7-sai"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x50027000 0x400>; - reg = <0x50027000 0x4>, <0x500273f0 0x10>; - interrupts = ; - resets = <&rcc SAI4_R>; - status = "disabled"; - - sai4a: audio-controller@50027004 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-a"; - reg = <0x04 0x1c>; - clocks = <&rcc SAI4_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 99 0x400 0x01>; - status = "disabled"; - }; - - sai4b: audio-controller@50027024 { - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; - clocks = <&rcc SAI4_K>; - clock-names = "sai_ck"; - dmas = <&dmamux1 100 0x400 0x01>; - status = "disabled"; - }; - }; - - dts: thermal@50028000 { - compatible = "st,stm32-thermal"; - reg = <0x50028000 0x100>; - interrupts = ; - clocks = <&rcc TMPSENS>; - clock-names = "pclk"; - #thermal-sensor-cells = <0>; - status = "disabled"; - }; - hash1: hash@54002000 { compatible = "st,stm32f756-hash"; reg = <0x54002000 0x400>; interrupts = ; clocks = <&rcc HASH1>; resets = <&rcc HASH1_R>; - dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0>; - dma-names = "in"; - dma-maxburst = <2>; status = "disabled"; + secure-status = "disabled"; }; rng1: rng@54003000 { @@ -1271,35 +297,37 @@ clocks = <&rcc RNG1_K>; resets = <&rcc RNG1_R>; status = "disabled"; + secure-status = "disabled"; }; - mdma1: dma-controller@58000000 { - compatible = "st,stm32h7-mdma"; - reg = <0x58000000 0x1000>; - interrupts = ; - clocks = <&rcc MDMA>; - #dma-cells = <5>; - dma-channels = <32>; - dma-requests = <48>; - }; - - fmc: nand-controller@58002000 { - compatible = "st,stm32mp15-fmc2"; - reg = <0x58002000 0x1000>, - <0x80000000 0x1000>, - <0x88010000 0x1000>, - <0x88020000 0x1000>, - <0x81000000 0x1000>, - <0x89010000 0x1000>, - <0x89020000 0x1000>; - interrupts = ; - dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>, - <&mdma1 20 0x10 0x12000a08 0x0 0x0>, - <&mdma1 21 0x10 0x12000a0a 0x0 0x0>; - dma-names = "tx", "rx", "ecc"; + fmc: memory-controller@58002000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "st,stm32mp1-fmc2-ebi"; + reg = <0x58002000 0x1000>; clocks = <&rcc FMC_K>; resets = <&rcc FMC_R>; status = "disabled"; + + ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */ + <1 0 0x64000000 0x04000000>, /* EBI CS 2 */ + <2 0 0x68000000 0x04000000>, /* EBI CS 3 */ + <3 0 0x6c000000 0x04000000>, /* EBI CS 4 */ + <4 0 0x80000000 0x10000000>; /* NAND */ + + nand-controller@4,0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32mp1-fmc2-nfc"; + reg = <4 0x00000000 0x1000>, + <4 0x08010000 0x1000>, + <4 0x08020000 0x1000>, + <4 0x01000000 0x1000>, + <4 0x09010000 0x1000>, + <4 0x09020000 0x1000>; + interrupts = ; + status = "disabled"; + }; }; qspi: spi@58003000 { @@ -1307,18 +335,17 @@ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; - dmas = <&mdma1 22 0x10 0x100002 0x0 0x0>, - <&mdma1 22 0x10 0x100008 0x0 0x0>; - dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; sdmmc1: sdmmc@58005000 { - compatible = "arm,pl18x", "arm,primecell"; - arm,primecell-periphid = <0x10153180>; - reg = <0x58005000 0x1000>; + compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00253180>; + reg = <0x58005000 0x1000>, <0x58006000 0x1000>; interrupts = ; interrupt-names = "cmd_irq"; clocks = <&rcc SDMMC1_K>; @@ -1331,9 +358,9 @@ }; sdmmc2: sdmmc@58007000 { - compatible = "arm,pl18x", "arm,primecell"; - arm,primecell-periphid = <0x10153180>; - reg = <0x58007000 0x1000>; + compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00253180>; + reg = <0x58007000 0x1000>, <0x58008000 0x1000>; interrupts = ; interrupt-names = "cmd_irq"; clocks = <&rcc SDMMC2_K>; @@ -1345,87 +372,26 @@ status = "disabled"; }; - crc1: crc@58009000 { - compatible = "st,stm32f7-crc"; - reg = <0x58009000 0x400>; - clocks = <&rcc CRC1>; - status = "disabled"; - }; - - stmmac_axi_config_0: stmmac-axi-config { - snps,wr_osr_lmt = <0x7>; - snps,rd_osr_lmt = <0x7>; - snps,blen = <0 0 0 0 16 8 4>; - }; - - ethernet0: ethernet@5800a000 { - compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; - reg = <0x5800a000 0x2000>; - reg-names = "stmmaceth"; - interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "macirq"; - clock-names = "stmmaceth", - "mac-clk-tx", - "mac-clk-rx", - "ethstp"; - clocks = <&rcc ETHMAC>, - <&rcc ETHTX>, - <&rcc ETHRX>, - <&rcc ETHSTP>; - st,syscon = <&syscfg 0x4>; - snps,mixed-burst; - snps,pbl = <2>; - snps,en-tx-lpi-clockgating; - snps,axi-config = <&stmmac_axi_config_0>; - snps,tso; - status = "disabled"; - }; - - usbh_ohci: usbh-ohci@5800c000 { - compatible = "generic-ohci"; - reg = <0x5800c000 0x1000>; - clocks = <&rcc USBH>; - resets = <&rcc USBH_R>; - interrupts = ; - status = "disabled"; - }; - - usbh_ehci: usbh-ehci@5800d000 { - compatible = "generic-ehci"; - reg = <0x5800d000 0x1000>; - clocks = <&rcc USBH>; - resets = <&rcc USBH_R>; - interrupts = ; - companion = <&usbh_ohci>; - status = "disabled"; - }; - - ltdc: display-controller@5a001000 { - compatible = "st,stm32-ltdc"; - reg = <0x5a001000 0x400>; - interrupts = , - ; - clocks = <&rcc LTDC_PX>; - clock-names = "lcd"; - resets = <&rcc LTDC_R>; - status = "disabled"; - }; - iwdg2: watchdog@5a002000 { compatible = "st,stm32mp1-iwdg"; reg = <0x5a002000 0x400>; + secure-interrupts = ; clocks = <&rcc IWDG2>, <&rcc CK_LSI>; clock-names = "pclk", "lsi"; status = "disabled"; + secure-status = "disabled"; }; usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; + #clock-cells = <0>; compatible = "st,stm32mp1-usbphyc"; reg = <0x5a006000 0x1000>; clocks = <&rcc USBPHY_K>; resets = <&rcc USBPHY_R>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18>; status = "disabled"; usbphyc_port0: usb-phy@0 { @@ -1446,6 +412,7 @@ clocks = <&rcc USART1_K>; resets = <&rcc USART1_R>; status = "disabled"; + secure-status = "disabled"; }; spi6: spi@5c001000 { @@ -1456,22 +423,34 @@ interrupts = ; clocks = <&rcc SPI6_K>; resets = <&rcc SPI6_R>; - dmas = <&mdma1 34 0x0 0x40008 0x0 0x0>, - <&mdma1 35 0x0 0x40002 0x0 0x0>; - dma-names = "rx", "tx"; status = "disabled"; + secure-status = "disabled"; }; i2c4: i2c@5c002000 { - compatible = "st,stm32f7-i2c"; + compatible = "st,stm32mp15-i2c"; reg = <0x5c002000 0x400>; interrupt-names = "event", "error"; - interrupts = , - ; + interrupts-extended = <&exti 24 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc I2C4_K>; resets = <&rcc I2C4_R>; #address-cells = <1>; #size-cells = <0>; + st,syscfg-fmp = <&syscfg 0x4 0x8>; + wakeup-source; + status = "disabled"; + secure-status = "disabled"; + }; + + iwdg1: watchdog@5c003000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5C003000 0x400>; + interrupts = ; + clocks = <&rcc IWDG1>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + secure-status = "disabled"; }; rtc: rtc@5c004000 { @@ -1479,8 +458,9 @@ reg = <0x5c004000 0x400>; clocks = <&rcc RTCAPB>, <&rcc RTC>; clock-names = "pclk", "rtc_ck"; - interrupts = ; + interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; + secure-status = "disabled"; }; bsec: efuse@5c005000 { @@ -1488,13 +468,38 @@ reg = <0x5c005000 0x400>; #address-cells = <1>; #size-cells = <1>; + + cfg0_otp: cfg0_otp@0 { + reg = <0x0 0x1>; + }; + part_number_otp: part_number_otp@4 { + reg = <0x4 0x1>; + }; + monotonic_otp: monotonic_otp@10 { + reg = <0x10 0x4>; + }; + nand_otp: nand_otp@24 { + reg = <0x24 0x4>; + }; + uid_otp: uid_otp@34 { + reg = <0x34 0xc>; + }; + package_otp: package_otp@40 { + reg = <0x40 0x4>; + }; + hw2_otp: hw2_otp@48 { + reg = <0x48 0x4>; + }; ts_cal1: calib@5c { reg = <0x5c 0x2>; }; ts_cal2: calib@5e { reg = <0x5e 0x2>; }; - mac_addr: mac_addr@e4 { + pkh_otp: pkh_otp@60 { + reg = <0x60 0x20>; + }; + ethernet_mac_address: mac@e4 { reg = <0xe4 0x8>; st,non-secure-otp; }; @@ -1508,17 +513,32 @@ secure-status = "okay"; }; + stgen: stgen@5c008000 { + compatible = "st,stm32-stgen"; + reg = <0x5C008000 0x1000>; + }; + i2c6: i2c@5c009000 { - compatible = "st,stm32f7-i2c"; + compatible = "st,stm32mp15-i2c"; reg = <0x5c009000 0x400>; interrupt-names = "event", "error"; - interrupts = , - ; + interrupts-extended = <&exti 54 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc I2C6_K>; resets = <&rcc I2C6_R>; #address-cells = <1>; #size-cells = <0>; + st,syscfg-fmp = <&syscfg 0x4 0x20>; + wakeup-source; status = "disabled"; + secure-status = "disabled"; + }; + + tamp: tamp@5c00a000 { + compatible = "st,stm32-tamp", "simple-bus", "syscon", "simple-mfd"; + reg = <0x5c00a000 0x400>; + secure-interrupts = ; + clocks = <&rcc RTCAPB>; }; /* @@ -1675,28 +695,8 @@ st,bank-name = "GPIOZ"; st,bank-ioport = <11>; status = "disabled"; + secure-status = "disabled"; }; }; }; - - mlahb: ahb { - compatible = "st,mlahb", "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - dma-ranges = <0x00000000 0x38000000 0x10000>, - <0x10000000 0x10000000 0x60000>, - <0x30000000 0x30000000 0x60000>; - - m4_rproc: m4@10000000 { - compatible = "st,stm32mp1-m4"; - reg = <0x10000000 0x40000>, - <0x30000000 0x40000>, - <0x38000000 0x10000>; - resets = <&rcc MCU_R>; - st,syscfg-holdboot = <&rcc 0x10C 0x1>; - st,syscfg-tz = <&rcc 0x000 0x1>; - status = "disabled"; - }; - }; }; diff --git a/core/arch/arm/dts/stm32mp153.dtsi b/core/arch/arm/dts/stm32mp153.dtsi index 2d759fc60..617380a52 100644 --- a/core/arch/arm/dts/stm32mp153.dtsi +++ b/core/arch/arm/dts/stm32mp153.dtsi @@ -12,34 +12,9 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <1>; - }; - }; - - soc { - m_can1: can@4400e000 { - compatible = "bosch,m_can"; - reg = <0x4400e000 0x400>, <0x44011000 0x1400>; - reg-names = "m_can", "message_ram"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; - clock-names = "hclk", "cclk"; - bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>; - status = "disabled"; - }; - - m_can2: can@4400f000 { - compatible = "bosch,m_can"; - reg = <0x4400f000 0x400>, <0x44011000 0x2800>; - reg-names = "m_can", "message_ram"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; - clock-names = "hclk", "cclk"; - bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>; - status = "disabled"; + clocks = <&rcc CK_MPU>; + clock-names = "cpu"; + operating-points-v2 = <&cpu0_opp_table>; }; }; }; diff --git a/core/arch/arm/dts/stm32mp157.dtsi b/core/arch/arm/dts/stm32mp157.dtsi index 3f0a4a91c..c83402907 100644 --- a/core/arch/arm/dts/stm32mp157.dtsi +++ b/core/arch/arm/dts/stm32mp157.dtsi @@ -5,27 +5,3 @@ */ #include "stm32mp153.dtsi" - -/ { - soc { - gpu: gpu@59000000 { - compatible = "vivante,gc"; - reg = <0x59000000 0x800>; - interrupts = ; - clocks = <&rcc GPU>, <&rcc GPU_K>; - clock-names = "bus" ,"core"; - resets = <&rcc GPU_R>; - status = "disabled"; - }; - - dsi: dsi@5a000000 { - compatible = "st,stm32-dsi"; - reg = <0x5a000000 0x800>; - clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>; - clock-names = "pclk", "ref", "px_clk"; - resets = <&rcc DSI_R>; - reset-names = "apb"; - status = "disabled"; - }; - }; -}; diff --git a/core/arch/arm/dts/stm32mp157a-dk1.dts b/core/arch/arm/dts/stm32mp157a-dk1.dts index bc9ee69e6..5d5c0a5f7 100644 --- a/core/arch/arm/dts/stm32mp157a-dk1.dts +++ b/core/arch/arm/dts/stm32mp157a-dk1.dts @@ -7,17 +7,20 @@ /dts-v1/; #include "stm32mp157.dtsi" +#include "stm32mp15xa.dtsi" #include "stm32mp15-pinctrl.dtsi" #include "stm32mp15xxac-pinctrl.dtsi" #include "stm32mp15xx-dkx.dtsi" +#include / { model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; aliases { - ethernet0 = ðernet0; serial0 = &uart4; + serial1 = &usart3; + serial2 = &uart7; }; chosen { @@ -25,14 +28,18 @@ }; }; -&rcc { - status = "okay"; - secure-status = "disable"; -}; - -&bsec { - board_id: board_id@ec { - reg = <0xec 0x4>; - st,non-secure-otp; - }; +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; }; diff --git a/core/arch/arm/dts/stm32mp157a-ed1.dts b/core/arch/arm/dts/stm32mp157a-ed1.dts new file mode 100644 index 000000000..1527b642a --- /dev/null +++ b/core/arch/arm/dts/stm32mp157a-ed1.dts @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157.dtsi" +#include "stm32mp15xa.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include "stm32mp15xx-edx.dtsi" +#include + +/ { + model = "STMicroelectronics STM32MP157A eval daughter"; + compatible = "st,stm32mp157a-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; +}; diff --git a/core/arch/arm/dts/stm32mp157a-ev1.dts b/core/arch/arm/dts/stm32mp157a-ev1.dts new file mode 100644 index 000000000..3cb35698a --- /dev/null +++ b/core/arch/arm/dts/stm32mp157a-ev1.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157a-ed1.dts" +#include "stm32mp15xx-evx.dtsi" + +/ { + model = "STMicroelectronics STM32MP157A eval daughter on eval mother"; + compatible = "st,stm32mp157a-ev1", "st,stm32mp157a-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial0 = &uart4; + serial1 = &usart3; + }; +}; + diff --git a/core/arch/arm/dts/stm32mp157c-dk2.dts b/core/arch/arm/dts/stm32mp157c-dk2.dts index c5b226de6..ff5c4509f 100644 --- a/core/arch/arm/dts/stm32mp157c-dk2.dts +++ b/core/arch/arm/dts/stm32mp157c-dk2.dts @@ -11,14 +11,17 @@ #include "stm32mp15-pinctrl.dtsi" #include "stm32mp15xxac-pinctrl.dtsi" #include "stm32mp15xx-dkx.dtsi" +#include / { model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; aliases { - ethernet0 = ðernet0; serial0 = &uart4; + serial1 = &usart3; + serial2 = &uart7; + serial3 = &usart2; }; chosen { @@ -26,81 +29,23 @@ }; }; -&dsi { - #address-cells = <1>; - #size-cells = <0>; +&cryp1 { status = "okay"; - phy-dsi-supply = <®18>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dsi_in: endpoint { - remote-endpoint = <<dc_ep1_out>; - }; - }; - - port@1 { - reg = <1>; - dsi_out: endpoint { - remote-endpoint = <&panel_in>; - }; - }; - }; - - panel@0 { - compatible = "orisetech,otm8009a"; - reg = <0>; - reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; - power-supply = <&v3v3>; - status = "okay"; - - port { - panel_in: endpoint { - remote-endpoint = <&dsi_out>; - }; - }; - }; -}; - -&i2c1 { - touchscreen@38 { - compatible = "focaltech,ft6236"; - reg = <0x38>; - interrupts = <2 2>; - interrupt-parent = <&gpiof>; - interrupt-controller; - touchscreen-size-x = <480>; - touchscreen-size-y = <800>; - status = "okay"; - }; }; -<dc { - status = "okay"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - ltdc_ep1_out: endpoint@1 { - reg = <1>; - remote-endpoint = <&dsi_in>; - }; - }; -}; - -&rcc { - status = "okay"; - secure-status = "disable"; -}; - -&bsec { - board_id: board_id@ec { - reg = <0xec 0x4>; - st,non-secure-otp; - }; +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; }; diff --git a/core/arch/arm/dts/stm32mp157c-ed1.dts b/core/arch/arm/dts/stm32mp157c-ed1.dts index ea301c550..8d8014751 100644 --- a/core/arch/arm/dts/stm32mp157c-ed1.dts +++ b/core/arch/arm/dts/stm32mp157c-ed1.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* - * Copyright (C) STMicroelectronics 2017 - All Rights Reserved - * Author: Ludovic Barre for STMicroelectronics. + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. */ /dts-v1/; @@ -9,8 +9,8 @@ #include "stm32mp15xc.dtsi" #include "stm32mp15-pinctrl.dtsi" #include "stm32mp15xxaa-pinctrl.dtsi" -#include -#include +#include "stm32mp15xx-edx.dtsi" +#include / { model = "STMicroelectronics STM32MP157C eval daughter"; @@ -19,362 +19,25 @@ chosen { stdout-path = "serial0:115200n8"; }; - - memory@c0000000 { - device_type = "memory"; - reg = <0xC0000000 0x40000000>; - }; - - reserved-memory { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - mcuram2: mcuram2@10000000 { - compatible = "shared-dma-pool"; - reg = <0x10000000 0x40000>; - no-map; - }; - - vdev0vring0: vdev0vring0@10040000 { - compatible = "shared-dma-pool"; - reg = <0x10040000 0x1000>; - no-map; - }; - - vdev0vring1: vdev0vring1@10041000 { - compatible = "shared-dma-pool"; - reg = <0x10041000 0x1000>; - no-map; - }; - - vdev0buffer: vdev0buffer@10042000 { - compatible = "shared-dma-pool"; - reg = <0x10042000 0x4000>; - no-map; - }; - - mcuram: mcuram@30000000 { - compatible = "shared-dma-pool"; - reg = <0x30000000 0x40000>; - no-map; - }; - - retram: retram@38000000 { - compatible = "shared-dma-pool"; - reg = <0x38000000 0x10000>; - no-map; - }; - - gpu_reserved: gpu@e8000000 { - reg = <0xe8000000 0x8000000>; - no-map; - }; - }; - - aliases { - serial0 = &uart4; - }; - - sd_switch: regulator-sd_switch { - compatible = "regulator-gpio"; - regulator-name = "sd_switch"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2900000>; - regulator-type = "voltage"; - regulator-always-on; - - gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>; - gpios-states = <0>; - states = <1800000 0x1>, - <2900000 0x0>; - }; -}; - -&adc { - /* ANA0, ANA1 are dedicated pins and don't need pinctrl: only in6. */ - pinctrl-0 = <&adc1_in6_pins_a>; - pinctrl-names = "default"; - vdd-supply = <&vdd>; - vdda-supply = <&vdda>; - vref-supply = <&vdda>; - status = "disabled"; - adc1: adc@0 { - st,adc-channels = <0 1 6>; - /* 16.5 ck_cycles sampling time */ - st,min-sample-time-nsecs = <400>; - status = "okay"; - }; -}; - -&dac { - pinctrl-names = "default"; - pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; - vref-supply = <&vdda>; - status = "disabled"; - dac1: dac@1 { - status = "okay"; - }; - dac2: dac@2 { - status = "okay"; - }; -}; - -&dts { - status = "okay"; -}; - -&gpu { - contiguous-area = <&gpu_reserved>; - status = "okay"; -}; - -&i2c4 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c4_pins_a>; - i2c-scl-rising-time-ns = <185>; - i2c-scl-falling-time-ns = <20>; - status = "okay"; - /* spare dmas for other usage */ - /delete-property/dmas; - /delete-property/dma-names; - - pmic: stpmic@33 { - compatible = "st,stpmic1"; - reg = <0x33>; - interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>; - interrupt-controller; - #interrupt-cells = <2>; - status = "okay"; - - regulators { - compatible = "st,stpmic1-regulators"; - ldo1-supply = <&v3v3>; - ldo2-supply = <&v3v3>; - ldo3-supply = <&vdd_ddr>; - ldo5-supply = <&v3v3>; - ldo6-supply = <&v3v3>; - pwr_sw1-supply = <&bst_out>; - pwr_sw2-supply = <&bst_out>; - - vddcore: buck1 { - regulator-name = "vddcore"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - regulator-initial-mode = <0>; - regulator-over-current-protection; - }; - - vdd_ddr: buck2 { - regulator-name = "vdd_ddr"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - regulator-initial-mode = <0>; - regulator-over-current-protection; - }; - - vdd: buck3 { - regulator-name = "vdd"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - st,mask-reset; - regulator-initial-mode = <0>; - regulator-over-current-protection; - }; - - v3v3: buck4 { - regulator-name = "v3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-over-current-protection; - regulator-initial-mode = <0>; - }; - - vdda: ldo1 { - regulator-name = "vdda"; - regulator-min-microvolt = <2900000>; - regulator-max-microvolt = <2900000>; - interrupts = ; - }; - - v2v8: ldo2 { - regulator-name = "v2v8"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - interrupts = ; - }; - - vtt_ddr: ldo3 { - regulator-name = "vtt_ddr"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <750000>; - regulator-always-on; - regulator-over-current-protection; - }; - - vdd_usb: ldo4 { - regulator-name = "vdd_usb"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - interrupts = ; - }; - - vdd_sd: ldo5 { - regulator-name = "vdd_sd"; - regulator-min-microvolt = <2900000>; - regulator-max-microvolt = <2900000>; - interrupts = ; - regulator-boot-on; - }; - - v1v8: ldo6 { - regulator-name = "v1v8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - interrupts = ; - }; - - vref_ddr: vref_ddr { - regulator-name = "vref_ddr"; - regulator-always-on; - regulator-over-current-protection; - }; - - bst_out: boost { - regulator-name = "bst_out"; - interrupts = ; - }; - - vbus_otg: pwr_sw1 { - regulator-name = "vbus_otg"; - interrupts = ; - }; - - vbus_sw: pwr_sw2 { - regulator-name = "vbus_sw"; - interrupts = ; - regulator-active-discharge = <1>; - }; - }; - - onkey { - compatible = "st,stpmic1-onkey"; - interrupts = , ; - interrupt-names = "onkey-falling", "onkey-rising"; - power-off-time-sec = <10>; - status = "okay"; - }; - - watchdog { - compatible = "st,stpmic1-wdt"; - status = "disabled"; - }; - }; -}; - -&ipcc { - status = "okay"; -}; - -&iwdg2 { - timeout-sec = <32>; - status = "okay"; -}; - -&m4_rproc { - memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, - <&vdev0vring1>, <&vdev0buffer>; - mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; - mbox-names = "vq0", "vq1", "shutdown"; - interrupt-parent = <&exti>; - interrupts = <68 1>; - status = "okay"; -}; - -&pwr_regulators { - vdd-supply = <&vdd>; - vdd_3v3_usbfs-supply = <&vdd_usb>; -}; - -&rng1 { - status = "okay"; }; -&rtc { +&cryp1 { status = "okay"; }; -&sdmmc1 { - pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; - pinctrl-1 = <&sdmmc1_b4_od_pins_a &sdmmc1_dir_pins_a>; - pinctrl-2 = <&sdmmc1_b4_sleep_pins_a &sdmmc1_dir_sleep_pins_a>; - broken-cd; - st,sig-dir; - st,neg-edge; - st,use-ckin; - bus-width = <4>; - vmmc-supply = <&vdd_sd>; - vqmmc-supply = <&sd_switch>; - status = "okay"; -}; - -&sdmmc2 { - pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; - pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>; - pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>; - non-removable; - no-sd; - no-sdio; - st,neg-edge; - bus-width = <8>; - vmmc-supply = <&v3v3>; - vqmmc-supply = <&v3v3>; - mmc-ddr-3_3v; - status = "okay"; -}; - -&timers6 { - status = "okay"; - /* spare dmas for other usage */ - /delete-property/dmas; - /delete-property/dma-names; - timer@5 { - status = "okay"; - }; -}; - -&uart4 { - pinctrl-names = "default"; - pinctrl-0 = <&uart4_pins_a>; - status = "okay"; -}; - -&usbphyc_port0 { - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; -}; - -&usbphyc_port1 { - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; -}; - -&rcc { - status = "okay"; - secure-status = "disable"; -}; - -&bsec { - board_id: board_id@ec { - reg = <0xec 0x4>; - st,non-secure-otp; - }; +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; }; diff --git a/core/arch/arm/dts/stm32mp157c-ev1.dts b/core/arch/arm/dts/stm32mp157c-ev1.dts index fd8c958b0..d12d30093 100644 --- a/core/arch/arm/dts/stm32mp157c-ev1.dts +++ b/core/arch/arm/dts/stm32mp157c-ev1.dts @@ -1,13 +1,12 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* - * Copyright (C) STMicroelectronics 2017 - All Rights Reserved - * Author: Ludovic Barre for STMicroelectronics. + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. */ /dts-v1/; #include "stm32mp157c-ed1.dts" -#include -/* #include Remove due to BSD license issue */ +#include "stm32mp15xx-evx.dtsi" / { model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; @@ -19,346 +18,6 @@ aliases { serial0 = &uart4; - ethernet0 = ðernet0; + serial1 = &usart3; }; - - clocks { - clk_ext_camera: clk-ext-camera { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - }; - }; - - joystick { - compatible = "gpio-keys"; - pinctrl-0 = <&joystick_pins>; - pinctrl-names = "default"; - button-0 { - label = "JoySel"; - /* linux,code = ; BSD license issue */ - interrupt-parent = <&stmfx_pinctrl>; - interrupts = <0 IRQ_TYPE_EDGE_RISING>; - }; - button-1 { - label = "JoyDown"; - /* linux,code = ; BSD license issue */ - interrupt-parent = <&stmfx_pinctrl>; - interrupts = <1 IRQ_TYPE_EDGE_RISING>; - }; - button-2 { - label = "JoyLeft"; - /* linux,code = ; BSD license issue */ - interrupt-parent = <&stmfx_pinctrl>; - interrupts = <2 IRQ_TYPE_EDGE_RISING>; - }; - button-3 { - label = "JoyRight"; - /* linux,code = ; BSD license issue */ - interrupt-parent = <&stmfx_pinctrl>; - interrupts = <3 IRQ_TYPE_EDGE_RISING>; - }; - button-4 { - label = "JoyUp"; - /* linux,code = ; BSD license issue */ - interrupt-parent = <&stmfx_pinctrl>; - interrupts = <4 IRQ_TYPE_EDGE_RISING>; - }; - }; - - panel_backlight: panel-backlight { - compatible = "gpio-backlight"; - gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; - default-on; - status = "okay"; - }; -}; - -&cec { - pinctrl-names = "default"; - pinctrl-0 = <&cec_pins_a>; - status = "okay"; -}; - -&dcmi { - status = "okay"; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&dcmi_pins_a>; - pinctrl-1 = <&dcmi_sleep_pins_a>; - - port { - dcmi_0: endpoint { - remote-endpoint = <&ov5640_0>; - bus-width = <8>; - hsync-active = <0>; - vsync-active = <0>; - pclk-sample = <1>; - }; - }; -}; - -&dsi { - #address-cells = <1>; - #size-cells = <0>; - phy-dsi-supply = <®18>; - status = "okay"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dsi_in: endpoint { - remote-endpoint = <<dc_ep0_out>; - }; - }; - - port@1 { - reg = <1>; - dsi_out: endpoint { - remote-endpoint = <&dsi_panel_in>; - }; - }; - }; - - panel-dsi@0 { - compatible = "raydium,rm68200"; - reg = <0>; - reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; - backlight = <&panel_backlight>; - power-supply = <&v3v3>; - status = "okay"; - - port { - dsi_panel_in: endpoint { - remote-endpoint = <&dsi_out>; - }; - }; - }; -}; - -ðernet0 { - status = "okay"; - pinctrl-0 = <ðernet0_rgmii_pins_a>; - pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; - pinctrl-names = "default", "sleep"; - phy-mode = "rgmii-id"; - max-speed = <1000>; - phy-handle = <&phy0>; - - mdio0 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "snps,dwmac-mdio"; - phy0: ethernet-phy@0 { - reg = <0>; - }; - }; -}; - -&fmc { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&fmc_pins_a>; - pinctrl-1 = <&fmc_sleep_pins_a>; - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - nand-on-flash-bbt; - #address-cells = <1>; - #size-cells = <1>; - }; -}; - -&i2c2 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c2_pins_a>; - i2c-scl-rising-time-ns = <185>; - i2c-scl-falling-time-ns = <20>; - status = "okay"; - - ov5640: camera@3c { - compatible = "ovti,ov5640"; - reg = <0x3c>; - clocks = <&clk_ext_camera>; - clock-names = "xclk"; - DOVDD-supply = <&v2v8>; - powerdown-gpios = <&stmfx_pinctrl 18 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>; - reset-gpios = <&stmfx_pinctrl 19 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; - rotation = <180>; - status = "okay"; - - port { - ov5640_0: endpoint { - remote-endpoint = <&dcmi_0>; - bus-width = <8>; - data-shift = <2>; /* lines 9:2 are used */ - hsync-active = <0>; - vsync-active = <0>; - pclk-sample = <1>; - }; - }; - }; - - stmfx: stmfx@42 { - compatible = "st,stmfx-0300"; - reg = <0x42>; - interrupts = <8 IRQ_TYPE_EDGE_RISING>; - interrupt-parent = <&gpioi>; - vdd-supply = <&v3v3>; - - stmfx_pinctrl: stmfx-pin-controller { - compatible = "st,stmfx-0300-pinctrl"; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-ranges = <&stmfx_pinctrl 0 0 24>; - - joystick_pins: joystick { - pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; - bias-pull-down; - }; - }; - }; -}; - -&i2c5 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c5_pins_a>; - i2c-scl-rising-time-ns = <185>; - i2c-scl-falling-time-ns = <20>; - status = "okay"; -}; - -<dc { - status = "okay"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - ltdc_ep0_out: endpoint@0 { - reg = <0>; - remote-endpoint = <&dsi_in>; - }; - }; -}; - -&m_can1 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&m_can1_pins_a>; - pinctrl-1 = <&m_can1_sleep_pins_a>; - status = "okay"; -}; - -&qspi { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>; - pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a &qspi_bk2_sleep_pins_a>; - reg = <0x58003000 0x1000>, <0x70000000 0x4000000>; - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - - flash0: mx66l51235l@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-rx-bus-width = <4>; - spi-max-frequency = <108000000>; - #address-cells = <1>; - #size-cells = <1>; - }; - - flash1: mx66l51235l@1 { - compatible = "jedec,spi-nor"; - reg = <1>; - spi-rx-bus-width = <4>; - spi-max-frequency = <108000000>; - #address-cells = <1>; - #size-cells = <1>; - }; -}; - -&sdmmc3 { - pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc3_b4_pins_a>; - pinctrl-1 = <&sdmmc3_b4_od_pins_a>; - pinctrl-2 = <&sdmmc3_b4_sleep_pins_a>; - broken-cd; - st,neg-edge; - bus-width = <4>; - vmmc-supply = <&v3v3>; - status = "disabled"; -}; - -&spi1 { - pinctrl-names = "default"; - pinctrl-0 = <&spi1_pins_a>; - status = "disabled"; -}; - -&timers2 { - /* spare dmas for other usage (un-delete to enable pwm capture) */ - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm2_pins_a>; - pinctrl-1 = <&pwm2_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; - }; - timer@1 { - status = "okay"; - }; -}; - -&timers8 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm8_pins_a>; - pinctrl-1 = <&pwm8_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; - }; - timer@7 { - status = "okay"; - }; -}; - -&timers12 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm12_pins_a>; - pinctrl-1 = <&pwm12_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; - }; - timer@11 { - status = "okay"; - }; -}; - -&usbh_ehci { - phys = <&usbphyc_port0>; - status = "okay"; -}; - -&usbotg_hs { - dr_mode = "peripheral"; - phys = <&usbphyc_port1 0>; - phy-names = "usb2-phy"; - status = "okay"; -}; - -&usbphyc { - status = "okay"; }; diff --git a/core/arch/arm/dts/stm32mp157d-dk1.dts b/core/arch/arm/dts/stm32mp157d-dk1.dts new file mode 100644 index 000000000..79297b831 --- /dev/null +++ b/core/arch/arm/dts/stm32mp157d-dk1.dts @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +/dts-v1/; + +#include "stm32mp157.dtsi" +#include "stm32mp15xd.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxac-pinctrl.dtsi" +#include "stm32mp15xx-dkx.dtsi" +#include + +/ { + model = "STMicroelectronics STM32MP157D-DK1 Discovery Board"; + compatible = "st,stm32mp157d-dk1", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + serial1 = &usart3; + serial2 = &uart7; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; +}; diff --git a/core/arch/arm/dts/stm32mp157d-ed1.dts b/core/arch/arm/dts/stm32mp157d-ed1.dts new file mode 100644 index 000000000..2c67ec0ac --- /dev/null +++ b/core/arch/arm/dts/stm32mp157d-ed1.dts @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157.dtsi" +#include "stm32mp15xd.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include "stm32mp15xx-edx.dtsi" +#include + +/ { + model = "STMicroelectronics STM32MP157D eval daughter"; + compatible = "st,stm32mp157d-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + + +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; +}; diff --git a/core/arch/arm/dts/stm32mp157d-ev1.dts b/core/arch/arm/dts/stm32mp157d-ev1.dts new file mode 100644 index 000000000..4a40f5fe5 --- /dev/null +++ b/core/arch/arm/dts/stm32mp157d-ev1.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157d-ed1.dts" +#include "stm32mp15xx-evx.dtsi" + +/ { + model = "STMicroelectronics STM32MP157D eval daughter on eval mother"; + compatible = "st,stm32mp157d-ev1", "st,stm32mp157d-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial0 = &uart4; + serial1 = &usart3; + }; +}; diff --git a/core/arch/arm/dts/stm32mp157f-dk2.dts b/core/arch/arm/dts/stm32mp157f-dk2.dts new file mode 100644 index 000000000..680ca0f6e --- /dev/null +++ b/core/arch/arm/dts/stm32mp157f-dk2.dts @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +/dts-v1/; + +#include "stm32mp157.dtsi" +#include "stm32mp15xf.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxac-pinctrl.dtsi" +#include "stm32mp15xx-dkx.dtsi" +#include + +/ { + model = "STMicroelectronics STM32MP157F-DK2 Discovery Board"; + compatible = "st,stm32mp157f-dk2", "st,stm32mp157"; + + aliases { + serial0 = &uart4; + serial1 = &usart3; + serial2 = &uart7; + serial3 = &usart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&cryp1 { + status = "okay"; +}; + +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; +}; diff --git a/core/arch/arm/dts/stm32mp157f-ed1.dts b/core/arch/arm/dts/stm32mp157f-ed1.dts new file mode 100644 index 000000000..1aa26cdbb --- /dev/null +++ b/core/arch/arm/dts/stm32mp157f-ed1.dts @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157.dtsi" +#include "stm32mp15xf.dtsi" +#include "stm32mp15-pinctrl.dtsi" +#include "stm32mp15xxaa-pinctrl.dtsi" +#include "stm32mp15xx-edx.dtsi" +#include + +/ { + model = "STMicroelectronics STM32MP157F eval daughter"; + compatible = "st,stm32mp157f-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&cryp1 { + status = "okay"; +}; + +&etzpc { + st,decprot = < + DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) + DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_NS_R_S_W, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK) + DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK) + >; +}; diff --git a/core/arch/arm/dts/stm32mp157f-ev1.dts b/core/arch/arm/dts/stm32mp157f-ev1.dts new file mode 100644 index 000000000..caf5dfe11 --- /dev/null +++ b/core/arch/arm/dts/stm32mp157f-ev1.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157f-ed1.dts" +#include "stm32mp15xx-evx.dtsi" + +/ { + model = "STMicroelectronics STM32MP157F eval daughter on eval mother"; + compatible = "st,stm32mp157f-ev1", "st,stm32mp157f-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial0 = &uart4; + serial1 = &usart3; + }; +}; diff --git a/core/arch/arm/dts/stm32mp15xa.dtsi b/core/arch/arm/dts/stm32mp15xa.dtsi new file mode 100644 index 000000000..5ed7e594f --- /dev/null +++ b/core/arch/arm/dts/stm32mp15xa.dtsi @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +&cpu0_opp_table { + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + opp-microvolt = <1200000>; + opp-supported-hw = <0x1>; + }; +}; diff --git a/core/arch/arm/dts/stm32mp15xc.dtsi b/core/arch/arm/dts/stm32mp15xc.dtsi index b06a55a2f..68d822d8c 100644 --- a/core/arch/arm/dts/stm32mp15xc.dtsi +++ b/core/arch/arm/dts/stm32mp15xc.dtsi @@ -4,6 +4,8 @@ * Author: Alexandre Torgue for STMicroelectronics. */ +#include "stm32mp15xa.dtsi" + / { soc { cryp1: cryp@54001000 { @@ -13,6 +15,7 @@ clocks = <&rcc CRYP1>; resets = <&rcc CRYP1_R>; status = "disabled"; + secure-status = "disabled"; }; }; }; diff --git a/core/arch/arm/dts/stm32mp15xd.dtsi b/core/arch/arm/dts/stm32mp15xd.dtsi new file mode 100644 index 000000000..18b05ee38 --- /dev/null +++ b/core/arch/arm/dts/stm32mp15xd.dtsi @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +&cpu0_opp_table { + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1350000>; + opp-supported-hw = <0x2>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <1200000>; + opp-supported-hw = <0x2>; + opp-suspend; + }; +}; diff --git a/core/arch/arm/dts/stm32mp15xf.dtsi b/core/arch/arm/dts/stm32mp15xf.dtsi new file mode 100644 index 000000000..526a1627c --- /dev/null +++ b/core/arch/arm/dts/stm32mp15xf.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + */ + +#include "stm32mp15xd.dtsi" + +/ { + soc { + cryp1: cryp@54001000 { + compatible = "st,stm32mp1-cryp"; + reg = <0x54001000 0x400>; + interrupts = ; + clocks = <&rcc CRYP1>; + resets = <&rcc CRYP1_R>; + status = "disabled"; + secure-status = "disabled"; + }; + }; +}; diff --git a/core/arch/arm/dts/stm32mp15xx-dkx.dtsi b/core/arch/arm/dts/stm32mp15xx-dkx.dtsi index f6672e87a..236cff932 100644 --- a/core/arch/arm/dts/stm32mp15xx-dkx.dtsi +++ b/core/arch/arm/dts/stm32mp15xx-dkx.dtsi @@ -4,8 +4,8 @@ * Author: Alexandre Torgue for STMicroelectronics. */ -#include -#include +#include +#include / { memory@c0000000 { @@ -13,206 +13,36 @@ reg = <0xc0000000 0x20000000>; }; - reserved-memory { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - mcuram2: mcuram2@10000000 { - compatible = "shared-dma-pool"; - reg = <0x10000000 0x40000>; - no-map; - }; - - vdev0vring0: vdev0vring0@10040000 { - compatible = "shared-dma-pool"; - reg = <0x10040000 0x1000>; - no-map; - }; - - vdev0vring1: vdev0vring1@10041000 { - compatible = "shared-dma-pool"; - reg = <0x10041000 0x1000>; - no-map; - }; - - vdev0buffer: vdev0buffer@10042000 { - compatible = "shared-dma-pool"; - reg = <0x10042000 0x4000>; - no-map; - }; - - mcuram: mcuram@30000000 { - compatible = "shared-dma-pool"; - reg = <0x30000000 0x40000>; - no-map; - }; - - retram: retram@38000000 { - compatible = "shared-dma-pool"; - reg = <0x38000000 0x10000>; - no-map; - }; - - gpu_reserved: gpu@d4000000 { - reg = <0xd4000000 0x4000000>; - no-map; - }; - }; - - led { - compatible = "gpio-leds"; - blue { - label = "heartbeat"; - gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "heartbeat"; - default-state = "off"; - }; - }; - - sound { - compatible = "audio-graph-card"; - label = "STM32MP1-DK"; - routing = - "Playback" , "MCLK", - "Capture" , "MCLK", - "MICL" , "Mic Bias"; - dais = <&sai2a_port &sai2b_port &i2s2_port>; - status = "okay"; + vin: vin { + compatible = "regulator-fixed"; + regulator-name = "vin"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; }; }; -&adc { - pinctrl-names = "default"; - pinctrl-0 = <&adc12_ain_pins_a>, <&adc12_usb_cc_pins_a>; - vdd-supply = <&vdd>; - vdda-supply = <&vdd>; - vref-supply = <&vrefbuf>; - status = "disabled"; - adc1: adc@0 { - /* - * Type-C USB_PWR_CC1 & USB_PWR_CC2 on in18 & in19. - * Use at least 5 * RC time, e.g. 5 * (Rp + Rd) * C: - * 5 * (56 + 47kOhms) * 5pF => 2.5us. - * Use arbitrary margin here (e.g. 5us). - */ - st,min-sample-time-nsecs = <5000>; - /* AIN connector, USB Type-C CC1 & CC2 */ - st,adc-channels = <0 1 6 13 18 19>; - status = "okay"; - }; - adc2: adc@100 { - /* AIN connector, USB Type-C CC1 & CC2 */ - st,adc-channels = <0 1 2 6 18 19>; - st,min-sample-time-nsecs = <5000>; - status = "okay"; +&bsec { + board_id: board_id@ec { + reg = <0xec 0x4>; + st,non-secure-otp; }; }; -&cec { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&cec_pins_b>; - pinctrl-1 = <&cec_pins_sleep_b>; - status = "okay"; +&clk_hse { + st,digbypass; }; -ðernet0 { - status = "okay"; - pinctrl-0 = <ðernet0_rgmii_pins_a>; - pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; - pinctrl-names = "default", "sleep"; - phy-mode = "rgmii-id"; - max-speed = <1000>; - phy-handle = <&phy0>; - - mdio0 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "snps,dwmac-mdio"; - phy0: ethernet-phy@0 { - reg = <0>; - }; - }; +&cpu0{ + cpu-supply = <&vddcore>; }; -&gpu { - contiguous-area = <&gpu_reserved>; - status = "okay"; +&cpu1{ + cpu-supply = <&vddcore>; }; -&i2c1 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&i2c1_pins_a>; - pinctrl-1 = <&i2c1_pins_sleep_a>; - i2c-scl-rising-time-ns = <100>; - i2c-scl-falling-time-ns = <7>; +&hash1 { status = "okay"; - /delete-property/dmas; - /delete-property/dma-names; - - hdmi-transmitter@39 { - compatible = "sil,sii9022"; - reg = <0x39>; - iovcc-supply = <&v3v3_hdmi>; - cvcc12-supply = <&v1v2_hdmi>; - reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>; - interrupts = <1 IRQ_TYPE_EDGE_FALLING>; - interrupt-parent = <&gpiog>; - #sound-dai-cells = <0>; - status = "okay"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - sii9022_in: endpoint { - remote-endpoint = <<dc_ep0_out>; - }; - }; - - port@3 { - reg = <3>; - sii9022_tx_endpoint: endpoint { - remote-endpoint = <&i2s2_endpoint>; - }; - }; - }; - }; - - cs42l51: cs42l51@4a { - compatible = "cirrus,cs42l51"; - reg = <0x4a>; - #sound-dai-cells = <0>; - VL-supply = <&v3v3>; - VD-supply = <&v1v8_audio>; - VA-supply = <&v1v8_audio>; - VAHP-supply = <&v1v8_audio>; - reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>; - clocks = <&sai2a>; - clock-names = "MCLK"; - status = "okay"; - - cs42l51_port: port { - #address-cells = <1>; - #size-cells = <0>; - - cs42l51_tx_endpoint: endpoint@0 { - reg = <0>; - remote-endpoint = <&sai2a_endpoint>; - frame-master; - bitclock-master; - }; - - cs42l51_rx_endpoint: endpoint@1 { - reg = <1>; - remote-endpoint = <&sai2b_endpoint>; - frame-master; - bitclock-master; - }; - }; - }; }; &i2c4 { @@ -220,24 +50,33 @@ pinctrl-0 = <&i2c4_pins_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; + clock-frequency = <400000>; status = "okay"; - /* spare dmas for other usage */ - /delete-property/dmas; - /delete-property/dma-names; + secure-status = "okay"; pmic: stpmic@33 { compatible = "st,stpmic1"; reg = <0x33>; - interrupts-extended = <&gpioa 0 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; interrupt-controller; #interrupt-cells = <2>; status = "okay"; + secure-status = "okay"; regulators { compatible = "st,stpmic1-regulators"; + buck1-supply = <&vin>; + buck2-supply = <&vin>; + buck3-supply = <&vin>; + buck4-supply = <&vin>; ldo1-supply = <&v3v3>; + ldo2-supply = <&vin>; ldo3-supply = <&vdd_ddr>; + ldo4-supply = <&vin>; + ldo5-supply = <&vin>; ldo6-supply = <&v3v3>; + vref_ddr-supply = <&vin>; + boost-supply = <&vin>; pwr_sw1-supply = <&bst_out>; pwr_sw2-supply = <&bst_out>; @@ -283,7 +122,6 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-always-on; - interrupts = ; }; v3v3_hdmi: ldo2 { @@ -291,7 +129,6 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; - interrupts = ; }; vtt_ddr: ldo3 { @@ -304,16 +141,12 @@ vdd_usb: ldo4 { regulator-name = "vdd_usb"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - interrupts = ; }; vdda: ldo5 { regulator-name = "vdda"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; - interrupts = ; regulator-boot-on; }; @@ -322,7 +155,6 @@ regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-always-on; - interrupts = ; }; vref_ddr: vref_ddr { @@ -331,295 +163,339 @@ regulator-over-current-protection; }; - bst_out: boost { + bst_out: boost { regulator-name = "bst_out"; - interrupts = ; - }; + }; vbus_otg: pwr_sw1 { regulator-name = "vbus_otg"; - interrupts = ; - }; + }; - vbus_sw: pwr_sw2 { + vbus_sw: pwr_sw2 { regulator-name = "vbus_sw"; - interrupts = ; regulator-active-discharge = <1>; - }; - }; - - onkey { - compatible = "st,stpmic1-onkey"; - interrupts = , ; - interrupt-names = "onkey-falling", "onkey-rising"; - power-off-time-sec = <10>; - status = "okay"; - }; - - watchdog { - compatible = "st,stpmic1-wdt"; - status = "disabled"; + }; }; }; }; -&i2s2 { - clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>; - clock-names = "pclk", "i2sclk", "x8k", "x11k"; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&i2s2_pins_a>; - pinctrl-1 = <&i2s2_pins_sleep_a>; +&iwdg2 { + timeout-sec = <32>; + secure-timeout-sec = <5>; status = "okay"; - - i2s2_port: port { - i2s2_endpoint: endpoint { - remote-endpoint = <&sii9022_tx_endpoint>; - format = "i2s"; - mclk-fs = <256>; - }; - }; + secure-status = "okay"; }; -&ipcc { - status = "okay"; +&nvmem_layout { + nvmem-cells = <&cfg0_otp>, + <&part_number_otp>, + <&monotonic_otp>, + <&nand_otp>, + <&uid_otp>, + <&package_otp>, + <&hw2_otp>, + <&pkh_otp>, + <&board_id>; + + nvmem-cell-names = "cfg0_otp", + "part_number_otp", + "monotonic_otp", + "nand_otp", + "uid_otp", + "package_otp", + "hw2_otp", + "pkh_otp", + "board_id"; }; -&iwdg2 { - timeout-sec = <32>; - status = "okay"; +&pwr_regulators { + system_suspend_supported_soc_modes = < + STM32_PM_CSLEEP_RUN + STM32_PM_CSTOP_ALLOW_LP_STOP + STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR + >; + system_off_soc_mode = ; + vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; }; -<dc { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <<dc_pins_a>; - pinctrl-1 = <<dc_pins_sleep_a>; - status = "okay"; +&rcc { + st,hsi-cal; + st,csi-cal; + st,cal-sec = <60>; + st,clksrc = < + CLK_MPU_PLL1P + CLK_AXI_PLL2P + CLK_MCU_PLL3P + CLK_PLL12_HSE + CLK_PLL3_HSE + CLK_PLL4_HSE + CLK_RTC_LSE + CLK_MCO1_DISABLED + CLK_MCO2_DISABLED + >; + + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ + 0 /*MCU*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ + 1 /*APB4*/ + 2 /*APB5*/ + 23 /*RTC*/ + 0 /*MCO1*/ + 0 /*MCO2*/ + >; + + st,pkcs = < + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK + CLK_ETH_DISABLED + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE + CLK_USBPHY_HSE + CLK_SPI2S1_PLL3Q + CLK_SPI2S23_PLL3Q + CLK_SPI45_HSI + CLK_SPI6_HSI + CLK_I2C46_HSI + CLK_SDMMC3_PLL4P + CLK_USBO_USBPHY + CLK_ADC_CKPER + CLK_CEC_LSE + CLK_I2C12_HSI + CLK_I2C35_HSI + CLK_UART1_HSI + CLK_UART24_HSI + CLK_UART35_HSI + CLK_UART6_HSI + CLK_UART78_HSI + CLK_SPDIF_PLL4P + CLK_FDCAN_PLL4R + CLK_SAI1_PLL3Q + CLK_SAI2_PLL3Q + CLK_SAI3_PLL3Q + CLK_SAI4_PLL3Q + CLK_RNG1_LSI + CLK_RNG2_LSI + CLK_LPTIM1_PCLK1 + CLK_LPTIM23_PCLK3 + CLK_LPTIM45_LSE + >; + + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + compatible = "st,stm32mp1-pll"; + reg = <1>; + cfg = <2 65 1 0 0 PQR(1,1,1)>; + frac = <0x1400>; + }; - port { - #address-cells = <1>; - #size-cells = <0>; + /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ + pll3: st,pll@2 { + compatible = "st,stm32mp1-pll"; + reg = <2>; + cfg = <1 33 1 16 36 PQR(1,1,1)>; + frac = <0x1a04>; + }; - ltdc_ep0_out: endpoint@0 { - reg = <0>; - remote-endpoint = <&sii9022_in>; - }; + /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ + pll4: st,pll@3 { + compatible = "st,stm32mp1-pll"; + reg = <3>; + cfg = <3 98 5 7 7 PQR(1,1,1)>; }; }; -&m4_rproc { - memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, - <&vdev0vring1>, <&vdev0buffer>; - mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; - mbox-names = "vq0", "vq1", "shutdown"; - interrupt-parent = <&exti>; - interrupts = <68 1>; +&rng1 { status = "okay"; + secure-status = "okay"; }; -&pwr_regulators { - vdd-supply = <&vdd>; - vdd_3v3_usbfs-supply = <&vdd_usb>; +&rtc { + status = "okay"; + secure-status = "okay"; }; -&rng1 { +&sdmmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_b4_pins_a>; + disable-wp; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; status = "okay"; }; -&rtc { - status = "okay"; +&timers15 { + secure-status = "okay"; + st,hsi-cal-input = <7>; + st,csi-cal-input = <8>; }; -&sai2 { - clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>; - clock-names = "pclk", "x8k", "x11k"; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_b>; - pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_b>; +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_a>; status = "okay"; +}; - sai2a: audio-controller@4400b004 { - #clock-cells = <0>; - dma-names = "tx"; - clocks = <&rcc SAI2_K>; - clock-names = "sai_ck"; - status = "okay"; - - sai2a_port: port { - sai2a_endpoint: endpoint { - remote-endpoint = <&cs42l51_tx_endpoint>; - format = "i2s"; - mclk-fs = <256>; - dai-tdm-slot-num = <2>; - dai-tdm-slot-width = <32>; - }; - }; - }; +&uart7 { + pinctrl-names = "default"; + pinctrl-0 = <&uart7_pins_c>; + status = "disabled"; +}; - sai2b: audio-controller@4400b024 { - dma-names = "rx"; - st,sync = <&sai2a 2>; - clocks = <&rcc SAI2_K>, <&sai2a>; - clock-names = "sai_ck", "MCLK"; - status = "okay"; +&usart3 { + pinctrl-names = "default"; + pinctrl-0 = <&usart3_pins_c>; + uart-has-rtscts; + status = "disabled"; +}; - sai2b_port: port { - sai2b_endpoint: endpoint { - remote-endpoint = <&cs42l51_rx_endpoint>; - format = "i2s"; - mclk-fs = <256>; - dai-tdm-slot-num = <2>; - dai-tdm-slot-width = <32>; - }; - }; - }; +&usbotg_hs { + phys = <&usbphyc_port1 0>; + phy-names = "usb2-phy"; + usb-role-switch; + status = "okay"; }; -&sdmmc1 { - pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc1_b4_pins_a>; - pinctrl-1 = <&sdmmc1_b4_od_pins_a>; - pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; - broken-cd; - st,neg-edge; - bus-width = <4>; - vmmc-supply = <&v3v3>; +&usbphyc { status = "okay"; }; -&sdmmc3 { - pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc3_b4_pins_a>; - pinctrl-1 = <&sdmmc3_b4_od_pins_a>; - pinctrl-2 = <&sdmmc3_b4_sleep_pins_a>; - broken-cd; - st,neg-edge; - bus-width = <4>; - vmmc-supply = <&v3v3>; - status = "disabled"; +&usbphyc_port0 { + phy-supply = <&vdd_usb>; }; -&timers1 { - /* spare dmas for other usage */ - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm1_pins_a>; - pinctrl-1 = <&pwm1_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; - }; - timer@0 { - status = "okay"; - }; +&usbphyc_port1 { + phy-supply = <&vdd_usb>; }; -&timers3 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm3_pins_a>; - pinctrl-1 = <&pwm3_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; +/* Low-power states of regulators */ +&v1v2_hdmi { + standby-ddr-sr { + regulator-off-in-suspend; }; - timer@2 { - status = "okay"; + standby-ddr-off { + regulator-off-in-suspend; }; }; -&timers4 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm4_pins_a &pwm4_pins_b>; - pinctrl-1 = <&pwm4_sleep_pins_a &pwm4_sleep_pins_b>; - pinctrl-names = "default", "sleep"; - status = "okay"; +&v1v8_audio { + standby-ddr-sr { + regulator-off-in-suspend; }; - timer@3 { - status = "okay"; + standby-ddr-off { + regulator-off-in-suspend; }; }; -&timers5 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm5_pins_a>; - pinctrl-1 = <&pwm5_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; +&v3v3 { + lp-stop { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; }; - timer@4 { - status = "okay"; + standby-ddr-sr { + regulator-off-in-suspend; }; -}; - -&timers6 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - timer@5 { - status = "okay"; + standby-ddr-off { + regulator-off-in-suspend; }; }; -&timers12 { - /delete-property/dmas; - /delete-property/dma-names; - status = "disabled"; - pwm { - pinctrl-0 = <&pwm12_pins_a>; - pinctrl-1 = <&pwm12_sleep_pins_a>; - pinctrl-names = "default", "sleep"; - status = "okay"; +&v3v3_hdmi { + standby-ddr-sr { + regulator-off-in-suspend; }; - timer@11 { - status = "okay"; + standby-ddr-off { + regulator-off-in-suspend; }; }; -&uart4 { - pinctrl-names = "default"; - pinctrl-0 = <&uart4_pins_a>; - status = "okay"; +&vdd { + lp-stop { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; + standby-ddr-sr { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; + standby-ddr-off { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; }; -&usbh_ehci { - phys = <&usbphyc_port0>; - status = "okay"; +&vdda { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; }; -&usbotg_hs { - dr_mode = "peripheral"; - phys = <&usbphyc_port1 0>; - phy-names = "usb2-phy"; - status = "okay"; +&vddcore { + lp-stop { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; }; -&usbphyc { - status = "okay"; +&vdd_ddr { + lp-stop { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + }; + standby-ddr-sr { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; }; -&usbphyc_port0 { - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; +&vdd_usb { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; }; -&usbphyc_port1 { - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; +&vref_ddr { + lp-stop { + regulator-on-in-suspend; + }; + standby-ddr-sr { + regulator-on-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; }; -&vrefbuf { - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2500000>; - vdda-supply = <&vdd>; - status = "okay"; +&vtt_ddr { + lp-stop { + regulator-off-in-suspend; + }; + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; }; diff --git a/core/arch/arm/dts/stm32mp15xx-edx.dtsi b/core/arch/arm/dts/stm32mp15xx-edx.dtsi new file mode 100644 index 000000000..ef51b00af --- /dev/null +++ b/core/arch/arm/dts/stm32mp15xx-edx.dtsi @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ + +#include +#include + +/ { + memory@c0000000 { + device_type = "memory"; + reg = <0xC0000000 0x40000000>; + }; + + aliases { + serial0 = &uart4; + }; + + vin: vin { + compatible = "regulator-fixed"; + regulator-name = "vin"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; +}; + +&bsec { + board_id: board_id@ec { + reg = <0xec 0x4>; + st,non-secure-otp; + }; +}; + +&clk_hse { + st,digbypass; +}; + +&cpu0{ + cpu-supply = <&vddcore>; +}; + +&cpu1{ + cpu-supply = <&vddcore>; +}; + +&hash1 { + status = "okay"; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; + clock-frequency = <400000>; + status = "okay"; + secure-status = "okay"; + + pmic: stpmic@33 { + compatible = "st,stpmic1"; + reg = <0x33>; + interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + secure-status = "okay"; + + regulators { + compatible = "st,stpmic1-regulators"; + buck1-supply = <&vin>; + buck2-supply = <&vin>; + buck3-supply = <&vin>; + buck4-supply = <&vin>; + ldo1-supply = <&v3v3>; + ldo2-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; + ldo4-supply = <&vin>; + ldo5-supply = <&v3v3>; + ldo6-supply = <&v3v3>; + vref_ddr-supply = <&vin>; + boost-supply = <&vin>; + pwr_sw1-supply = <&bst_out>; + pwr_sw2-supply = <&bst_out>; + + vddcore: buck1 { + regulator-name = "vddcore"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + vdd_ddr: buck2 { + regulator-name = "vdd_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + vdd: buck3 { + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + st,mask-reset; + regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + + v3v3: buck4 { + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-over-current-protection; + regulator-initial-mode = <0>; + }; + + vdda: ldo1 { + regulator-name = "vdda"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + }; + + v2v8: ldo2 { + regulator-name = "v2v8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <750000>; + regulator-always-on; + regulator-over-current-protection; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; + }; + + vdd_sd: ldo5 { + regulator-name = "vdd_sd"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + regulator-boot-on; + }; + + v1v8: ldo6 { + regulator-name = "v1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; + regulator-over-current-protection; + }; + + bst_out: boost { + regulator-name = "bst_out"; + }; + + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + regulator-active-discharge = <1>; + }; + }; + }; +}; + +&iwdg2 { + timeout-sec = <32>; + secure-timeout-sec = <5>; + status = "okay"; + secure-status = "okay"; +}; + +&nvmem_layout { + nvmem-cells = <&cfg0_otp>, + <&part_number_otp>, + <&monotonic_otp>, + <&nand_otp>, + <&uid_otp>, + <&package_otp>, + <&hw2_otp>, + <&pkh_otp>, + <&board_id>; + + nvmem-cell-names = "cfg0_otp", + "part_number_otp", + "monotonic_otp", + "nand_otp", + "uid_otp", + "package_otp", + "hw2_otp", + "pkh_otp", + "board_id"; +}; + +&pwr_regulators { + system_suspend_supported_soc_modes = < + STM32_PM_CSLEEP_RUN + STM32_PM_CSTOP_ALLOW_LP_STOP + STM32_PM_CSTOP_ALLOW_LPLV_STOP + STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR + >; + system_off_soc_mode = ; + vdd-supply = <&vdd>; + vdd_3v3_usbfs-supply = <&vdd_usb>; +}; + +&rcc { + st,hsi-cal; + st,csi-cal; + st,cal-sec = <60>; + st,clksrc = < + CLK_MPU_PLL1P + CLK_AXI_PLL2P + CLK_MCU_PLL3P + CLK_PLL12_HSE + CLK_PLL3_HSE + CLK_PLL4_HSE + CLK_RTC_LSE + CLK_MCO1_DISABLED + CLK_MCO2_DISABLED + >; + + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ + 0 /*MCU*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ + 1 /*APB4*/ + 2 /*APB5*/ + 23 /*RTC*/ + 0 /*MCO1*/ + 0 /*MCO2*/ + >; + + st,pkcs = < + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK + CLK_ETH_DISABLED + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE + CLK_USBPHY_HSE + CLK_SPI2S1_PLL3Q + CLK_SPI2S23_PLL3Q + CLK_SPI45_HSI + CLK_SPI6_HSI + CLK_I2C46_HSI + CLK_SDMMC3_PLL4P + CLK_USBO_USBPHY + CLK_ADC_CKPER + CLK_CEC_LSE + CLK_I2C12_HSI + CLK_I2C35_HSI + CLK_UART1_HSI + CLK_UART24_HSI + CLK_UART35_HSI + CLK_UART6_HSI + CLK_UART78_HSI + CLK_SPDIF_PLL4P + CLK_FDCAN_PLL4R + CLK_SAI1_PLL3Q + CLK_SAI2_PLL3Q + CLK_SAI3_PLL3Q + CLK_SAI4_PLL3Q + CLK_RNG1_LSI + CLK_RNG2_LSI + CLK_LPTIM1_PCLK1 + CLK_LPTIM23_PCLK3 + CLK_LPTIM45_LSE + >; + + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + compatible = "st,stm32mp1-pll"; + reg = <1>; + cfg = <2 65 1 0 0 PQR(1,1,1)>; + frac = <0x1400>; + }; + + /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ + pll3: st,pll@2 { + compatible = "st,stm32mp1-pll"; + reg = <2>; + cfg = <1 33 1 16 36 PQR(1,1,1)>; + frac = <0x1a04>; + }; + + /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ + pll4: st,pll@3 { + compatible = "st,stm32mp1-pll"; + reg = <3>; + cfg = <3 98 5 7 7 PQR(1,1,1)>; + }; +}; + +&rng1 { + status = "okay"; + secure-status = "okay"; +}; + +&rtc { + status = "okay"; + secure-status = "okay"; +}; + +&sdmmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; + disable-wp; + st,sig-dir; + st,neg-edge; + st,use-ckin; + bus-width = <4>; + vmmc-supply = <&vdd_sd>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-ddr50; + status = "okay"; +}; + +&sdmmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; + non-removable; + no-sd; + no-sdio; + st,neg-edge; + bus-width = <8>; + vmmc-supply = <&v3v3>; + vqmmc-supply = <&vdd>; + mmc-ddr-3_3v; + status = "okay"; +}; + +&timers15 { + secure-status = "okay"; + st,hsi-cal-input = <7>; + st,csi-cal-input = <8>; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_a>; + status = "okay"; +}; + +&usbotg_hs { + vbus-supply = <&vbus_otg>; +}; + +&usbphyc_port0 { + phy-supply = <&vdd_usb>; +}; + +&usbphyc_port1 { + phy-supply = <&vdd_usb>; +}; + +/* Low-power states of regulators */ +&v1v8 { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&v2v8 { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&v3v3 { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vdd { + lp-stop { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; + lplv-stop { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; + standby-ddr-sr { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; + standby-ddr-off { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + }; +}; + +&vdda { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vddcore { + lp-stop { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + lplv-stop { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vdd_ddr { + lp-stop { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + }; + lplv-stop { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + }; + standby-ddr-sr { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vdd_sd { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vdd_usb { + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vref_ddr { + lp-stop { + regulator-on-in-suspend; + }; + lplv-stop { + regulator-on-in-suspend; + }; + standby-ddr-sr { + regulator-on-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; + +&vtt_ddr { + lp-stop { + regulator-off-in-suspend; + }; + lplv-stop { + regulator-off-in-suspend; + }; + standby-ddr-sr { + regulator-off-in-suspend; + }; + standby-ddr-off { + regulator-off-in-suspend; + }; +}; diff --git a/core/arch/arm/dts/stm32mp15xx-evx.dtsi b/core/arch/arm/dts/stm32mp15xx-evx.dtsi new file mode 100644 index 000000000..ce1982d45 --- /dev/null +++ b/core/arch/arm/dts/stm32mp15xx-evx.dtsi @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ + +&fmc { + pinctrl-names = "default"; + pinctrl-0 = <&fmc_pins_a>; + status = "okay"; + + nand-controller@4,0 { + status = "okay"; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; + }; +}; + +&i2c4 { + pmic: stpmic@33 { + regulators { + v1v8: ldo6 { + regulator-enable-ramp-delay = <300000>; + }; + }; + }; +}; + +&qspi { + pinctrl-names = "default"; + pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>; + reg = <0x58003000 0x1000>, <0x70000000 0x4000000>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + flash0: mx66l51235l@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-rx-bus-width = <4>; + spi-max-frequency = <108000000>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + +&timers12 { + status = "disabled"; +}; + +&usart3 { + pinctrl-names = "default"; + pinctrl-0 = <&usart3_pins_b>; + uart-has-rtscts; + status = "disabled"; +}; + +&usbotg_hs { + pinctrl-0 = <&usbotg_hs_pins_a>; + pinctrl-names = "default"; + phys = <&usbphyc_port1 0>; + phy-names = "usb2-phy"; + status = "okay"; +}; + +&usbphyc { + status = "okay"; +}; diff --git a/core/arch/arm/dts/stm32mp15xxaa-pinctrl.dtsi b/core/arch/arm/dts/stm32mp15xxaa-pinctrl.dtsi index 04f7a43ad..4f4130eff 100644 --- a/core/arch/arm/dts/stm32mp15xxaa-pinctrl.dtsi +++ b/core/arch/arm/dts/stm32mp15xxaa-pinctrl.dtsi @@ -79,6 +79,7 @@ gpioz: gpio@54004000 { status = "okay"; + secure-status = "okay"; ngpios = <8>; gpio-ranges = <&pinctrl_z 0 400 8>; }; diff --git a/core/arch/arm/dts/stm32mp15xxac-pinctrl.dtsi b/core/arch/arm/dts/stm32mp15xxac-pinctrl.dtsi index 7eaa245f4..866c050da 100644 --- a/core/arch/arm/dts/stm32mp15xxac-pinctrl.dtsi +++ b/core/arch/arm/dts/stm32mp15xxac-pinctrl.dtsi @@ -67,6 +67,7 @@ gpioz: gpio@54004000 { status = "okay"; + secure-status = "okay"; ngpios = <8>; gpio-ranges = <&pinctrl_z 0 400 8>; }; diff --git a/core/arch/arm/include/arm32.h b/core/arch/arm/include/arm32.h index f28b73fda..2f67cc762 100644 --- a/core/arch/arm/include/arm32.h +++ b/core/arch/arm/include/arm32.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-2-Clause */ /* - * Copyright (c) 2016, Linaro Limited + * Copyright (c) 2016-2019, Linaro Limited * Copyright (c) 2014, STMicroelectronics International N.V. */ @@ -163,6 +163,15 @@ #define IDPFR1_GENTIMER_SHIFT 16 #define IDPFR1_GENTIMER_MASK (0xF << IDPFR1_GENTIMER_SHIFT) +/* Generic timer registers and fields */ +#define CNTCR_OFFSET 0x000 +#define CNTSR_OFFSET 0x004 +#define CNTCVL_OFFSET 0x008 +#define CNTCVU_OFFSET 0x00C +#define CNTFID_OFFSET 0x020 + +#define CNTCR_EN BIT(0) + #ifndef __ASSEMBLER__ #include #ifdef CFG_ARM_GICV3 diff --git a/core/arch/arm/include/kernel/tlb_helpers.h b/core/arch/arm/include/kernel/tlb_helpers.h index d33dd5c01..2dbcbcf08 100644 --- a/core/arch/arm/include/kernel/tlb_helpers.h +++ b/core/arch/arm/include/kernel/tlb_helpers.h @@ -25,11 +25,10 @@ static inline void tlbi_mva_allasid_nosync(vaddr_t va) #endif } -static inline void tlbi_mva_asid(vaddr_t va, uint32_t asid) +static inline void tlbi_mva_asid_nosync(vaddr_t va, uint32_t asid) { uint32_t a = asid & TLBI_ASID_MASK; - dsb_ishst(); #ifdef ARM64 tlbi_vale1is((va >> TLBI_MVA_SHIFT) | SHIFT_U64(a, TLBI_ASID_SHIFT)); tlbi_vale1is((va >> TLBI_MVA_SHIFT) | @@ -38,6 +37,12 @@ static inline void tlbi_mva_asid(vaddr_t va, uint32_t asid) write_tlbimvais((va & ~(BIT32(TLBI_MVA_SHIFT) - 1)) | a); write_tlbimvais((va & ~(BIT32(TLBI_MVA_SHIFT) - 1)) | a | 1); #endif +} + +static inline void tlbi_mva_asid(vaddr_t va, uint32_t asid) +{ + dsb_ishst(); + tlbi_mva_asid_nosync(va, asid); dsb_ish(); isb(); } diff --git a/core/arch/arm/include/mm/core_mmu.h b/core/arch/arm/include/mm/core_mmu.h index 33ee2ebd7..bf8e68607 100644 --- a/core/arch/arm/include/mm/core_mmu.h +++ b/core/arch/arm/include/mm/core_mmu.h @@ -97,6 +97,7 @@ * MEM_AREA_NSEC_SHM: NonSecure shared RAM between NSec and TEE. * MEM_AREA_RAM_NSEC: NonSecure RAM storing data * MEM_AREA_RAM_SEC: Secure RAM storing some secrets + * MEM_AREA_ROM_SEC: Secure read only memory storing some secrets * MEM_AREA_IO_NSEC: NonSecure HW mapped registers * MEM_AREA_IO_SEC: Secure HW mapped registers * MEM_AREA_EXT_DT: Memory loads external device tree @@ -121,6 +122,7 @@ enum teecore_memtypes { MEM_AREA_NSEC_SHM, MEM_AREA_RAM_NSEC, MEM_AREA_RAM_SEC, + MEM_AREA_ROM_SEC, MEM_AREA_IO_NSEC, MEM_AREA_IO_SEC, MEM_AREA_EXT_DT, @@ -150,6 +152,7 @@ static inline const char *teecore_memtype_name(enum teecore_memtypes type) [MEM_AREA_NSEC_SHM] = "NSEC_SHM", [MEM_AREA_RAM_NSEC] = "RAM_NSEC", [MEM_AREA_RAM_SEC] = "RAM_SEC", + [MEM_AREA_ROM_SEC] = "ROM_SEC", [MEM_AREA_IO_NSEC] = "IO_NSEC", [MEM_AREA_IO_SEC] = "IO_SEC", [MEM_AREA_EXT_DT] = "EXT_DT", @@ -629,6 +632,18 @@ enum teecore_tlb_op { /* TLB invalidation for a range of virtual address */ void tlbi_mva_range(vaddr_t va, size_t size, size_t granule); +/* + * tlbi_mva_range_asid() - Invalidate TLB for virtual address range for + * a specific ASID + * @va: start virtual address, must be a multiple of @granule + * @len: length in bytes of range, must be a multiple of @granule + * @granule: granularity of mapping, supported values are + * CORE_MMU_PGDIR_SIZE or SMALL_PAGE_SIZE. This value must + * match the actual mappings. + * @asid: Address space identifier + */ +void tlbi_mva_range_asid(vaddr_t va, size_t len, size_t granule, uint32_t asid); + /* deprecated: please call straight tlbi_all() and friends */ int core_tlb_maintenance(int op, unsigned long a) __deprecated; diff --git a/core/arch/arm/include/mm/pgt_cache.h b/core/arch/arm/include/mm/pgt_cache.h index d19414e48..433dc3920 100644 --- a/core/arch/arm/include/mm/pgt_cache.h +++ b/core/arch/arm/include/mm/pgt_cache.h @@ -23,8 +23,8 @@ struct ts_ctx; struct pgt { void *tbl; -#if defined(CFG_PAGED_USER_TA) vaddr_t vabase; +#if defined(CFG_PAGED_USER_TA) struct ts_ctx *ctx; size_t num_used_entries; #endif @@ -61,6 +61,8 @@ void pgt_alloc(struct pgt_cache *pgt_cache, struct ts_ctx *owning_ctx, vaddr_t begin, vaddr_t last); void pgt_free(struct pgt_cache *pgt_cache, bool save_ctx); +void pgt_clear_ctx_range(struct pgt_cache *pgt_cache, struct ts_ctx *ctx, + vaddr_t begin, vaddr_t end); #ifdef CFG_PAGED_USER_TA void pgt_flush_ctx_range(struct pgt_cache *pgt_cache, struct ts_ctx *ctx, vaddr_t begin, vaddr_t last); @@ -73,6 +75,7 @@ static inline void pgt_flush_ctx_range(struct pgt_cache *pgt_cache __unused, } #endif + void pgt_init(void); #if defined(CFG_PAGED_USER_TA) diff --git a/core/arch/arm/include/sm/pm.h b/core/arch/arm/include/sm/pm.h index 939f966e8..90f031a2b 100644 --- a/core/arch/arm/include/sm/pm.h +++ b/core/arch/arm/include/sm/pm.h @@ -34,7 +34,11 @@ struct sm_pm_ctx { uint32_t sp; paddr_t cpu_resume_addr; +#ifdef CFG_WITH_LPAE + uint32_t suspend_regs[18]; +#else uint32_t suspend_regs[16]; +#endif }; /* suspend/resume core functions */ diff --git a/core/arch/arm/mm/core_mmu.c b/core/arch/arm/mm/core_mmu.c index 4f27b2499..489dae220 100644 --- a/core/arch/arm/mm/core_mmu.c +++ b/core/arch/arm/mm/core_mmu.c @@ -388,6 +388,7 @@ void core_mmu_set_discovered_nsec_ddr(struct core_mmu_phys_mem *start, carve_out_phys_mem(&m, &num_elems, map->pa, map->size); break; case MEM_AREA_EXT_DT: + case MEM_AREA_RAM_NSEC: case MEM_AREA_RES_VASPACE: case MEM_AREA_SHM_VASPACE: case MEM_AREA_TA_VASPACE: @@ -490,7 +491,6 @@ static bool pbuf_is_sdp_mem(paddr_t pbuf __unused, size_t len __unused) /* Check special memories comply with registered memories */ static void verify_special_mem_areas(struct tee_mmap_region *mem_map, - size_t len, const struct core_mmu_phys_mem *start, const struct core_mmu_phys_mem *end, const char *area_name __maybe_unused) @@ -498,7 +498,6 @@ static void verify_special_mem_areas(struct tee_mmap_region *mem_map, const struct core_mmu_phys_mem *mem; const struct core_mmu_phys_mem *mem2; struct tee_mmap_region *mmap; - size_t n; if (start == end) { DMSG("No %s memory area defined", area_name); @@ -524,9 +523,18 @@ static void verify_special_mem_areas(struct tee_mmap_region *mem_map, /* * Check memories do not intersect any mapped memory. * This is called before reserved VA space is loaded in mem_map. + * + * Exceptions are the memory areas that maps with the same attributes + * as for example MEM_AREA_RAM_NSEC and MEM_AREA_NSEC_SHM + * which may overlap since they are used for the same purpose + * except that MEM_AREA_NSEC_SHM is always mapped and + * MEM_AREA_RAM_NSEC only uses a dynamic mapping. */ for (mem = start; mem < end; mem++) { - for (mmap = mem_map, n = 0; n < len; mmap++, n++) { + for (mmap = mem_map; mmap->type != MEM_AREA_END; mmap++) { + if (core_mmu_type_to_attr(mem->type) == + core_mmu_type_to_attr(mmap->type)) + continue; if (core_is_buffer_intersect(mem->addr, mem->size, mmap->pa, mmap->size)) { MSG_MEM_INSTERSECT(mem->addr, mem->size, @@ -650,6 +658,8 @@ uint32_t core_mmu_type_to_attr(enum teecore_memtypes t) case MEM_AREA_RAM_SEC: case MEM_AREA_SEC_RAM_OVERALL: return attr | TEE_MATTR_SECURE | TEE_MATTR_PRW | cached; + case MEM_AREA_ROM_SEC: + return attr | TEE_MATTR_SECURE | TEE_MATTR_PR | cached; case MEM_AREA_RES_VASPACE: case MEM_AREA_SHM_VASPACE: return 0; @@ -841,8 +851,7 @@ static size_t collect_mem_ranges(struct tee_mmap_region *memory_map, } if (IS_ENABLED(CFG_SECURE_DATA_PATH)) - verify_special_mem_areas(memory_map, num_elems, - phys_sdp_mem_begin, + verify_special_mem_areas(memory_map, phys_sdp_mem_begin, phys_sdp_mem_end, "SDP"); add_va_space(memory_map, num_elems, MEM_AREA_RES_VASPACE, @@ -1145,6 +1154,7 @@ static void check_mem_map(struct tee_mmap_region *map) case MEM_AREA_IO_NSEC: case MEM_AREA_EXT_DT: case MEM_AREA_RAM_SEC: + case MEM_AREA_ROM_SEC: case MEM_AREA_RAM_NSEC: case MEM_AREA_RES_VASPACE: case MEM_AREA_SHM_VASPACE: @@ -1395,6 +1405,21 @@ void tlbi_mva_range(vaddr_t va, size_t size, size_t granule) isb(); } +void tlbi_mva_range_asid(vaddr_t va, size_t len, size_t granule, uint32_t asid) +{ + assert(granule == CORE_MMU_PGDIR_SIZE || granule == SMALL_PAGE_SIZE); + assert(!(va & (granule - 1)) && !(len & (granule - 1))); + + dsb_ishst(); + while (len) { + tlbi_mva_asid_nosync(va, asid); + len -= granule; + va += granule; + } + dsb_ish(); + isb(); +} + TEE_Result cache_op_inner(enum cache_op op, void *va, size_t len) { switch (op) { diff --git a/core/arch/arm/mm/mobj.c b/core/arch/arm/mm/mobj.c index 7a129cf5a..b14e93939 100644 --- a/core/arch/arm/mm/mobj.c +++ b/core/arch/arm/mm/mobj.c @@ -49,6 +49,7 @@ static void *mobj_phys_get_va(struct mobj *mobj, size_t offset) return (void *)(moph->va + offset); } +DECLARE_KEEP_PAGER(mobj_phys_get_va); static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs, size_t granule, paddr_t *pa) @@ -228,7 +229,7 @@ static void *mobj_mm_get_va(struct mobj *mobj, size_t offs) return mobj_get_va(to_mobj_mm(mobj)->parent_mobj, mobj_mm_offs(mobj, offs)); } - +DECLARE_KEEP_PAGER(mobj_mm_get_va); static TEE_Result mobj_mm_get_pa(struct mobj *mobj, size_t offs, size_t granule, paddr_t *pa) @@ -657,4 +658,4 @@ static TEE_Result mobj_init(void) return TEE_SUCCESS; } -driver_init_late(mobj_init); +service_init(mobj_init); diff --git a/core/arch/arm/mm/pgt_cache.c b/core/arch/arm/mm/pgt_cache.c index 3e854934d..988c1a351 100644 --- a/core/arch/arm/mm/pgt_cache.c +++ b/core/arch/arm/mm/pgt_cache.c @@ -413,13 +413,65 @@ static void pgt_free_unlocked(struct pgt_cache *pgt_cache, } } -static struct pgt *pop_from_some_list(vaddr_t vabase __unused, +static struct pgt *pop_from_some_list(vaddr_t vabase, struct ts_ctx *ctx __unused) { - return pop_from_free_list(); + struct pgt *p = pop_from_free_list(); + + if (p) + p->vabase = vabase; + + return p; } #endif /*!CFG_PAGED_USER_TA*/ +static void clear_ctx_range_from_list(struct pgt_cache *pgt_cache, + void *ctx __maybe_unused, + vaddr_t begin, vaddr_t end) +{ + struct pgt *p = NULL; +#ifdef CFG_WITH_LPAE + uint64_t *tbl = NULL; +#else + uint32_t *tbl = NULL; +#endif + unsigned int idx = 0; + unsigned int n = 0; + + SLIST_FOREACH(p, pgt_cache, link) { + vaddr_t b = MAX(p->vabase, begin); + vaddr_t e = MIN(p->vabase + CORE_MMU_PGDIR_SIZE, end); + +#ifdef CFG_PAGED_USER_TA + if (p->ctx != ctx) + continue; +#endif + if (b >= e) + continue; + + tbl = p->tbl; + idx = (b - p->vabase) / SMALL_PAGE_SIZE; + n = (e - b) / SMALL_PAGE_SIZE; + memset(tbl + idx, 0, n * sizeof(*tbl)); + } +} + +void pgt_clear_ctx_range(struct pgt_cache *pgt_cache, struct ts_ctx *ctx, + vaddr_t begin, vaddr_t end) +{ + mutex_lock(&pgt_mu); + + if (pgt_cache) + clear_ctx_range_from_list(pgt_cache, ctx, begin, end); +#ifdef CFG_PAGED_USER_TA + clear_ctx_range_from_list(&pgt_cache_list, ctx, begin, end); +#endif + + mutex_unlock(&pgt_mu); +} + + + static bool pgt_alloc_unlocked(struct pgt_cache *pgt_cache, struct ts_ctx *ctx, vaddr_t begin, vaddr_t last) { diff --git a/core/arch/arm/plat-stm32mp1/boot_api.h b/core/arch/arm/plat-stm32mp1/boot_api.h index 62e38b588..a7daffd44 100644 --- a/core/arch/arm/plat-stm32mp1/boot_api.h +++ b/core/arch/arm/plat-stm32mp1/boot_api.h @@ -14,7 +14,9 @@ #define BCKR_CORE1_MAGIC_NUMBER 4 /* Value for BCKR_CORE1_MAGIC_NUMBER entry */ +#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xca7face0 #define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xca7face1 +#define BOOT_API_A7_RESET_MAGIC_NUMBER 0xca7dead0 /* Backup register #5: physical address of core1 entry at boot up */ #define BCKR_CORE1_BRANCH_ADDRESS 5 diff --git a/core/arch/arm/plat-stm32mp1/conf.mk b/core/arch/arm/plat-stm32mp1/conf.mk index baf3fe49a..b1d41c92a 100644 --- a/core/arch/arm/plat-stm32mp1/conf.mk +++ b/core/arch/arm/plat-stm32mp1/conf.mk @@ -1,22 +1,41 @@ # 1GB and 512MB DDR targets do not locate secure DDR at the same place. flavor_dts_file-157A_DK1 = stm32mp157a-dk1.dts +flavor_dts_file-157A_ED1 = stm32mp157a-ed1.dts +flavor_dts_file-157A_EV1 = stm32mp157a-ev1.dts flavor_dts_file-157C_DK2 = stm32mp157c-dk2.dts flavor_dts_file-157C_ED1 = stm32mp157c-ed1.dts flavor_dts_file-157C_EV1 = stm32mp157c-ev1.dts +flavor_dts_file-157D_DK1 = stm32mp157d-dk1.dts +flavor_dts_file-157D_ED1 = stm32mp157d-ed1.dts +flavor_dts_file-157D_EV1 = stm32mp157d-ev1.dts +flavor_dts_file-157F_DK2 = stm32mp157f-dk2.dts +flavor_dts_file-157F_ED1 = stm32mp157f-ed1.dts +flavor_dts_file-157F_EV1 = stm32mp157f-ev1.dts -flavorlist-cryp-512M = $(flavor_dts_file-157C_DK2) +flavorlist-cryp-512M = $(flavor_dts_file-157C_DK2) \ + $(flavor_dts_file-157F_DK2) -flavorlist-no_cryp-512M = $(flavor_dts_file-157A_DK1) +flavorlist-no_cryp-512M = $(flavor_dts_file-157A_DK1) \ + $(flavor_dts_file-157D_DK1) flavorlist-cryp-1G = $(flavor_dts_file-157C_ED1) \ - $(flavor_dts_file-157C_EV1) + $(flavor_dts_file-157C_EV1) \ + $(flavor_dts_file-157F_ED1) \ + $(flavor_dts_file-157F_EV1) -flavorlist-no_cryp = $(flavorlist-no_cryp-512M) +flavorlist-no_cryp-1G = $(flavor_dts_file-157A_ED1) \ + $(flavor_dts_file-157A_EV1) \ + $(flavor_dts_file-157D_ED1) \ + $(flavor_dts_file-157D_EV1) + +flavorlist-no_cryp = $(flavorlist-no_cryp-512M) \ + $(flavorlist-no_cryp-1G) flavorlist-512M = $(flavorlist-cryp-512M) \ $(flavorlist-no_cryp-512M) -flavorlist-1G = $(flavorlist-cryp-1G) +flavorlist-1G = $(flavorlist-cryp-1G) \ + $(flavorlist-no_cryp-1G) ifneq ($(PLATFORM_FLAVOR),) ifeq ($(flavor_dts_file-$(PLATFORM_FLAVOR)),) @@ -31,9 +50,14 @@ endif include core/arch/arm/cpu/cortex-a7.mk +$(call force,CFG_CLK_DRIVER,y) +$(call force,CFG_ARM_GIC_PM,y) $(call force,CFG_BOOT_SECONDARY_REQUEST,y) $(call force,CFG_GIC,y) $(call force,CFG_INIT_CNTVOFF,y) +$(call force,CFG_PM,y) +$(call force,CFG_PM_ARM32,y) +$(call force,CFG_PM_STUBS,y) $(call force,CFG_PSCI_ARM32,y) $(call force,CFG_SCMI_MSG_DRIVERS,y) $(call force,CFG_SCMI_MSG_CLOCK,y) @@ -52,6 +76,8 @@ CFG_SHMEM_START ?= 0xdfe00000 CFG_DRAM_SIZE ?= 0x20000000 endif +CFG_DTB_MAX_SIZE ?= 0x20000 + CFG_TZSRAM_START ?= 0x2ffc0000 CFG_TZSRAM_SIZE ?= 0x0003f000 CFG_STM32MP1_SCMI_SHM_BASE ?= 0x2ffff000 @@ -65,23 +91,45 @@ CFG_DRAM_SIZE ?= 0x40000000 CFG_TEE_CORE_NB_CORE ?= 2 CFG_WITH_PAGER ?= y CFG_WITH_LPAE ?= y -CFG_MMAP_REGIONS ?= 23 +CFG_MMAP_REGIONS ?= 30 +CFG_CORE_HEAP_SIZE ?= 49152 +CFG_DTB_MAX_SIZE = 0x20000 + +# Disable early TA compression to limit HEAP size +CFG_EARLY_TA_COMPRESS ?= n + +# Embed public part of this key in OP-TEE OS +CFG_RPROC_SIGN_KEY ?= keys/default_rproc.pem ifeq ($(CFG_EMBED_DTB_SOURCE_FILE),) # Some drivers mandate DT support +$(call force,CFG_STM32_CLKCALIB,n) $(call force,CFG_STM32_I2C,n) +$(call force,CFG_STM32_IWDG,n) +$(call force,CFG_STM32_TIM,n) $(call force,CFG_STPMIC1,n) endif +CFG_RPROC_PTA ?= n CFG_STM32_BSEC ?= y +CFG_STM32_CLKCALIB ?= y +CFG_STM32_CRYP ?= y CFG_STM32_ETZPC ?= y CFG_STM32_GPIO ?= y CFG_STM32_I2C ?= y +CFG_STM32_IWDG ?= y CFG_STM32_RNG ?= y +CFG_STM32_RTC ?= y +CFG_STM32_TIM ?= y CFG_STM32_UART ?= y +CFG_STM32MP15_CLK ?= y CFG_STPMIC1 ?= y CFG_TZC400 ?= y +ifeq ($(CFG_STM32_CLKCALIB),y) +$(call force,CFG_STM32_TIM,y) +endif + ifeq ($(CFG_STPMIC1),y) $(call force,CFG_STM32_I2C,y) $(call force,CFG_STM32_GPIO,y) @@ -92,12 +140,23 @@ CFG_STM32MP_PANIC_ON_TZC_PERM_VIOLATION ?= y # SiP/OEM service for non-secure world CFG_STM32_BSEC_SIP ?= y +CFG_STM32_CLKCALIB_SIP ?= y +CFG_STM32_LOWPOWER_SIP ?= $(CFG_PM) +CFG_STM32_PWR_SIP ?= y +CFG_STM32_RCC_SIP ?= y + +# Default use stm32mp1 PM mailbox context version 2 +# Use CFG_STM32MP15_PM_CONTEX_VERSION=1 to force version 0 when dealing with +# a TF-A firmware that supports version 1 of the context mailbox. +CFG_STM32MP15_PM_CONTEX_VERSION ?= 2 # Default enable some test facitilites CFG_TEE_CORE_EMBED_INTERNAL_TESTS ?= y CFG_WITH_STATS ?= y +CFG_WERROR ?= y # Default disable some support for pager memory size constraint +CFG_TEE_CORE_LOG_LEVEL ?= 2 CFG_TEE_CORE_DEBUG ?= n CFG_UNWIND ?= n CFG_LOCKDEP ?= n @@ -108,3 +167,6 @@ CFG_WITH_NSEC_GPIOS ?= y CFG_WITH_NSEC_UARTS ?= y # UART instance used for early console (0 disables early console) CFG_STM32_EARLY_CONSOLE_UART ?= 4 + +# Generate the STM32 files +CFG_STM32MP15x_STM32IMAGE ?= n diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c new file mode 100644 index 000000000..d52f638eb --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018-2020, STMicroelectronics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CALIBRATION_TIMEOUT_US 10000 + +/* List of forbiden values for HSI and CSI */ +static const uint16_t fbv_hsi[] = { + 512, 480, 448, 416, 384, 352, 320, 288, + 256, 224, 192, 160, 128, 96, 64, 32, 0, +}; +static const uint16_t fbv_csi[] = { + 256, 240, 224, 208, 192, 176, 160, 144, + 128, 112, 96, 80, 64, 48, 32, 16, 0, +}; + +struct stm32mp1_trim_boundary_t { + unsigned int max; /* Max boundary trim value around forbidden value */ + unsigned int min; /* Min boundary trim value around forbidden value */ +}; + +struct stm32mp1_clk_cal { + const uint16_t *fbv; + unsigned int cal_ref; + int trim_max; + int trim_min; + unsigned int boundary_max; + unsigned long ref_freq; + unsigned int freq_margin; + unsigned long (*get_freq)(void); + void (*set_trim)(unsigned int cal); + unsigned int (*get_trim)(void); + struct stm32mp1_trim_boundary_t boundary[16]; +}; + +static void hsi_set_trim(unsigned int cal); +static unsigned int hsi_get_trimed_cal(void); +static void csi_set_trim(unsigned int cal); +static unsigned int csi_get_trimed_cal(void); + +static struct stm32mp1_clk_cal *hsi_calib; +static struct stm32mp1_clk_cal *csi_calib; + +static const struct stm32mp1_clk_cal hsi_calib_config = { + .fbv = fbv_hsi, + .trim_max = 63, + .trim_min = -64, + .ref_freq = 0, + .freq_margin = 5, + .set_trim = hsi_set_trim, + .get_trim = hsi_get_trimed_cal, +}; + +static const struct stm32mp1_clk_cal csi_calib_config = { + .fbv = fbv_csi, + .trim_max = 15, + .trim_min = -16, + .ref_freq = 0, + .freq_margin = 8, + .set_trim = csi_set_trim, + .get_trim = csi_get_trimed_cal, +}; + +static int get_signed_value(uint8_t val) +{ + return (int8_t)(val << 1) / 2; +} + +static void hsi_set_trim(unsigned int cal) +{ + int clk_trim = (int)cal - (int)hsi_calib->cal_ref; + uint32_t trim = ((uint32_t)clk_trim << RCC_HSICFGR_HSITRIM_SHIFT) & + RCC_HSICFGR_HSITRIM_MASK; + + io_clrsetbits32(stm32_rcc_base() + RCC_HSICFGR, + RCC_HSICFGR_HSITRIM_MASK, trim); +} +DECLARE_KEEP_PAGER(hsi_set_trim); + +static unsigned int hsi_get_trimed_cal(void) +{ + uint32_t utrim = (io_read32(stm32_rcc_base() + RCC_HSICFGR) & + RCC_HSICFGR_HSITRIM_MASK) >> + RCC_HSICFGR_HSITRIM_SHIFT; + int trim = get_signed_value((uint8_t)utrim); + + if (trim + (int)hsi_calib->cal_ref < 0) + return 0; + + return hsi_calib->cal_ref + trim; +} +DECLARE_KEEP_PAGER(hsi_get_trimed_cal); + +static void csi_set_trim(unsigned int cal) +{ + int clk_trim = (int)cal - (int)csi_calib->cal_ref + + csi_calib->trim_max + 1; + uint32_t trim = ((uint32_t)clk_trim << RCC_CSICFGR_CSITRIM_SHIFT) & + RCC_CSICFGR_CSITRIM_MASK; + + io_clrsetbits32(stm32_rcc_base() + RCC_CSICFGR, + RCC_CSICFGR_CSITRIM_MASK, trim); +} +DECLARE_KEEP_PAGER(csi_set_trim); + +static unsigned int csi_get_trimed_cal(void) +{ + uint32_t trim = (io_read32(stm32_rcc_base() + RCC_CSICFGR) & + RCC_CSICFGR_CSITRIM_MASK) >> + RCC_CSICFGR_CSITRIM_SHIFT; + + return (int)trim - csi_calib->trim_max + (int)csi_calib->cal_ref - 1; +} +DECLARE_KEEP_PAGER(csi_get_trimed_cal); + +static unsigned int trim_increase(struct stm32mp1_clk_cal *clk_cal, + unsigned int cal) +{ + struct stm32mp1_trim_boundary_t *boundary = NULL; + unsigned int new_cal = 0; + int i = 0; + + /* By default: last calibration value */ + new_cal = cal; + + /* Start from Lowest cal value */ + for (i = (int)clk_cal->boundary_max - 1; i >= 0; i--) { + boundary = &clk_cal->boundary[i]; + + if (cal < boundary->min) { + new_cal = boundary->min; + break; + } + + if ((cal >= boundary->min) && (cal < boundary->max)) { + new_cal = cal + 1; + break; + } + } + + return new_cal; +} + +static unsigned int trim_decrease(struct stm32mp1_clk_cal *clk_cal, + unsigned int cal) +{ + struct stm32mp1_trim_boundary_t *boundary = NULL; + unsigned int new_cal = 0; + unsigned int i = 0; + + /* By default: last calibration value */ + new_cal = cal; + + /* Start from Highest cal value */ + for (i = 0; i < clk_cal->boundary_max; i++) { + boundary = &clk_cal->boundary[i]; + + if (cal > boundary->max) { + new_cal = boundary->max; + break; + } + + if ((cal > boundary->min) && (cal <= boundary->max)) { + new_cal = cal - 1; + break; + } + } + + return new_cal; +} + +static void rcc_calibration(struct stm32mp1_clk_cal *clk_cal) +{ + unsigned long margin = (clk_cal->ref_freq * + clk_cal->freq_margin) / 1000; + unsigned long min = clk_cal->ref_freq - margin; + unsigned long max = clk_cal->ref_freq + margin; + unsigned long freq = clk_cal->get_freq(); + int trim = 0; + int new_trim = 0; + unsigned long conv = 0; + unsigned long min_conv = ULONG_MAX; + uint64_t timeout_ref = 0; + + if ((freq >= min) && (freq <= max)) + return; + + trim = clk_cal->get_trim(); + timeout_ref = timeout_init_us(CALIBRATION_TIMEOUT_US); + do { + if (freq < clk_cal->ref_freq) + new_trim = trim_increase(clk_cal, trim); + else + new_trim = trim_decrease(clk_cal, trim); + + clk_cal->set_trim(new_trim); + freq = clk_cal->get_freq(); + if (freq == 0) { + /* Calibration will be stopped */ + clk_cal->ref_freq = 0U; + return; + } + conv = (clk_cal->ref_freq < freq) ? + freq - clk_cal->ref_freq : clk_cal->ref_freq - freq; + if (conv < min_conv) { + min_conv = conv; + trim = new_trim; + } + + if (timeout_elapsed(timeout_ref)) + break; + + } while (conv == min_conv); + + clk_cal->set_trim(trim); + freq = clk_cal->get_freq(); + if ((freq < min) || (freq > max)) { + EMSG("%s Calibration : Freq %lu , trim %i\n", + (clk_cal->set_trim == hsi_set_trim) ? "HSI" : "CSI", + freq, trim); + } +} + +static void save_trim(struct stm32mp1_clk_cal *clk_cal, + unsigned int i, unsigned int max, unsigned int min) +{ + clk_cal->boundary[i].max = max; + clk_cal->boundary[i].min = min; +} + +static int trim_find_prev_boundary(struct stm32mp1_clk_cal *clk_cal, + unsigned int x1) +{ + unsigned int x = x1; + unsigned long freq = 0; + + clk_cal->set_trim(x1 + 1); + freq = clk_cal->get_freq(); + + while (x >= (clk_cal->cal_ref + clk_cal->trim_min)) { + x--; + clk_cal->set_trim(x); + + if (clk_cal->get_freq() <= freq) + break; + }; + + return x; +} + +static void trim_table_init(struct stm32mp1_clk_cal *clk_cal) +{ + const uint16_t *trim_fbv = clk_cal->fbv; + unsigned int min = 0; + unsigned int max = 0; + int boundary = 0; + int i = 0; + + max = clk_cal->cal_ref + clk_cal->trim_max; + min = clk_cal->cal_ref + clk_cal->trim_min; + + while (trim_fbv[i]) { + unsigned int x = 0; + unsigned int x1 = trim_fbv[i]; + unsigned int x2 = trim_fbv[i + 1]; + + if ((max <= x2) || (min >= x1)) { + i++; + if (boundary != 0) + goto out; + + continue; + } + + /* Take forbiden value + 1 */ + x2 = x2 + 1; + if (x2 < min) + x2 = min; + + if (boundary == 0) { + /* Save first boundary */ + save_trim(clk_cal, boundary, max, x2); + boundary++; + i++; + continue; + } + + x = trim_find_prev_boundary(clk_cal, x1); + /* Save boundary values */ + save_trim(clk_cal, boundary, x - 1, x2); + boundary++; + i++; + }; +out: + clk_cal->boundary_max = boundary; +} + +/* Timer countdown/delay argument for the target calibration periodicity */ +static uint32_t timer_val; + +#define CNTP_CTL_ENABLE BIT(0) +#define CNTP_CTL_IMASK BIT(1) +#define CNTP_CTL_ISTATUS BIT(2) + +static void arm_timer(void) +{ + if (!timer_val) + return; + + write_cntp_ctl(read_cntp_ctl() & ~(CNTP_CTL_ENABLE | CNTP_CTL_IMASK)); + write_cntp_tval(timer_val); + write_cntp_ctl(read_cntp_ctl() | CNTP_CTL_ENABLE); +} + +static void arm_timer_with_period(uint32_t period_sec) +{ + timer_val = period_sec * read_cntfrq(); + + if (timer_val > INT32_MAX) + timer_val = INT32_MAX; + + DMSG("Calibration timeout set to %"PRIu32, timer_val / read_cntfrq()); + + arm_timer(); +} + +static void calib_period(void) +{ + (void)stm32mp_start_clock_calib(CK_HSI); + (void)stm32mp_start_clock_calib(CK_CSI); + + arm_timer(); +} + +static enum itr_return arm_cntp_it_handler(struct itr_handler *handler __unused) +{ + if (timer_val) + calib_period(); + + return ITRR_HANDLED; +} +static struct itr_handler arm_cntp_handler = { + .it = GIC_SPI_SEC_PHY_TIMER, + .handler = arm_cntp_it_handler, +}; +DECLARE_KEEP_PAGER(arm_cntp_handler); + +static TEE_Result timer_pm(enum pm_op op, uint32_t pm_hint __unused, + const struct pm_callback_handle *handle __unused) +{ + if (op == PM_OP_RESUME && timer_val) + calib_period(); + + return TEE_SUCCESS; +} +DECLARE_KEEP_PAGER(timer_pm); + +static TEE_Result init_arm_cntp_timer(void) +{ + itr_add(&arm_cntp_handler); + itr_enable(arm_cntp_handler.it); + + register_pm_driver_cb(timer_pm, NULL); + + return TEE_SUCCESS; +} +driver_init(init_arm_cntp_timer); + +static void init_periodic_calibration(void *fdt, int node) +{ + uint32_t period = 0; + int lenp = 0; + const fdt32_t *cuint = fdt_getprop(fdt, node, "st,cal-sec", &lenp); + + if (cuint) + period = fdt32_to_cpu(*cuint); + + DMSG("Calib period %us", period); + arm_timer_with_period(period); +} + +int stm32mp_start_clock_calib(unsigned int clock_id) +{ + struct stm32mp1_clk_cal *clk_calib = NULL; + + switch (clock_id) { + case CK_HSI: + clk_calib = hsi_calib; + break; + case CK_CSI: + clk_calib = csi_calib; + break; + default: + DMSG("Cannot calibrate clock %u", clock_id); + return 1; + } + + if (clk_calib->ref_freq == 0U) + return 1; + + DMSG("%s", clock_id == CK_HSI ? "HSI" : "CSI"); + rcc_calibration(clk_calib); + + return 0; +} + +static int init_hsi_calibration(void *fdt, int node) +{ + if (!fdt_getprop(fdt, node, "st,hsi-cal", NULL)) + return 0; + + hsi_calib = calloc(1, sizeof(*hsi_calib)); + assert(hsi_calib); + memcpy(hsi_calib, &hsi_calib_config, sizeof(*hsi_calib)); + + stm32_tim_freq_func(&hsi_calib->get_freq, HSI_CAL); + if (hsi_calib->get_freq == NULL) { + free(hsi_calib); + return -1; + } + + hsi_calib->ref_freq = clk_get_rate(CK_HSI); + + hsi_calib->cal_ref = (io_read32(stm32_rcc_base() + RCC_HSICFGR) & + RCC_HSICFGR_HSICAL_MASK) >> + RCC_HSICFGR_HSICAL_SHIFT; + + trim_table_init(hsi_calib); + hsi_calib->set_trim(hsi_calib->cal_ref); + stm32mp_start_clock_calib(CK_HSI); + return 1; +} + +static int init_csi_calibration(void *fdt, int node) +{ + if (!fdt_getprop(fdt, node, "st,csi-cal", NULL)) + return 0; + + csi_calib = calloc(1, sizeof(*csi_calib)); + assert(csi_calib); + memcpy(csi_calib, &csi_calib_config, sizeof(*csi_calib)); + + stm32_tim_freq_func(&csi_calib->get_freq, CSI_CAL); + if (csi_calib->get_freq == NULL) { + free(csi_calib); + return -1; + } + + csi_calib->ref_freq = clk_get_rate(CK_CSI); + + csi_calib->cal_ref = (io_read32(stm32_rcc_base() + RCC_CSICFGR) & + RCC_CSICFGR_CSICAL_MASK) >> + RCC_CSICFGR_CSICAL_SHIFT; + trim_table_init(csi_calib); + csi_calib->set_trim(csi_calib->cal_ref); + stm32mp_start_clock_calib(CK_CSI); + return 1; +} + +static TEE_Result init_stm32mp1_calib(void) +{ + void *fdt = NULL; + int rcc_node = 0; + int res_csi = 0; + int res_hsi = 0; + + fdt = get_embedded_dt(); + if (!fdt) + panic(); + + rcc_node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); + if (rcc_node < 0) + panic(); + + res_hsi = init_hsi_calibration(fdt, rcc_node); + if (res_hsi < 0) + panic("HSI calibration init failed"); + res_csi = init_csi_calibration(fdt, rcc_node); + if (res_csi < 0) + panic("CSI calibration init failed"); + if (res_csi || res_hsi) + init_periodic_calibration(fdt, rcc_node); + + return TEE_SUCCESS; +} +driver_init(init_stm32mp1_calib); diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c new file mode 100644 index 000000000..1c2d9b2c8 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMEOUT_500US 500 + +static enum stm32mp1_ddr_sr_mode saved_ddr_sr_mode; + +static vaddr_t get_ddrctrl_base(void) +{ + static struct io_pa_va base __nex_data = { .pa = DDRCTRL_BASE }; + + return io_pa_or_va(&base); +} + +static vaddr_t get_ddrphy_base(void) +{ + static struct io_pa_va base __nex_data = { .pa = DDRPHYC_BASE }; + + return io_pa_or_va(&base); +} + +static void ddr_disable_clock(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + + /* Disable all clocks */ + io_clrbits32(rcc_base + RCC_DDRITFCR, + RCC_DDRITFCR_DDRC1EN | + RCC_DDRITFCR_DDRC2EN | + RCC_DDRITFCR_DDRPHYCAPBEN | + RCC_DDRITFCR_DDRCAPBEN); +} + +static void ddr_enable_clock(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + + /* Enable all clocks */ + io_setbits32(rcc_base + RCC_DDRITFCR, + RCC_DDRITFCR_DDRC1EN | + RCC_DDRITFCR_DDRC2EN | + RCC_DDRITFCR_DDRPHYCEN | + RCC_DDRITFCR_DDRPHYCAPBEN | + RCC_DDRITFCR_DDRCAPBEN); +} + +static void do_sw_handshake(void) +{ + vaddr_t ddrctrl_base = get_ddrctrl_base(); + + io_clrbits32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); +} + +static void do_sw_ack(void) +{ + uint64_t timeout_ref = 0; + vaddr_t ddrctrl_base = get_ddrctrl_base(); + + io_setbits32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); + + timeout_ref = timeout_init_us(TIMEOUT_500US); + while (!timeout_elapsed(timeout_ref)) + if (io_read32(ddrctrl_base + DDRCTRL_SWSTAT) & + DDRCTRL_SWSTAT_SW_DONE_ACK) + return; + + panic(); +} + +static int ddr_sw_self_refresh_in(void) +{ + uint64_t timeout_ref = 0; + uint32_t operating_mode = 0; + uint32_t selref_type = 0; + uint8_t op_mode_changed = 0; + vaddr_t pwr_base = stm32_pwr_base(); + vaddr_t rcc_base = stm32_rcc_base(); + vaddr_t ddrctrl_base = get_ddrctrl_base(); + vaddr_t ddrphy_base = get_ddrphy_base(); + + io_clrbits32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + + /* Blocks AXI ports from taking anymore transactions */ + io_clrbits32(ddrctrl_base + DDRCTRL_PCTRL_0, DDRCTRL_PCTRL_N_PORT_EN); + io_clrbits32(ddrctrl_base + DDRCTRL_PCTRL_1, DDRCTRL_PCTRL_N_PORT_EN); + + /* + * Waits unit all AXI ports are idle + * Poll PSTAT.rd_port_busy_n = 0 + * Poll PSTAT.wr_port_busy_n = 0 + */ + timeout_ref = timeout_init_us(TIMEOUT_500US); + while (io_read32(ddrctrl_base + DDRCTRL_PSTAT)) + if (timeout_elapsed(timeout_ref)) + goto pstat_failed; + + /* SW Self-Refresh entry */ + io_setbits32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); + + /* + * Wait operating mode change in self-refresh mode + * with STAT.operating_mode[1:0]==11. + * Ensure transition to self-refresh was due to software + * by checking also that STAT.selfref_type[1:0]=2. + */ + timeout_ref = timeout_init_us(TIMEOUT_500US); + while (!timeout_elapsed(timeout_ref)) { + uint32_t stat = io_read32(ddrctrl_base + DDRCTRL_STAT); + + operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; + selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; + + if ((operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && + (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) { + op_mode_changed = 1; + break; + } + } + + if (op_mode_changed == 0U) + goto selfref_sw_failed; + + /* IOs powering down (PUBL registers) */ + io_setbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); + io_setbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR); + io_clrsetbits32(ddrphy_base + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CKPDD_MASK, DDRPHYC_ACIOCR_CKPDD_0); + io_clrsetbits32(ddrphy_base + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CKPDR_MASK, DDRPHYC_ACIOCR_CKPDR_0); + io_clrsetbits32(ddrphy_base + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CSPDD_MASK, DDRPHYC_ACIOCR_CSPDD_0); + io_clrbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); + io_setbits32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); + io_setbits32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); + io_clrsetbits32(ddrphy_base + DDRPHYC_DSGCR, + DDRPHYC_DSGCR_ODTPDD_MASK, DDRPHYC_DSGCR_ODTPDD_0); + io_setbits32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); + io_clrsetbits32(ddrphy_base + DDRPHYC_DSGCR, + DDRPHYC_DSGCR_CKEPDD_MASK, DDRPHYC_DSGCR_CKEPDD_0); + + /* Disable PZQ cell (PUBL register) */ + io_setbits32(ddrphy_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); + + /* Activate sw retention in PWRCTRL */ + io_setbits32(pwr_base + PWR_CR3_OFF, PWR_CR3_DDRRETEN); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ + io_setbits32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + /* Disable all DLLs: GLITCH window */ + io_setbits32(ddrphy_base + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLDIS); + io_setbits32(ddrphy_base + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + io_setbits32(ddrphy_base + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + io_setbits32(ddrphy_base + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + io_setbits32(ddrphy_base + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */ + io_clrbits32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + /* Disable all clocks */ + ddr_disable_clock(); + + return 0; + +selfref_sw_failed: + /* This bit should be cleared to restore DDR in its previous state */ + io_clrbits32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); + +pstat_failed: + io_setbits32(ddrctrl_base + DDRCTRL_PCTRL_0, DDRCTRL_PCTRL_N_PORT_EN); + io_setbits32(ddrctrl_base + DDRCTRL_PCTRL_1, DDRCTRL_PCTRL_N_PORT_EN); + + return -1; +} + +static int ddr_sw_self_refresh_exit(void) +{ + uint64_t timeout_ref = 0; + vaddr_t rcc_base = stm32_rcc_base(); + vaddr_t pwr_base = stm32_pwr_base(); + vaddr_t ddrctrl_base = get_ddrctrl_base(); + vaddr_t ddrphy_base = get_ddrphy_base(); + + /* Enable all clocks */ + ddr_enable_clock(); + + do_sw_handshake(); + + /* Mask dfi_init_complete_en */ + io_clrbits32(ddrctrl_base + DDRCTRL_DFIMISC, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + + do_sw_ack(); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ + io_setbits32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + + /* Enable all DLLs: GLITCH window */ + io_clrbits32(ddrphy_base + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLDIS); + io_clrbits32(ddrphy_base + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + io_clrbits32(ddrphy_base + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + io_clrbits32(ddrphy_base + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + io_clrbits32(ddrphy_base + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); + + /* Additional delay to avoid early DLL clock switch */ + udelay(50); + + /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ + io_clrbits32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); + io_clrbits32(ddrphy_base + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); + udelay(10); + io_setbits32(ddrphy_base + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); + + /* PHY partial init: (DLL lock and ITM reset) */ + io_write32(ddrphy_base + DDRPHYC_PIR, + DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | + DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT); + + /* Need to wait at least 10 clock cycles before accessing PGSR */ + udelay(10); + + timeout_ref = timeout_init_us(TIMEOUT_500US); + while (!(io_read32(ddrphy_base + DDRPHYC_PGSR) & DDRPHYC_PGSR_IDONE)) + if (timeout_elapsed(timeout_ref)) + return -1; + + do_sw_handshake(); + + /* Unmask dfi_init_complete_en to uMCTL2 */ + io_setbits32(ddrctrl_base + DDRCTRL_DFIMISC, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + + do_sw_ack(); + + /* Deactivate sw retention in PWR */ + io_clrbits32(pwr_base + PWR_CR3_OFF, PWR_CR3_DDRRETEN); + + /* Enable PZQ cell (PUBL register) */ + io_clrbits32(ddrphy_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); + + /* Enable pad drivers */ + io_clrbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); + io_setbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); + io_clrbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CKPDD_MASK); + io_clrbits32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CSPDD_MASK); + io_clrbits32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); + io_clrbits32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); + io_clrbits32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_ODTPDD_MASK); + io_clrbits32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); + io_clrbits32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKEPDD_MASK); + + /* Remove selfrefresh */ + io_clrbits32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); + + /* Wait operating_mode == normal */ + timeout_ref = timeout_init_us(TIMEOUT_500US); + while (1) { + if ((io_read32(ddrctrl_base + DDRCTRL_STAT) & + DDRCTRL_STAT_OPERATING_MODE_MASK) == + DDRCTRL_STAT_OPERATING_MODE_NORMAL) + break; + + if (timeout_elapsed(timeout_ref)) + return -1; + } + + /* AXI ports are no longer blocked from taking transactions */ + io_setbits32(ddrctrl_base + DDRCTRL_PCTRL_0, DDRCTRL_PCTRL_N_PORT_EN); + io_setbits32(ddrctrl_base + DDRCTRL_PCTRL_1, DDRCTRL_PCTRL_N_PORT_EN); + + io_setbits32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + + return 0; +} + +uint32_t get_ddrphy_calibration(void) +{ + vaddr_t ddrphy_base = get_ddrphy_base(); + uint32_t zcal = io_read32(ddrphy_base + DDRPHYC_ZQ0CR0); + + return (zcal & DDRPHYC_ZQ0CRN_ZDATA_MASK) >> DDRPHYC_ZQ0CRN_ZDATA_SHIFT; +} + +int ddr_standby_sr_entry(void) +{ + vaddr_t pwr_base = stm32_pwr_base(); + + if (ddr_sw_self_refresh_in()) + return -1; + + /* Enable I/O retention mode in standby */ + io_setbits32(pwr_base + PWR_CR3_OFF, PWR_CR3_DDRSREN); + + return 0; +} + +int ddr_standby_sr_exit(void) +{ + return ddr_sw_self_refresh_exit(); +} + +static void ddr_sr_mode_ssr(void) +{ + vaddr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR; + vaddr_t ddrctrl_base = get_ddrctrl_base(); + + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1EN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2EN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBLPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCAPBLPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCAPBEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCEN); + io_clrbits32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); + io_clrbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK); + + /* Disable HW LP interface of uMCTL2 */ + io_clrbits32(ddrctrl_base + DDRCTRL_HWLPCTL, DDRCTRL_HWLPCTL_HW_LP_EN); + + /* Configure Automatic LP modes of uMCTL2 */ + io_clrsetbits32(ddrctrl_base + DDRCTRL_PWRTMG, + DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, + DDRCTRL_PWRTMG_SELFREF_TO_X32_0); + + /* + * Disable Clock disable with LP modes + * (used in RUN mode for LPDDR2 with specific timing). + */ + io_clrbits32(ddrctrl_base + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); + + /* Disable automatic Self-Refresh mode */ + io_clrbits32(ddrctrl_base + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_SELFREF_EN); +} + +static void ddr_sr_mode_asr(void) +{ + vaddr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR; + vaddr_t ddrctrl_base = get_ddrctrl_base(); + + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCLPEN); + io_clrsetbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK, + RCC_DDRITFCR_DDRCKMOD_ASR1); + + /* Enable HW LP interface of uMCTL2 */ + io_setbits32(ddrctrl_base + DDRCTRL_HWLPCTL, DDRCTRL_HWLPCTL_HW_LP_EN); + + /* Configure Automatic LP modes of uMCTL2 */ + io_clrsetbits32(ddrctrl_base + DDRCTRL_PWRTMG, + DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, + DDRCTRL_PWRTMG_SELFREF_TO_X32_0); + + /* + * Enable Clock disable with LP modes + * (used in RUN mode for LPDDR2 with specific timing). + */ + io_setbits32(ddrctrl_base + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); + + /* Enable automatic Self-Refresh for ASR mode */ + io_setbits32(ddrctrl_base + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_SELFREF_EN); +} + +static void ddr_sr_mode_hsr(void) +{ + vaddr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR; + vaddr_t ddrctrl_base = get_ddrctrl_base(); + + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); + io_clrbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); + io_clrbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN); + io_setbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCLPEN); + io_clrsetbits32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK, + RCC_DDRITFCR_DDRCKMOD_HSR1); + + /* Enable HW LP interface of uMCTL2 */ + io_setbits32(ddrctrl_base + DDRCTRL_HWLPCTL, DDRCTRL_HWLPCTL_HW_LP_EN); + + /* Configure Automatic LP modes of uMCTL2 */ + io_clrsetbits32(ddrctrl_base + DDRCTRL_PWRTMG, + DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, + DDRCTRL_PWRTMG_SELFREF_TO_X32_0); + + /* + * Enable Clock disable with LP modes + * (used in RUN mode for LPDDR2 with specific timing). + */ + io_setbits32(ddrctrl_base + DDRCTRL_PWRCTL, + DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); +} + +static enum stm32mp1_ddr_sr_mode ddr_read_sr_mode(void) +{ + uint32_t pwrctl = io_read32(get_ddrctrl_base() + DDRCTRL_PWRCTL); + uint32_t mask = DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | + DDRCTRL_PWRCTL_SELFREF_EN; + + switch (pwrctl & mask) { + case 0U: + return DDR_SSR_MODE; + + case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE: + return DDR_HSR_MODE; + + case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | DDRCTRL_PWRCTL_SELFREF_EN: + return DDR_ASR_MODE; + + default: + return DDR_SR_MODE_INVALID; + } +} + +static void ddr_set_sr_mode(enum stm32mp1_ddr_sr_mode mode) +{ + switch (mode) { + case DDR_SSR_MODE: + ddr_sr_mode_ssr(); + break; + + case DDR_HSR_MODE: + ddr_sr_mode_hsr(); + break; + + case DDR_ASR_MODE: + ddr_sr_mode_asr(); + break; + + default: + EMSG("Unknown Self Refresh mode\n"); + panic(); + } +} + +void ddr_save_sr_mode(enum stm32mp1_ddr_sr_mode mode) +{ + /* Save current mode before setting new one */ + saved_ddr_sr_mode = ddr_read_sr_mode(); + ddr_set_sr_mode(mode); +} + +void ddr_restore_sr_mode(void) +{ + ddr_set_sr_mode(saved_ddr_sr_mode); +} diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h new file mode 100644 index 000000000..e2d809bcd --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef __STM32MP1_DDRC_H__ +#define __STM32MP1_DDRC_H__ + +#include + +/* DDR Controller */ +/* DDR Controller registers offsets */ +#define DDRCTRL_MSTR 0x000 +#define DDRCTRL_STAT 0x004 +#define DDRCTRL_MRCTRL0 0x010 +#define DDRCTRL_MRSTAT 0x018 +#define DDRCTRL_PWRCTL 0x030 +#define DDRCTRL_PWRTMG 0x034 +#define DDRCTRL_HWLPCTL 0x038 +#define DDRCTRL_RFSHCTL3 0x060 +#define DDRCTRL_RFSHTMG 0x064 +#define DDRCTRL_INIT0 0x0D0 +#define DDRCTRL_DFIMISC 0x1B0 +#define DDRCTRL_DBG1 0x304 +#define DDRCTRL_DBGCAM 0x308 +#define DDRCTRL_DBGCMD 0x30C +#define DDRCTRL_DBGSTAT 0x310 +#define DDRCTRL_SWCTL 0x320 +#define DDRCTRL_SWSTAT 0x324 +#define DDRCTRL_PSTAT 0x3FC +#define DDRCTRL_PCTRL_0 0x490 +#define DDRCTRL_PCTRL_1 0x540 + +/* DDR Controller Register fields */ +#define DDRCTRL_MSTR_DDR3 BIT(0) +#define DDRCTRL_MSTR_LPDDR2 BIT(2) +#define DDRCTRL_MSTR_LPDDR3 BIT(3) +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK_32(13, 12) +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL 0 +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF BIT(12) +#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER BIT(13) +#define DDRCTRL_MSTR_DLL_OFF_MODE BIT(15) + +#define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK_32(2, 0) +#define DDRCTRL_STAT_OPERATING_MODE_NORMAL BIT(0) +#define DDRCTRL_STAT_OPERATING_MODE_SR (BIT(0) | BIT(1)) +#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK_32(5, 4) +#define DDRCTRL_STAT_SELFREF_TYPE_ASR (BIT(4) | BIT(5)) +#define DDRCTRL_STAT_SELFREF_TYPE_SR BIT(5) + +#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE 0 +/* only one rank supported */ +#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4 +#define DDRCTRL_MRCTRL0_MR_RANK_ALL \ + BIT(DDRCTRL_MRCTRL0_MR_RANK_SHIFT) +#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12 +#define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK_32(15, 12) +#define DDRCTRL_MRCTRL0_MR_WR BIT(31) + +#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0) + +#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) +#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) +#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) +#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) + +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK_32(19, 12) +#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16) + +#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0) + +#define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) + +#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK_32(27, 16) +#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16 + +#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK GENMASK_32(31, 30) +#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL BIT(30) + +#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0) + +#define DDRCTRL_DBG1_DIS_HIF BIT(1) + +#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29) +#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28) +#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26) +#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK_32(12, 8) +#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK_32(4, 0) + +#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \ + (DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \ + DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY) + +#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \ + (DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \ + DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \ + DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH) + +#define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0) + +#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0) + +#define DDRCTRL_SWCTL_SW_DONE BIT(0) + +#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0) + +#define DDRCTRL_PCTRL_N_PORT_EN BIT(0) + +/* DDR PHY registers offsets */ +#define DDRPHYC_PIR 0x004 +#define DDRPHYC_PGCR 0x008 +#define DDRPHYC_PGSR 0x00C +#define DDRPHYC_DLLGCR 0x010 +#define DDRPHYC_ACDLLCR 0x014 +#define DDRPHYC_PTR0 0x018 +#define DDRPHYC_ACIOCR 0x024 +#define DDRPHYC_DXCCR 0x028 +#define DDRPHYC_DSGCR 0x02C +#define DDRPHYC_ZQ0CR0 0x180 +#define DDRPHYC_DX0GCR 0x1C0 +#define DDRPHYC_DX0DLLCR 0x1CC +#define DDRPHYC_DX1GCR 0x200 +#define DDRPHYC_DX1DLLCR 0x20C +#define DDRPHYC_DX2GCR 0x240 +#define DDRPHYC_DX2DLLCR 0x24C +#define DDRPHYC_DX3GCR 0x280 +#define DDRPHYC_DX3DLLCR 0x28C + +/* DDR PHY Register fields */ +#define DDRPHYC_PIR_INIT BIT(0) +#define DDRPHYC_PIR_DLLSRST BIT(1) +#define DDRPHYC_PIR_DLLLOCK BIT(2) +#define DDRPHYC_PIR_ZCAL BIT(3) +#define DDRPHYC_PIR_ITMSRST BIT(4) +#define DDRPHYC_PIR_DRAMRST BIT(5) +#define DDRPHYC_PIR_DRAMINIT BIT(6) +#define DDRPHYC_PIR_QSTRN BIT(7) +#define DDRPHYC_PIR_ICPC BIT(16) +#define DDRPHYC_PIR_ZCALBYP BIT(30) +#define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7) + +#define DDRPHYC_PGCR_DFTCMP BIT(2) +#define DDRPHYC_PGCR_PDDISDX BIT(24) +#define DDRPHYC_PGCR_RFSHDT_MASK GENMASK_32(28, 25) + +#define DDRPHYC_PGSR_IDONE BIT(0) +#define DDRPHYC_PGSR_DTERR BIT(5) +#define DDRPHYC_PGSR_DTIERR BIT(6) +#define DDRPHYC_PGSR_DFTERR BIT(7) +#define DDRPHYC_PGSR_RVERR BIT(8) +#define DDRPHYC_PGSR_RVEIRR BIT(9) + +#define DDRPHYC_DLLGCR_BPS200 BIT(23) + +#define DDRPHYC_ACDLLCR_DLLSRST BIT(30) +#define DDRPHYC_ACDLLCR_DLLDIS BIT(31) + +#define DDRPHYC_PTR0_TDLLSRST_OFFSET 0 +#define DDRPHYC_PTR0_TDLLSRST_MASK GENMASK_32(5, 0) +#define DDRPHYC_PTR0_TDLLLOCK_OFFSET 6 +#define DDRPHYC_PTR0_TDLLLOCK_MASK GENMASK_32(17, 6) +#define DDRPHYC_PTR0_TITMSRST_OFFSET 18 +#define DDRPHYC_PTR0_TITMSRST_MASK GENMASK_32(21, 18) + +#define DDRPHYC_ACIOCR_ACOE BIT(1) +#define DDRPHYC_ACIOCR_ACPDD BIT(3) +#define DDRPHYC_ACIOCR_ACPDR BIT(4) +#define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK_32(10, 8) +#define DDRPHYC_ACIOCR_CKPDD_0 BIT(8) +#define DDRPHYC_ACIOCR_CKPDR_MASK GENMASK_32(13, 11) +#define DDRPHYC_ACIOCR_CKPDR_0 BIT(11) +#define DDRPHYC_ACIOCR_CSPDD_MASK GENMASK_32(21, 18) +#define DDRPHYC_ACIOCR_CSPDD_0 BIT(18) +#define DDRPHYC_ACIOCR_RSTPDD BIT(27) +#define DDRPHYC_ACIOCR_RSTPDR BIT(28) + +#define DDRPHYC_DXCCR_DXPDD BIT(2) +#define DDRPHYC_DXCCR_DXPDR BIT(3) + +#define DDRPHYC_DSGCR_CKEPDD_MASK GENMASK_32(19, 16) +#define DDRPHYC_DSGCR_CKEPDD_0 BIT(16) +#define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK_32(23, 20) +#define DDRPHYC_DSGCR_ODTPDD_0 BIT(20) +#define DDRPHYC_DSGCR_NL2PD BIT(24) + +#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK_32(27, 0) +#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0 +#define DDRPHYC_ZQ0CRN_ZDEN BIT(28) +#define DDRPHYC_ZQ0CRN_ZQPD BIT(31) + +#define DDRPHYC_DXNGCR_DXEN BIT(0) + +#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30) +#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31) +#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14) +#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14 + +/* DDR Self Refresh (SR) modes */ +enum stm32mp1_ddr_sr_mode { + DDR_SR_MODE_INVALID = 0, + DDR_SSR_MODE, + DDR_HSR_MODE, + DDR_ASR_MODE, +}; + +void ddr_save_sr_mode(enum stm32mp1_ddr_sr_mode mode); +void ddr_restore_sr_mode(void); + +/* Return 32bit calibration value used for DDRPHY */ +uint32_t get_ddrphy_calibration(void); + +/* + * Entry/exit DDR selfrefresh mode + * Return 0 on success and a non-null value on error + */ +int ddr_standby_sr_entry(void); +int ddr_standby_sr_exit(void); + +#endif /*__STM32MP1_DDRC_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c index 8d18ff94b..a7d755a0c 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) 2017-2020, STMicroelectronics + * Copyright (c) 2017-2021, STMicroelectronics */ #include @@ -36,6 +36,8 @@ static uint32_t pmic_i2c_addr; /* CPU voltage supplier if found */ static char cpu_supply_name[PMIC_REGU_SUPPLY_NAME_LEN]; +/* USB voltage supplier if found */ +static char *usb_supply_name; bool stm32mp_with_pmic(void) { @@ -372,6 +374,49 @@ const char *stm32mp_pmic_get_cpu_supply_name(void) return cpu_supply_name; } +/* Return a libfdt compliant status value */ +static int save_usb_supply_name(void) +{ + void *fdt = NULL; + int node = 0; + int subnode = 0; + const fdt32_t *cuint = NULL; + const char *name = NULL; + + fdt = get_embedded_dt(); + if (!fdt) + panic(); + + node = fdt_node_offset_by_compatible(fdt, -1, "st,stm32mp1-usbphyc"); + if (node < 0) + return -FDT_ERR_NOTFOUND; + + fdt_for_each_subnode(subnode, fdt, node) { + cuint = fdt_getprop(fdt, subnode, "phy-supply", NULL); + if (cuint) + break; + } + if (!cuint) + return -FDT_ERR_NOTFOUND; + + node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); + if (node < 0) + return -FDT_ERR_NOTFOUND; + + name = fdt_get_name(fdt, node, NULL); + assert(name); + usb_supply_name = strdup(name); + if (!usb_supply_name) + panic(); + + return 0; +} + +const char *stm32mp_pmic_get_usb_supply_name(void) +{ + return usb_supply_name; +} + /* Preallocate not that much regu references */ static char *nsec_access_regu_name[PMIC_REGU_COUNT]; @@ -452,6 +497,9 @@ static void parse_regulator_fdt_nodes(void) if (save_cpu_supply_name()) DMSG("No CPU supply provided"); + + if (save_usb_supply_name()) + DMSG("No USB supply provided"); } /* diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h index 4625af125..f91654733 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause */ /* - * Copyright (c) 2017-2020, STMicroelectronics + * Copyright (c) 2017-2021, STMicroelectronics */ #ifndef __STM32MP1_PMIC_H__ @@ -15,6 +15,7 @@ void stm32mp_get_pmic(void); void stm32mp_put_pmic(void); int stm32mp_dt_pmic_status(void); const char *stm32mp_pmic_get_cpu_supply_name(void); +const char *stm32mp_pmic_get_usb_supply_name(void); #else static inline void stm32mp_pmic_apply_boot_on_config(void) { @@ -43,6 +44,11 @@ static inline const char *stm32mp_pmic_get_cpu_supply_name(void) { return NULL; } + +static inline const char *stm32mp_pmic_get_usb_supply_name(void) +{ + return NULL; +} #endif #endif /*__STM32MP1_PMIC_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h index 9cedd9321..5783a5ca9 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h @@ -13,10 +13,41 @@ #define PWR_CR2_OFF 0x08 #define PWR_CR3_OFF 0x0c #define PWR_MPUCR_OFF 0x10 +#define PWR_MCUCR_OFF 0x14 #define PWR_WKUPCR_OFF 0x20 #define PWR_MPUWKUPENR_OFF 0x28 -#define PWR_OFFSET_MASK 0x3fUL +#define PWR_OFFSET_MASK GENMASK_32(5, 0) + +#define PWR_CR1_LPDS BIT(0) +#define PWR_CR1_LPCFG BIT(1) +#define PWR_CR1_LVDS BIT(2) +#define PWR_CR1_DBP BIT(8) + +#define PWR_CR2_BREN BIT(0) +#define PWR_CR2_RREN BIT(1) +#define PWR_CR2_BRRDY BIT(16) +#define PWR_CR2_RRRDY BIT(17) + +#define PWR_CR3_VBE BIT(8) +#define PWR_CR3_VBRS BIT(9) +#define PWR_CR3_DDRSREN BIT(10) +#define PWR_CR3_DDRSRDIS BIT(11) +#define PWR_CR3_DDRRETEN BIT(12) +#define PWR_CR3_USB33DEN BIT(24) +#define PWR_CR3_REG18EN BIT(28) +#define PWR_CR3_REG11EN BIT(30) + +#define PWR_MPUCR_PDDS BIT(0) +#define PWR_MPUCR_CSTDBYDIS BIT(3) +#define PWR_MPUCR_CSSF BIT(9) + +#define PWR_MCUCR_PDDS BIT(0) + +#define PWR_WKUPCR_MASK (GENMASK_32(27, 16) | \ + GENMASK_32(13, 8) | GENMASK_32(5, 0)) + +#define PWR_MPUWKUPENR_MASK GENMASK_32(5, 0) enum pwr_regulator { PWR_REG11 = 0, diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c index 37d2cb0dc..345a19807 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,7 @@ */ #define SYSCFG_CMPCR 0x20U #define SYSCFG_CMPENSETR 0x24U +#define SYSCFG_CMPENCLRR 0x28U /* * SYSCFG_CMPCR Register @@ -47,8 +49,8 @@ void stm32mp_syscfg_enable_io_compensation(void) vaddr_t syscfg_base = get_syscfg_base(); uint64_t timeout_ref = 0; - stm32_clock_enable(CK_CSI); - stm32_clock_enable(SYSCFG); + clk_enable(CK_CSI); + clk_enable(SYSCFG); io_setbits32(syscfg_base + SYSCFG_CMPENSETR, SYSCFG_CMPENSETR_MPU_EN); @@ -71,6 +73,9 @@ void stm32mp_syscfg_disable_io_compensation(void) vaddr_t syscfg_base = get_syscfg_base(); uint32_t value = 0; + /* No refcount balance needed on non-secure SYSCFG clock */ + clk_enable(SYSCFG); + value = io_read32(syscfg_base + SYSCFG_CMPCR) >> SYSCFG_CMPCR_ANSRC_SHIFT; @@ -84,10 +89,9 @@ void stm32mp_syscfg_disable_io_compensation(void) DMSG("SYSCFG.cmpcr = %#"PRIx32, io_read32(syscfg_base + SYSCFG_CMPCR)); - io_clrbits32(syscfg_base + SYSCFG_CMPENSETR, SYSCFG_CMPENSETR_MPU_EN); + io_setbits32(syscfg_base + SYSCFG_CMPENCLRR, SYSCFG_CMPENSETR_MPU_EN); - stm32_clock_disable(SYSCFG); - stm32_clock_disable(CK_CSI); + clk_disable(CK_CSI); } static TEE_Result stm32mp1_iocomp(void) diff --git a/core/arch/arm/plat-stm32mp1/drivers/sub.mk b/core/arch/arm/plat-stm32mp1/drivers/sub.mk index 42b6893f0..0b814a410 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/sub.mk +++ b/core/arch/arm/plat-stm32mp1/drivers/sub.mk @@ -1,4 +1,5 @@ -srcs-y += stm32mp1_clk.c +srcs-$(CFG_STM32_CLKCALIB) += stm32mp1_calib.c +srcs-y += stm32mp1_ddrc.c srcs-$(CFG_STPMIC1) += stm32mp1_pmic.c srcs-y += stm32mp1_pwr.c srcs-y += stm32mp1_rcc.c diff --git a/core/arch/arm/plat-stm32mp1/link.mk b/core/arch/arm/plat-stm32mp1/link.mk index 01a9b8ed5..fa1465a45 100644 --- a/core/arch/arm/plat-stm32mp1/link.mk +++ b/core/arch/arm/plat-stm32mp1/link.mk @@ -1,5 +1,6 @@ include core/arch/arm/kernel/link.mk +ifeq ($(CFG_STM32MP15x_STM32IMAGE),y) # Create stm32 formatted images from the native binary images define stm32image_cmd @@ -22,3 +23,4 @@ all: $(link-out-dir)/tee-pageable_v2.stm32 cleanfiles += $(link-out-dir)/tee-pageable_v2.stm32 $(link-out-dir)/tee-pageable_v2.stm32: $(link-out-dir)/tee-pageable_v2.bin $(stm32image_cmd) --source $< --dest $@ --bintype 0x22 +endif diff --git a/core/arch/arm/plat-stm32mp1/main.c b/core/arch/arm/plat-stm32mp1/main.c index 9dca331c7..bf2e394fb 100644 --- a/core/arch/arm/plat-stm32mp1/main.c +++ b/core/arch/arm/plat-stm32mp1/main.c @@ -1,23 +1,30 @@ // SPDX-License-Identifier: BSD-2-Clause /* - * Copyright (c) 2017-2018, STMicroelectronics * Copyright (c) 2016-2018, Linaro Limited + * Copyright (c) 2017-2021, STMicroelectronics */ #include #include #include +#include #include #include -#include +#include #include +#include +#include +#include #include +#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -29,7 +36,10 @@ register_phys_mem_pgdir(MEM_AREA_IO_NSEC, GPIOS_NSEC_BASE, GPIOS_NSEC_SIZE); #endif register_phys_mem_pgdir(MEM_AREA_IO_NSEC, I2C4_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_NSEC, I2C6_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_NSEC, IWDG1_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_NSEC, IWDG2_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_NSEC, RNG1_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_NSEC, RTC_BASE, SMALL_PAGE_SIZE); #ifdef CFG_WITH_NSEC_UARTS register_phys_mem_pgdir(MEM_AREA_IO_NSEC, USART1_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_NSEC, USART2_BASE, SMALL_PAGE_SIZE); @@ -41,17 +51,38 @@ register_phys_mem_pgdir(MEM_AREA_IO_NSEC, UART7_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_NSEC, UART8_BASE, SMALL_PAGE_SIZE); #endif +register_phys_mem_pgdir(MEM_AREA_IO_SEC, BKPSRAM_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, BSEC_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, DBGMCU_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, DDRCTRL_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, DDRPHYC_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, ETZPC_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, GIC_BASE, GIC_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, GPIOZ_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, I2C4_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, I2C6_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, IWDG1_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, PWR_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, RCC_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, RNG1_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, RTC_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, STGEN_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, SYSCFG_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, TAMP_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM1_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM2_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM3_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM4_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM5_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM6_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM7_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM8_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM12_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM13_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM14_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM15_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM16_BASE, SMALL_PAGE_SIZE); +register_phys_mem_pgdir(MEM_AREA_IO_SEC, TIM17_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, TZC_BASE, SMALL_PAGE_SIZE); register_phys_mem_pgdir(MEM_AREA_IO_SEC, USART1_BASE, SMALL_PAGE_SIZE); @@ -66,6 +97,20 @@ register_dynamic_shm(DDR_BASE, CFG_TZDRAM_START - DDR_BASE); register_dynamic_shm(TZDRAM_END, DRAM_END - TZDRAM_END); #endif +/* Map non-secure DDR bottom for the low power sequence */ +register_phys_mem(MEM_AREA_RAM_NSEC, DDR_BASE, SMALL_PAGE_SIZE); + +#ifdef CFG_RPROC_PTA +/* Map MCU RETRAM as read write for Cortex-M4 firmware management */ +register_phys_mem(MEM_AREA_IO_SEC, RETRAM_BASE, RETRAM_SIZE); + +/* Map MCU SRAM as read write for Cortex-M4 firmware management */ +register_phys_mem(MEM_AREA_IO_SEC, MCUSRAM_BASE, MCUSRAM_SIZE); +#endif + +/* Map TEE physical RAM as read-only for content storage when suspending */ +register_phys_mem(MEM_AREA_ROM_SEC, TEE_RAM_START, TEE_RAM_PH_SIZE); + #define _ID2STR(id) (#id) #define ID2STR(id) _ID2STR(id) @@ -168,8 +213,106 @@ static TEE_Result init_console_from_dt(void) /* Probe console from DT once clock inits (service init level) are completed */ service_init_late(init_console_from_dt); + +static TEE_Result initialize_pll1_settings(void) +{ + uint32_t cpu_voltage = 0U; + int ret = 0; + + if (stm32mp1_clk_pll1_settings_are_valid()) + return TEE_SUCCESS; + + if (stm32mp_dt_pmic_status() > 0) { + stm32mp_get_pmic(); + + ret = stpmic1_regulator_voltage_get( + stm32mp_pmic_get_cpu_supply_name()); + if (ret < 0) + return ret; + + cpu_voltage = (uint32_t)ret; + + stm32mp_put_pmic(); + } + + if (stm32mp1_clk_compute_all_pll1_settings(cpu_voltage)) + panic(); + + return TEE_SUCCESS; +} + +/* Compute PLL1 settings once PMIC init is completed */ +driver_init_late(initialize_pll1_settings); + +static TEE_Result disable_usb_phy_regulator(void) +{ + if (stm32mp_dt_pmic_status() > 0) { + const char *name = stm32mp_pmic_get_usb_supply_name(); + + if (!name) + return TEE_SUCCESS; + + stm32mp_get_pmic(); + if (stpmic1_regulator_disable(name)) + panic(); + + stm32mp_put_pmic(); + } + + return TEE_SUCCESS; +} + +/* Disable USB regulator to avoid initialization issues */ +boot_final(disable_usb_phy_regulator); #endif +static uintptr_t stm32_dbgmcu_base(void) +{ + static void *va; + + if (!cpu_mmu_enabled()) + return DBGMCU_BASE; + + if (!va) + va = phys_to_virt(DBGMCU_BASE, MEM_AREA_IO_SEC); + + return (uintptr_t)va; +} + +/* SoC versioning util, returns default ID if can't access DBGMCU */ +TEE_Result stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version) +{ + uint32_t id = STM32MP1_CHIP_DEFAULT_VERSION; + + if (!chip_version) + return TEE_ERROR_BAD_PARAMETERS; + + if (stm32_bsec_read_debug_conf() & BSEC_DBGSWGEN) + id = (io_read32(stm32_dbgmcu_base() + DBGMCU_IDC) & + DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT; + + *chip_version = id; + + return TEE_SUCCESS; +} + +/* SoC device ID util, returns default ID if can't access DBGMCU */ +TEE_Result stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id) +{ + uint32_t id = STM32MP1_CHIP_ID; + + if (!chip_dev_id) + return TEE_ERROR_BAD_PARAMETERS; + + if (stm32_bsec_read_debug_conf() & BSEC_DBGSWGEN) + id = io_read32(stm32_dbgmcu_base() + DBGMCU_IDC) & + DBGMCU_IDC_DEV_ID_MASK; + + *chip_dev_id = id; + + return TEE_SUCCESS; +} + /* * GIC init, used also for primary/secondary boot core wake completion */ @@ -212,7 +355,11 @@ static TEE_Result init_stm32mp1_drivers(void) (SYSRAM_SEC_SIZE >= CFG_TZSRAM_SIZE))); etzpc_configure_tzma(1, SYSRAM_SEC_SIZE >> SMALL_PAGE_SHIFT); +#ifdef STM32MP1_USE_MPU0_RESET + /* BootROM needs unlocked for independent reset */ +#else etzpc_lock_tzma(1); +#endif return TEE_SUCCESS; } @@ -241,12 +388,20 @@ void stm32mp_get_bsec_static_cfg(struct stm32_bsec_static_cfg *cfg) bool stm32mp_is_closed_device(void) { - uint32_t otp = 0; + uint32_t otp_id = 0; + size_t bit_len = 0; + uint32_t otp_value = 0; TEE_Result result = TEE_ERROR_GENERIC; + if (stm32_bsec_find_otp_in_nvmem_layout(CFG0_OTP, &otp_id, &bit_len)) + panic(); + + if (bit_len != 8) + panic(); + /* Non closed_device platform expects fuse well programmed to 0 */ - result = stm32_bsec_shadow_read_otp(&otp, DATA0_OTP); - if (!result && !(otp & BIT(DATA0_OTP_SECURED_POS))) + result = stm32_bsec_shadow_read_otp(&otp_value, otp_id); + if (!result && !(otp_value & BIT(CFG0_OTP_SECURED_POS))) return false; return true; @@ -290,6 +445,20 @@ vaddr_t stm32mp_bkpreg(unsigned int idx) return bkpreg_base() + (idx * sizeof(uint32_t)); } +vaddr_t stm32mp_bkpsram_base(void) +{ + struct io_pa_va base = { .pa = BKPSRAM_BASE }; + + return io_pa_or_va(&base); +} + +vaddr_t stm32mp_stgen_base(void) +{ + struct io_pa_va base = { .pa = STGEN_BASE }; + + return io_pa_or_va(&base); +} + vaddr_t stm32_get_gpio_bank_base(unsigned int bank) { static struct io_pa_va gpios_nsec_base = { .pa = GPIOS_NSEC_BASE }; @@ -322,3 +491,178 @@ unsigned int stm32_get_gpio_bank_clock(unsigned int bank) assert(bank <= GPIO_BANK_K); return GPIOA + bank; } + +static int get_part_number(uint32_t *part_nb) +{ + uint32_t part_number = 0; + uint32_t dev_id = 0; + uint32_t otp = 0; + size_t bit_len = 0; + + assert(part_nb); + + if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id)) + return -1; + + if (stm32_bsec_find_otp_in_nvmem_layout(PART_NUMBER_OTP, + &otp, &bit_len)) + return -1; + + if (bit_len != 8) + panic(); + + if (stm32_bsec_read_otp(&part_number, otp)) + return -1; + + part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >> + PART_NUMBER_OTP_PART_SHIFT; + + *part_nb = part_number | (dev_id << 16); + + return 0; +} + +bool stm32mp_supports_cpu_opp(uint32_t opp_id) +{ + uint32_t part_number = 0; + uint32_t id = 0; + + if (get_part_number(&part_number)) { + DMSG("Cannot get part number\n"); + panic(); + } + + switch (opp_id) { + case PLAT_OPP_ID1: + case PLAT_OPP_ID2: + id = opp_id; + break; + default: + return false; + } + + switch (part_number) { + case STM32MP157F_PART_NB: + case STM32MP157D_PART_NB: + case STM32MP153F_PART_NB: + case STM32MP153D_PART_NB: + case STM32MP151F_PART_NB: + case STM32MP151D_PART_NB: + return true; + default: + return id == PLAT_OPP_ID1; + } +} + +enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode) +{ + switch (mode) { + case DECPROT_S_RW: + return ETZPC_DECPROT_S_RW; + case DECPROT_NS_R_S_W: + return ETZPC_DECPROT_NS_R_S_W; + case DECPROT_MCU_ISOLATION: + return ETZPC_DECPROT_MCU_ISOLATION; + case DECPROT_NS_RW: + return ETZPC_DECPROT_NS_RW; + default: + panic(); + } +} + +unsigned int stm32mp_iwdg_irq2instance(size_t irq) +{ + int id = irq - STM32MP1_IRQ_IWDG1; + + assert(id >= IWDG1_INST && id <= IWDG2_INST); + return (unsigned int)id; +} + +size_t stm32mp_iwdg_instance2irq(unsigned int instance) +{ + return instance + STM32MP1_IRQ_IWDG1; +} + +unsigned int stm32mp_iwdg_iomem2instance(vaddr_t pbase) +{ + switch (pbase) { + case IWDG1_BASE: + return IWDG1_INST; + case IWDG2_BASE: + return IWDG2_INST; + default: + panic(); + } +} + +unsigned long stm32_get_iwdg_otp_config(vaddr_t pbase) +{ + unsigned int idx = 0; + unsigned long iwdg_cfg = 0; + uint32_t otp_id = 0; + size_t bit_len = 0; + uint32_t otp_value = 0; + + idx = stm32mp_iwdg_iomem2instance(pbase); + + if (stm32_bsec_find_otp_in_nvmem_layout(HW2_OTP, &otp_id, &bit_len)) + panic(); + + if (bit_len != 32) + panic(); + + if (stm32_bsec_read_otp(&otp_value, otp_id)) + panic(); + + if (otp_value & BIT(idx + HW2_OTP_IWDG_HW_ENABLE_SHIFT)) + iwdg_cfg |= IWDG_HW_ENABLED; + + if (otp_value & BIT(idx + HW2_OTP_IWDG_FZ_STOP_SHIFT)) + iwdg_cfg |= IWDG_DISABLE_ON_STOP; + + if (otp_value & BIT(idx + HW2_OTP_IWDG_FZ_STANDBY_SHIFT)) + iwdg_cfg |= IWDG_DISABLE_ON_STANDBY; + + return iwdg_cfg; +} + +#ifdef CFG_STM32_RTC +/* + * Return true if RTC needs to be read twice not once for a reliable value. + * + * This function determines the number of needed RTC calendar read operations + * to get consistent values: RTC may need to be read twice depending on clock + * frequencies. + * If APB1 frequency is less than 7 times the RTC one, the software has to + * read the calendar time and date register twice. + */ +bool stm32_rtc_get_read_twice(void) +{ + unsigned long apb1_freq = 0; + unsigned long rtc_freq = 0; + uint32_t apb1_div = 0; + vaddr_t rcc_base = stm32_rcc_base(); + + switch ((io_read32(rcc_base + RCC_BDCR) & + RCC_BDCR_RTCSRC_MASK) >> RCC_BDCR_RTCSRC_SHIFT) { + case 1: + rtc_freq = clk_get_rate(CK_LSE); + break; + case 2: + rtc_freq = clk_get_rate(CK_LSI); + break; + case 3: + rtc_freq = clk_get_rate(CK_HSE); + rtc_freq /= (io_read32(rcc_base + RCC_RTCDIVR) & + RCC_DIVR_DIV_MASK) + 1U; + break; + default: + panic(); + } + + apb1_div = io_read32(rcc_base + RCC_APB1DIVR) & RCC_APBXDIV_MASK; + apb1_freq = clk_get_rate(CK_MCU) >> apb1_div; + + return apb1_freq < (rtc_freq * 7U); +} +#endif diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.c b/core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.c new file mode 100644 index 000000000..486977baa --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stm32mp1_smc.h" +#include "low_power_svc.h" +#include "../pm/power.h" +#include "../pm/context.h" + +#undef DDR_SR_TEST + +#ifdef DDR_SR_TEST +uint32_t sr_mode_scv_handler(uint32_t __maybe_unused x1, uint32_t x2) +{ + unsigned int mode = x2; + + DMSG("DDR selfrefresh mode 0x%" PRIx32 ", 0x%" PRIx32, mode, x1); + + switch (mode) { + case STM32_SIP_SVC_SR_MODE_SSR: + ddr_sr_mode_ssr(); + break; + case STM32_SIP_SVC_SR_MODE_ASR: + ddr_sr_mode_asr(); + break; + case STM32_SIP_SVC_SR_MODE_HSR: + ddr_sr_mode_hsr(); + break; + default: + return STM32_SIP_SVC_INVALID_PARAMS; + } + + return STM32_SIP_SVC_OK; +} +#else +uint32_t sr_mode_scv_handler(uint32_t __unused x1, uint32_t __unused x2) +{ + return STM32_SIP_SVC_FAILED; +} +#endif + +uint32_t cstop_scv_handler(struct sm_ctx __unused *ctx, uint32_t __unused x1, + uint32_t __unused x2, uint32_t __unused x3) +{ + DMSG("core %u", get_core_pos()); + + stm32mp1_set_lp_deepest_soc_mode(PSCI_MODE_SYSTEM_SUSPEND, + STM32_PM_CSTOP_ALLOW_LPLV_STOP); + + return (psci_system_suspend(ctx->nsec.mon_lr, 0, &ctx->nsec) == 0) ? + STM32_SIP_SVC_OK : STM32_SIP_SVC_FAILED; +} + +uint32_t standby_scv_handler(struct sm_ctx *ctx, uint32_t __unused x1, + uint32_t __unused x2, uint32_t x3) +{ + uint32_t nsec_resume_ep = x3; + + DMSG("core %u", get_core_pos()); + + if (nsec_resume_ep == 0U) { + shutdown_scv_handler(); + panic(); + } + + stm32mp1_set_lp_deepest_soc_mode(PSCI_MODE_SYSTEM_SUSPEND, + STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR); + + return (psci_system_suspend(nsec_resume_ep, 0, &ctx->nsec) == 0) ? + STM32_SIP_SVC_OK : STM32_SIP_SVC_FAILED; +} + +uint32_t shutdown_scv_handler(void) +{ + DMSG("core %u", get_core_pos()); + + if (!stm32mp_with_pmic()) { + return STM32_SIP_SVC_FAILED; + } + + psci_system_off(); + panic(); +} + +uint32_t pm_domain_scv_handler(uint32_t id, uint32_t enable) +{ + unsigned int pd = id; + + DMSG("%sable PD %u", enable != 0 ? "En" : "Dis", pd); + + switch (pd) { + case STM32MP1_PD_VSW: + case STM32MP1_PD_CORE_RET: + case STM32MP1_PD_CORE: + break; + default: + return STM32_SIP_SVC_INVALID_PARAMS; + } + + stm32mp1_set_pm_domain_state(pd, enable); + + return STM32_SIP_SVC_OK; +} + +#ifdef CFG_TEE_CORE_DEBUG +uint32_t pm_set_lp_state_scv_handler(uint32_t request, uint32_t state) +{ + uint32_t power_mode; + + switch (request) { + case STM32_OEM_SVC_LP_FORCE_SUSPEND_PARAMS: + DMSG("Set suspend mode to %u", state); + power_mode = PSCI_MODE_SYSTEM_SUSPEND; + break; + case STM32_OEM_SVC_LP_FORCE_OFF_PARAMS: + DMSG("Set off mode to %u", state); + power_mode = PSCI_MODE_SYSTEM_OFF; + break; + default: + return STM32_OEM_SVC_INVALID_PARAMS; + } + + if (stm32mp1_set_lp_deepest_soc_mode(power_mode, state) < 0) { + return STM32_OEM_SVC_FAILED; + } + + return STM32_OEM_SVC_OK; +} +#else +uint32_t pm_set_lp_state_scv_handler(uint32_t __unused mode, + uint32_t __unused state) +{ + return STM32_SIP_SVC_FAILED; +} +#endif diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.h b/core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.h new file mode 100644 index 000000000..3d7d247d9 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/nsec-service/low_power_svc.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2018, STMicroelectronics + */ + +#ifndef LOW_POWER_SVC_H +#define LOW_POWER_SVC_H + +#include +#include + +#ifdef CFG_STM32_LOWPOWER_SIP +uint32_t sr_mode_scv_handler(uint32_t x1, uint32_t x2); +uint32_t cstop_scv_handler(struct sm_ctx *nsec, + uint32_t x1, uint32_t x2, uint32_t x3); +uint32_t standby_scv_handler(struct sm_ctx *nsec, + uint32_t x1, uint32_t x2, uint32_t x3); +uint32_t shutdown_scv_handler(void); +uint32_t pm_domain_scv_handler(uint32_t x1, uint32_t x2); + +uint32_t pm_set_lp_state_scv_handler(uint32_t x1, uint32_t x2); +#else +uint32_t sr_mode_scv_handler(uint32_t x1 __unused, uint32_t x2 __unused) +{ + return STM32_SIP_SVC_FAILED; +} + +uint32_t cstop_scv_handler(struct sm_ctx *nsec __unused, uint32_t x1 __unused, + uint32_t x2 __unused, uint32_t x3 __unused) +{ + return STM32_SIP_SVC_FAILED; +} + +uint32_t standby_scv_handler(struct sm_ctx *nsec __unused, uint32_t x1 __unused, + uint32_t x2 __unused, uint32_t x3 __unused) +{ + return STM32_SIP_SVC_FAILED; +} + +uint32_t shutdown_scv_handler(void) +{ + return STM32_SIP_SVC_FAILED; +} + +uint32_t pm_domain_scv_handler(uint32_t x1 __unused, uint32_t x2 __unused) +{ + return STM32_SIP_SVC_FAILED; +} + +uint32_t pm_set_lp_state_scv_handler(uint32_t x1 __unused, uint32_t x2 __unused) +{ + return STM32_SIP_SVC_FAILED; +} +#endif /* CFG_STM32_LOWPOWER_SIP */ +#endif /* LOW_POWER_SVC_H */ diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.c b/core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.c new file mode 100644 index 000000000..6c78d8203 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2018, STMicroelectronics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwr_svc.h" +#include "stm32mp1_smc.h" + +struct pwr_reg_prop { + uint32_t offset; + uint32_t mask; +}; + +#define PWR_ALLOWED_MASK(_off, _mask) { .offset = (_off), .mask = (_mask), } + +static const struct pwr_reg_prop allowed_regs[] = { + PWR_ALLOWED_MASK(PWR_CR3_OFF, PWR_CR3_VBE | PWR_CR3_VBRS | + PWR_CR3_USB33DEN | + PWR_CR3_REG18EN | PWR_CR3_REG11EN), + PWR_ALLOWED_MASK(PWR_WKUPCR_OFF, PWR_WKUPCR_MASK), + PWR_ALLOWED_MASK(PWR_MPUWKUPENR_OFF, PWR_MPUWKUPENR_MASK), +}; + +uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3) +{ + uint32_t req = x1; + uint32_t offset = x2; + uint32_t value = x3; + vaddr_t va = 0; + uint32_t allowed = 0; + unsigned int i = 0; + + /* + * Argument x2 can be either the register physical address of the + * register offset toward PWR_BASE. + */ + if ((offset & ~PWR_OFFSET_MASK) != 0) { + if ((offset & ~PWR_OFFSET_MASK) != PWR_BASE) + return STM32_SIP_SVC_INVALID_PARAMS; + + offset &= PWR_OFFSET_MASK; + } + + DMSG("PWR service: %s 0x%" PRIx32 " at offset 0x%" PRIx32, + req == STM32_SIP_SVC_REG_WRITE ? "write" : + req == STM32_SIP_SVC_REG_SET ? "set" : "clear", + value, offset); + + for (i = 0; i < ARRAY_SIZE(allowed_regs); i++) { + if (offset != allowed_regs[i].offset) + continue; + + va = stm32_pwr_base() + offset; + allowed = allowed_regs[i].mask; + value &= allowed; + + switch (req) { + case STM32_SIP_SVC_REG_WRITE: + io_mask32_stm32shregs(va, value, allowed); + FMSG("wrt off %" PRIx32 "=%" PRIx32 " => %" PRIx32, + offset, value, io_read32(va)); + return STM32_SIP_SVC_OK; + case STM32_SIP_SVC_REG_SET: + io_setbits32_stm32shregs(va, value); + FMSG("set off %" PRIx32 "=%" PRIx32 " => %" PRIx32, + offset, value, io_read32(va)); + return STM32_SIP_SVC_OK; + case STM32_SIP_SVC_REG_CLEAR: + io_clrbits32_stm32shregs(va, value); + FMSG("clr off %" PRIx32 "=%" PRIx32 " => %" PRIx32, + offset, value, io_read32(va)); + return STM32_SIP_SVC_OK; + default: + return STM32_SIP_SVC_INVALID_PARAMS; + } + } + + return STM32_SIP_SVC_INVALID_PARAMS; +} diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.h b/core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.h new file mode 100644 index 000000000..429d62071 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/nsec-service/pwr_svc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2017-2018, STMicroelectronics + */ + +#ifndef __PWR_SVC_H__ +#define __PWR_SVC_H__ + +#include + +#ifdef CFG_STM32_PWR_SIP +uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3); +#else +static inline uint32_t pwr_scv_handler(uint32_t x1 __unused, + uint32_t x2 __unused, + uint32_t x3 __unused) +{ + return STM32_SIP_SVC_FAILED; +} +#endif + +#endif /* __PWR_SVC_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.c b/core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.c new file mode 100644 index 000000000..b4307b065 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2019, STMicroelectronics + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rcc_svc.h" +#include "stm32mp1_smc.h" + +static bool offset_is_clear_register(uint32_t __maybe_unused offset) +{ + /* All allowed registers are non set/clear registers */ + return false; +} + +static void access_allowed_mask(uint32_t request, uint32_t offset, + uint32_t value, uint32_t allowed_mask) +{ + vaddr_t va = stm32_rcc_base() + offset; + + if (!allowed_mask) + return; + + switch (request) { + case STM32_SIP_SVC_REG_WRITE: + if (offset_is_clear_register(offset)) { + /* CLR registers show SET state, not CLR state */ + io_write32(va, value & allowed_mask); + } else { + io_mask32_stm32shregs(va, value, allowed_mask); + } + FMSG("wrt 0x%" PRIx32 "=0x%" PRIx32 " => 0x%" PRIx32, + offset, value, io_read32(va)); + break; + + case STM32_SIP_SVC_REG_SET: + if (offset_is_clear_register(offset)) { + /* CLR registers show SET state, not CLR state */ + io_write32(va, value & allowed_mask); + } else { + io_setbits32_stm32shregs(va, value & allowed_mask); + } + FMSG("set 0x%" PRIx32 "=0x%" PRIx32 " => 0x%" PRIx32, + offset, value, io_read32(va)); + break; + + case STM32_SIP_SVC_REG_CLEAR: + /* Nothing to do on CLR registers */ + if (!offset_is_clear_register(offset)) + io_clrbits32_stm32shregs(va, value & allowed_mask); + FMSG("clear 0x%" PRIx32 "=0x%" PRIx32 " => 0x%" PRIx32, + offset, value, io_read32(va)); + break; + + default: + break; + } +} + +static uint32_t raw_allowed_access_request(uint32_t request, + uint32_t offset, uint32_t value) +{ + uint32_t allowed_mask = 0; + + switch (offset) { + case RCC_MP_CIER: + case RCC_MP_CIFR: + allowed_mask = RCC_MP_CIFR_WKUPF; + break; + case RCC_MP_GCR: + allowed_mask = RCC_MP_GCR_BOOT_MCU; + break; + default: + return STM32_SIP_SVC_INVALID_PARAMS; + } + + access_allowed_mask(request, offset, value, allowed_mask); + + return STM32_SIP_SVC_OK; +} + +uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3) +{ + uint32_t request = x1; + uint32_t offset = x2; + uint32_t value = x3; + + /* + * Argument x2 can be either the register physical address of the + * register offset toward RCC_BASE. + */ + if (offset & ~RCC_OFFSET_MASK) { + if ((offset & ~RCC_OFFSET_MASK) != RCC_BASE) + return STM32_SIP_SVC_INVALID_PARAMS; + + offset &= RCC_OFFSET_MASK; + } + + DMSG_RAW("RCC service: %s 0x%" PRIx32 " at offset 0x%" PRIx32, + request == STM32_SIP_SVC_REG_WRITE ? "write" : + request == STM32_SIP_SVC_REG_SET ? "set" : "clear", + value, offset); + + return raw_allowed_access_request(request, offset, value); +} + +uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res) +{ + uint32_t cmd = x1; + uint32_t opp = x2 / 1000U; /* KHz */ + + switch (cmd) { + case STM32_SIP_SVC_RCC_OPP_SET: + if (stm32mp1_set_opp_khz(opp)) + return STM32_SIP_SVC_FAILED; + break; + + case STM32_SIP_SVC_RCC_OPP_ROUND: + if(stm32mp1_round_opp_khz(&opp)) + return STM32_SIP_SVC_FAILED; + + if (MUL_OVERFLOW(opp, 1000, res)) + return STM32_SIP_SVC_FAILED; + break; + + default: + return STM32_SIP_SVC_INVALID_PARAMS; + } + + return STM32_SIP_SVC_OK; +} diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.h b/core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.h new file mode 100644 index 000000000..873458f49 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/nsec-service/rcc_svc.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2017-2019, STMicroelectronics + */ + +#ifndef RCC_SVC_H +#define RCC_SVC_H + +#include + +#ifdef CFG_STM32_RCC_SIP +uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3); +uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res); +#else +static inline uint32_t rcc_scv_handler(uint32_t x1 __unused, + uint32_t x2 __unused, + uint32_t x3 __unused) +{ + return STM32_SIP_SVC_FAILED; +} +static inline uint32_t rcc_opp_scv_handler(uint32_t x1 __unused, + uint32_t x2 __unused, + uint32_t *res __unused) + +{ + return STM32_SIP_SVC_FAILED; +} +#endif + +#endif /*RCC_SVC_H*/ diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_smc.h b/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_smc.h index 3fbde31fe..a1f0e5859 100644 --- a/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_smc.h +++ b/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_smc.h @@ -14,7 +14,7 @@ #define STM32_SIP_SVC_VERSION_MAJOR 0x0 #define STM32_SIP_SVC_VERSION_MINOR 0x1 -#define STM32_SIP_SVC_FUNCTION_COUNT 0x3 +#define STM32_SIP_SVC_FUNCTION_COUNT 12 /* STM32 SIP service generic return codes */ #define STM32_SIP_SVC_OK 0x0 @@ -71,6 +71,51 @@ */ #define STM32_SIP_SVC_FUNC_VERSION 0xff03 +/* + * SIP function STM32_SIP_SVC_FUNC_RCC + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (input) Service ID (STM32_SIP_SVC_REG_xxx) + * Argument a2: (input) register offset or physical address + * (output) register read value, if applicable + * Argument a3: (input) register target value if applicable + */ +#define STM32_SIP_SVC_FUNC_RCC 0x1000 + +/* Service ID for STM32_SIP_FUNC_RCC */ +#define STM32_SIP_SVC_REG_READ 0x0 +#define STM32_SIP_SVC_REG_WRITE 0x1 +#define STM32_SIP_SVC_REG_SET 0x2 +#define STM32_SIP_SVC_REG_CLEAR 0x3 + +/* + * SIP functions STM32_SIP_SVC_FUNC_CAL + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (input) Clock ID (from DT clock bindings) + */ +#define STM32_SIP_SVC_FUNC_CAL 0x1002 + +/* + * SIP functions STM32_SIP_FUNC_PWR + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (input) Service ID (STM32_SIP_REG_xxx) + * Argument a2: (input) register offset or physical address + * (output) register read value, if applicable + * Argument a3: (input) register target value if applicable + */ +#define STM32_SIP_SVC_FUNC_PWR 0x1001 + +/* Service ID for STM32_SIP_SVC_FUNC_RCC/_PWR */ +#define STM32_SIP_SVC_REG_READ 0x0 +#define STM32_SIP_SVC_REG_WRITE 0x1 +#define STM32_SIP_SVC_REG_SET 0x2 +#define STM32_SIP_SVC_REG_CLEAR 0x3 + /* * SIP functions STM32_SIP_SVC_FUNC_BSEC * @@ -92,6 +137,91 @@ /* reserved for STM32_SIP_SVC_SMC_WRITE_ALL 0x6 */ #define STM32_SIP_SVC_BSEC_WRLOCK_OTP 0x7 +/* + * SIP functions STM32_SIP_FUNC_SR_MODE + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (unused) + * Argument a2: (input) Target selfrefresh mode + */ +#define STM32_SIP_FUNC_SR_MODE 0x1004 + +/* DDR Self-Refresh modes */ +#define STM32_SIP_SR_MODE_SSR 0x0 +#define STM32_SIP_SR_MODE_ASR 0x1 +#define STM32_SIP_SR_MODE_HSR 0x2 + +/* + * SIP functions STM32_SIP_FUNC_CSTOP + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (unused) + * Argument a2: (unused) + * Argument a3: (input) Target SoC mode + */ +#define STM32_SIP_FUNC_CSTOP 0x1005 + +/* Valid SoC modes used for CSTOP, */ +#define STM32_SIP_CSLEEP_RUN 0x0 +#define STM32_SIP_CSTOP_ALLOW_STOP 0x1 +#define STM32_SIP_CSTOP_ALLOW_LP_STOP 0x2 +#define STM32_SIP_CSTOP_ALLOW_LPLV_STOP 0x3 +#define STM32_SIP_CSTOP_ALLOW_STANDBY 0x4 +#define STM32_SIP_CSTOP_ALLOW_STANDBY_DDR_OFF 0x5 +#define STM32_SIP_CSTOP_SHUTDOWN 0x6 + +/* + * SIP functions STM32_SIP_FUNC_STANDBY + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a1: (unused) + * Argument a2: (unused) + * Argument a3: (input) non null only for DDR off standby + */ +#define STM32_SIP_FUNC_STANDBY 0x1006 + +/* + * SIP function STM32_SIP_FUNC_SHUTDOWN + * + * Argument a0: (input) SMCC ID + * (output) status return code + */ +#define STM32_SIP_FUNC_SHUTDOWN 0x1007 + +/* + * SIP function STM32_SIP_FUNC_PD_DOMAIN + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a2: (index) ID of target power domain to be enabled/disabled + * Argument a3: (input) 0 to disable, 1 to eanble target domain + */ +#define STM32_SIP_FUNC_PD_DOMAIN 0x1008 + +/* Valid IDs for power domain for function STM32_SIP_FUNC_PD_DOMAIN */ +#define STM32_SIP_PD_VSW 0x0 +#define STM32_SIP_PD_CORE_RET 0x1 +#define STM32_SIP_PD_CORE 0x2 +#define STM32_SIP_PD_MAX_PM_DOMAIN 0x3 + +/* + * SIP function STM32_SIP_FUNC_RCC_OPP. + * + * Argument a0: (input) SMCC ID. + * (output) Status return code. + * Argument a1: (input) Service ID (STM32_SIP_RCC_OPP_xxx). + * (output) Rounded frequency, if applicable. + * Argument a2: (input) Requested frequency. + */ +#define STM32_SIP_SVC_FUNC_RCC_OPP 0x1009 + +/* Service ID for STM32_SIP_FUNC_RCC_OPP */ +#define STM32_SIP_SVC_RCC_OPP_SET 0x0 +#define STM32_SIP_SVC_RCC_OPP_ROUND 0x1 + /* * SIP function STM32_SIP_SVC_FUNC_SCMI_AGENT0 * SIP function STM32_SIP_SVC_FUNC_SCMI_AGENT1 @@ -103,4 +233,68 @@ #define STM32_SIP_SVC_FUNC_SCMI_AGENT0 0x2000 #define STM32_SIP_SVC_FUNC_SCMI_AGENT1 0x2001 +/* + * OEM Functions + */ +#define STM32_OEM_SVC_VERSION_MAJOR 0x0 +#define STM32_OEM_SVC_VERSION_MINOR 0x1 + +#define STM32_OEM_SVC_FUNCTION_COUNT 1 + +/* Use the same UID as for SiP service */ +#define STM32_OEM_SVC_UID_0 STM32_SIP_SVC_UID_0 +#define STM32_OEM_SVC_UID_1 STM32_SIP_SVC_UID_1 +#define STM32_OEM_SVC_UID_2 STM32_SIP_SVC_UID_2 +#define STM32_OEM_SVC_UID_3 STM32_SIP_SVC_UID_3 + + +/* OEM service generic return codes */ +#define STM32_OEM_SVC_OK 0x0 +#define STM32_OEM_SVC_NOT_SUPPORTED 0xffffffffU +#define STM32_OEM_SVC_FAILED 0xfffffffeU +#define STM32_OEM_SVC_INVALID_PARAMS 0xfffffffdU + +/* + * OEM function STM32_OEM_FUNC_CALL_COUNT + * + * Argument a0: (input) SMCC ID + * (output) Count of defined function IDs + */ +#define STM32_OEM_SVC_FUNC_CALL_COUNT 0xff00 + +/* + * OEM function STM32_OEM_SVC_FUNC_UID + * + * Argument a0: (input) SMCC ID + * (output) Lowest 32bit of the stm32mp1 OEM service UUID + * Argument a1: (output) Next 32bit of the stm32mp1 OEM service UUID + * Argument a2: (output) Next 32bit of the stm32mp1 OEM service UUID + * Argument a3: (output) Last 32bit of the stm32mp1 OEM service UUID + */ +#define STM32_OEM_SVC_FUNC_UID 0xff01 + +/* + * OEM function STM32_OEM_FUNC_VERSION + * + * Argument a0: (input) SMCC ID + * (output) STM32 OEM service major + * Argument a1: (output) STM32 OEM service minor + */ +#define STM32_OEM_SVC_FUNC_VERSION 0xff03 + +/* + * OEM function STM32_OEM_SVC_FUNC_LP_FORCE_PARAMS + * + * Argument a0: (input) SMCC ID + * (output) status return code + * Argument a2: (input) ID of the mode: suspend or shutdown (off) + * Argument a3: (input) ID of the power state to be reached for the mode + * Refer to stm32mp1 power bindings. + */ +#define STM32_OEM_SVC_FUNC_LP_FORCE_PARAMS 0x0f800 + +/* Valid IDs for power mode in STM32_OEM_SVC_FUNC_LP_FORCE_PARAMS */ +#define STM32_OEM_SVC_LP_FORCE_SUSPEND_PARAMS 0 +#define STM32_OEM_SVC_LP_FORCE_OFF_PARAMS 1 + #endif /* __STM32MP1_SMC_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_svc_setup.c b/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_svc_setup.c index 49d23ff02..f5f131df6 100644 --- a/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_svc_setup.c +++ b/core/arch/arm/plat-stm32mp1/nsec-service/stm32mp1_svc_setup.c @@ -7,11 +7,32 @@ #include #include #include +#include #include "bsec_svc.h" +#include "low_power_svc.h" +#include "pwr_svc.h" +#include "rcc_svc.h" #include "stm32mp1_smc.h" -static enum sm_handler_ret sip_service(struct sm_ctx *ctx __unused, +#ifdef CFG_STM32_CLKCALIB_SIP +static uint32_t calib_scv_handler(uint32_t x1) +{ + unsigned long clock_id = x1; + + if (stm32mp_start_clock_calib(clock_id)) + return STM32_SIP_SVC_FAILED; + + return STM32_SIP_SVC_OK; +} +#else +static uint32_t calib_scv_handler(uint32_t __unused x1) +{ + return STM32_SIP_SVC_FAILED; +} +#endif + +static enum sm_handler_ret sip_service(struct sm_ctx *ctx, struct thread_smc_args *args) { switch (OPTEE_SMC_FUNC_NUM(args->a0)) { @@ -39,6 +60,60 @@ static enum sm_handler_ret sip_service(struct sm_ctx *ctx __unused, case STM32_SIP_SVC_FUNC_BSEC: bsec_main(args); break; + case STM32_SIP_SVC_FUNC_RCC: + args->a0 = rcc_scv_handler(args->a1, args->a2, args->a3); + break; + case STM32_SIP_SVC_FUNC_RCC_OPP: + args->a0 = rcc_opp_scv_handler(args->a1, args->a2, &args->a1); + break; + case STM32_SIP_SVC_FUNC_CAL: + args->a0 = calib_scv_handler(args->a1); + break; + case STM32_SIP_SVC_FUNC_PWR: + args->a0 = pwr_scv_handler(args->a1, args->a2, args->a3); + break; + case STM32_SIP_FUNC_SR_MODE: + args->a0 = sr_mode_scv_handler(args->a1, args->a2); + break; + case STM32_SIP_FUNC_CSTOP: + args->a0 = cstop_scv_handler(ctx, args->a1, args->a2, args->a3); + break; + case STM32_SIP_FUNC_STANDBY: + args->a0 = standby_scv_handler(ctx, args->a1, args->a2, args->a3); + break; + case STM32_SIP_FUNC_SHUTDOWN: + args->a0 = shutdown_scv_handler(); + break; + case STM32_SIP_FUNC_PD_DOMAIN: + args->a0 = pm_domain_scv_handler(args->a1, args->a2); + break; + default: + return SM_HANDLER_PENDING_SMC; + } + + return SM_HANDLER_SMC_HANDLED; +} + +static enum sm_handler_ret oem_service(struct sm_ctx *ctx __unused, + struct thread_smc_args *args) +{ + switch (OPTEE_SMC_FUNC_NUM(args->a0)) { + case STM32_OEM_SVC_FUNC_CALL_COUNT: + args->a0 = STM32_OEM_SVC_FUNCTION_COUNT; + break; + case STM32_OEM_SVC_FUNC_VERSION: + args->a0 = STM32_OEM_SVC_VERSION_MAJOR; + args->a1 = STM32_OEM_SVC_VERSION_MINOR; + break; + case STM32_OEM_SVC_FUNC_UID: + args->a0 = STM32_OEM_SVC_UID_0; + args->a1 = STM32_OEM_SVC_UID_1; + args->a2 = STM32_OEM_SVC_UID_2; + args->a3 = STM32_OEM_SVC_UID_3; + break; + case STM32_OEM_SVC_FUNC_LP_FORCE_PARAMS: + args->a0 = pm_set_lp_state_scv_handler(args->a1, args->a2); + break; default: return SM_HANDLER_PENDING_SMC; } @@ -56,6 +131,8 @@ enum sm_handler_ret sm_platform_handler(struct sm_ctx *ctx) switch (OPTEE_SMC_OWNER_NUM(args->a0)) { case OPTEE_SMC_OWNER_SIP: return sip_service(ctx, args); + case OPTEE_SMC_OWNER_OEM: + return oem_service(ctx, args); default: return SM_HANDLER_PENDING_SMC; } diff --git a/core/arch/arm/plat-stm32mp1/nsec-service/sub.mk b/core/arch/arm/plat-stm32mp1/nsec-service/sub.mk index 6e1abcb4a..acccda16a 100644 --- a/core/arch/arm/plat-stm32mp1/nsec-service/sub.mk +++ b/core/arch/arm/plat-stm32mp1/nsec-service/sub.mk @@ -2,3 +2,6 @@ global-incdirs-y += . srcs-y += stm32mp1_svc_setup.c srcs-$(CFG_STM32_BSEC_SIP) += bsec_svc.c +srcs-$(CFG_STM32_LOWPOWER_SIP) += low_power_svc.c +srcs-$(CFG_STM32_PWR_SIP) += pwr_svc.c +srcs-$(CFG_STM32_RCC_SIP) += rcc_svc.c diff --git a/core/arch/arm/plat-stm32mp1/plat_tzc400.c b/core/arch/arm/plat-stm32mp1/plat_tzc400.c index bce923711..23c7170e5 100644 --- a/core/arch/arm/plat-stm32mp1/plat_tzc400.c +++ b/core/arch/arm/plat-stm32mp1/plat_tzc400.c @@ -33,39 +33,45 @@ static struct itr_handler tzc_itr_handler = { }; DECLARE_KEEP_PAGER(tzc_itr_handler); -static bool tzc_region_is_non_secure(unsigned int i, vaddr_t base, size_t size) +static bool tzc_find_region(vaddr_t base, size_t size, struct tzc_region_config *region_cfg) +{ + uint8_t i = 1; + + while (true) { + if (tzc_get_region_config(i++, region_cfg) != TEE_SUCCESS) + return false; + + if (region_cfg->base <= base && region_cfg->top >= (base + size - 1)) + return true; + } +} + +static bool tzc_region_is_non_secure(vaddr_t base, size_t size) { struct tzc_region_config region_cfg = { }; uint32_t ns_cpu_mask = TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID); uint32_t filters_mask = GENMASK_32(1, 0); - if (tzc_get_region_config(i, ®ion_cfg)) - panic(); - - return region_cfg.base == base && region_cfg.top == (base + size - 1) && - region_cfg.sec_attr == TZC_REGION_S_NONE && - (region_cfg.ns_device_access & ns_cpu_mask) == ns_cpu_mask && - region_cfg.filters == filters_mask; + return tzc_find_region(base, size, ®ion_cfg) && + region_cfg.sec_attr == TZC_REGION_S_NONE && + (region_cfg.ns_device_access & ns_cpu_mask) == ns_cpu_mask && + region_cfg.filters == filters_mask; } -static bool tzc_region_is_secure(unsigned int i, vaddr_t base, size_t size) +static bool tzc_region_is_secure(vaddr_t base, size_t size) { struct tzc_region_config region_cfg = { }; uint32_t filters_mask = GENMASK_32(1, 0); - if (tzc_get_region_config(i, ®ion_cfg)) - panic(); - - return region_cfg.base == base && region_cfg.top == (base + size - 1) && - region_cfg.sec_attr == TZC_REGION_S_RDWR && - region_cfg.ns_device_access == 0 && - region_cfg.filters == filters_mask; + return tzc_find_region(base, size, ®ion_cfg) && + region_cfg.sec_attr == TZC_REGION_S_RDWR && + region_cfg.ns_device_access == 0 && + region_cfg.filters == filters_mask; } static TEE_Result init_stm32mp1_tzc(void) { void *base = phys_to_virt(TZC_BASE, MEM_AREA_IO_SEC); - unsigned int region_index = 1; const uint64_t dram_start = DDR_BASE; const uint64_t dram_end = dram_start + CFG_DRAM_SIZE; const uint64_t tzdram_start = CFG_TZDRAM_START; @@ -83,21 +89,15 @@ static TEE_Result init_stm32mp1_tzc(void) * expectations. */ if (dram_start < tzdram_start) { - if (!tzc_region_is_non_secure(region_index, dram_start, - tzdram_start - dram_start)) + if (!tzc_region_is_non_secure(dram_start, tzdram_start - dram_start)) panic("Unexpected TZC area on non-secure region"); - - region_index++; } - if (!tzc_region_is_secure(region_index, tzdram_start, tzdram_size)) + if (!tzc_region_is_secure(tzdram_start, tzdram_size)) panic("Unexpected TZC configuration on secure region"); if (tzdram_end < dram_end) { - region_index++; - - if (!tzc_region_is_non_secure(region_index, tzdram_end, - dram_end - tzdram_end)) + if (!tzc_region_is_non_secure(tzdram_end, dram_end - tzdram_end)) panic("Unexpected TZC area on non-secure region"); } diff --git a/core/arch/arm/plat-stm32mp1/platform_config.h b/core/arch/arm/plat-stm32mp1/platform_config.h index cf68f4510..0ea5efc32 100644 --- a/core/arch/arm/plat-stm32mp1/platform_config.h +++ b/core/arch/arm/plat-stm32mp1/platform_config.h @@ -8,14 +8,47 @@ #include +/* Enable/disable use of the core0 reset control from RCC */ +#undef STM32MP1_USE_MPU0_RESET + /* Make stacks aligned to data cache line length */ #define STACK_ALIGNMENT 32 +#if defined(CFG_WITH_PAGER) +#if defined(CFG_WITH_LPAE) +/* + * Optimize unpaged memory size: + * - one table for the level2 table for overall vmem range + * - two tables for TEE RAM fine grain mapping [2ffc.0000 301f.ffff] + * - one table for a 2MByte dynamic shared virtual memory (SHM_VASPACE) + */ +#define MAX_XLAT_TABLES 4 +#else +/* + * Optimize unpaged memory size: + * - two tables for TEE RAM mapping [2ffc.0000 300f.ffff] + * - one table for secure internal RAMs (PM: ROMed core TEE RAM) + * - one table for non-secure internal RAMs (PM: DDR first page) + * - two tables for a 2MByte dynamiq shared virtual memory (SHM_VASPACE) + */ +#define MAX_XLAT_TABLES 6 +#endif /*CFG_WITH_LPAE*/ +#else +/* Be generous with this setup that has plenty of secure RAM */ +#define MAX_XLAT_TABLES 10 +#endif /*CFG_WITH_PAGER*/ + /* SoC interface registers base address */ +#define MCUSRAM_BASE 0x30000000ul +#define RETRAM_BASE 0x38000000ul +#define BKPSRAM_BASE 0x54000000 #define BSEC_BASE 0x5c005000 #define ETZPC_BASE 0x5c007000 #define CRYP1_BASE 0x54001000 +#define DBGMCU_BASE 0x50081000 #define DDR_BASE 0xc0000000ul +#define DDRCTRL_BASE 0x5a003000 +#define DDRPHYC_BASE 0x5a004000 #define GIC_BASE 0xa0021000ul #define GPIOA_BASE 0x50002000 #define GPIOB_BASE 0x50003000 @@ -39,9 +72,24 @@ #define RNG1_BASE 0x54003000 #define RTC_BASE 0x5c004000 #define SPI6_BASE 0x5c001000 +#define STGEN_BASE 0x5c008000 #define SYSCFG_BASE 0x50020000 #define SYSRAM_BASE 0x2ffc0000 #define TAMP_BASE 0x5c00a000 +#define TIM1_BASE 0x44000000 +#define TIM2_BASE 0x40000000 +#define TIM3_BASE 0x40001000 +#define TIM4_BASE 0x40002000 +#define TIM5_BASE 0x40003000 +#define TIM6_BASE 0x40004000 +#define TIM7_BASE 0x40005000 +#define TIM8_BASE 0x44001000 +#define TIM12_BASE 0x40006000 +#define TIM13_BASE 0x40007000 +#define TIM14_BASE 0x40008000 +#define TIM15_BASE 0x44006000 +#define TIM16_BASE 0x44007000 +#define TIM17_BASE 0x44008000 #define TZC_BASE 0x5c006000 #define UART1_BASE 0x5c000000 #define UART2_BASE 0x4000e000 @@ -52,6 +100,9 @@ #define UART7_BASE 0x40018000 #define UART8_BASE 0x40019000 +/* DDR expected size if not found in device tree */ +#define STM32MP1_DDR_SIZE_DFLT (1 * 1024 * 1024 * 1024) + /* Console configuration */ #define STM32MP1_DEBUG_USART_BASE UART4_BASE #define GIC_SPI_UART4 84 @@ -65,16 +116,21 @@ #define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U) -#define DATA0_OTP 0 -#define PART_NUMBER_OTP 1 -#define MONOTONIC_OTP 4 -#define NAND_OTP 9 -#define UID0_OTP 13 -#define UID1_OTP 14 -#define UID2_OTP 15 -#define HW2_OTP 18 +#define CFG0_OTP "cfg0_otp" +#define CFG0_OTP_SECURED_POS 6 + +#define HW2_OTP "hw2_otp" +#define HW2_OTP_IWDG_HW_ENABLE_SHIFT 3 +#define HW2_OTP_IWDG_FZ_STOP_SHIFT 5 +#define HW2_OTP_IWDG_FZ_STANDBY_SHIFT 7 -#define DATA0_OTP_SECURED_POS 6 +#define PART_NUMBER_OTP "part_number_otp" +#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0) +#define PART_NUMBER_OTP_PART_SHIFT 0 + +#define HW2_OTP_IWDG_HW_ENABLE_SHIFT 3 +#define HW2_OTP_IWDG_FZ_STOP_SHIFT 5 +#define HW2_OTP_IWDG_FZ_STANDBY_SHIFT 7 /* GIC resources */ #define GIC_SIZE 0x2000 @@ -84,11 +140,14 @@ #define GIC_NON_SEC_SGI_0 0 #define GIC_SEC_SGI_0 8 #define GIC_SEC_SGI_1 9 +#define GIC_SPI_SEC_PHY_TIMER 29 #define TARGET_CPU0_GIC_MASK BIT(0) #define TARGET_CPU1_GIC_MASK BIT(1) #define TARGET_CPUS_GIC_MASK GENMASK_32(CFG_TEE_CORE_NB_CORE - 1, 0) +#define STM32MP_GIC_PRIORITY_CSTOP 0xc0 + /* * GPIO banks: 11 non secure banks (A to K) and 1 secure bank (Z) * Bank register's base address is computed from the bank ID listed here. @@ -116,6 +175,16 @@ #define GPIO_BANK_K 10U #define GPIO_BANK_Z 25U +/* IWDG resources */ +#define IWDG1_INST 0 +#define IWDG2_INST 1 + +#define STM32MP1_IRQ_IWDG1 182U +#define STM32MP1_IRQ_IWDG2 183U + +/* RCC platform resources */ +#define RCC_WAKEUP_IT 177 + /* TAMP resources */ #define TAMP_BKP_REGISTER_OFF 0x100 @@ -140,6 +209,24 @@ #define USART3_BASE UART3_BASE #define USART6_BASE UART6_BASE +/* DBGMCU resources */ +#define DBGMCU_IDC 0x0 +#define DBGMCU_IDC_DEV_ID_MASK GENMASK_32(11, 0) +#define DBGMCU_IDC_REV_ID_MASK GENMASK_32(31, 16) +#define DBGMCU_IDC_REV_ID_SHIFT 16 + +/* BKPSRAM layout */ +#define BKPSRAM_SIZE 0x1000 +#define BKPSRAM_PM_OFFSET 0x000 +#define BKPSRAM_PM_SIZE (BKPSRAM_PM_MAILBOX_SIZE + \ + BKPSRAM_PM_CONTEXT_SIZE) + +#define BKPSRAM_PM_MAILBOX_OFFSET BKPSRAM_PM_OFFSET +#define BKPSRAM_PM_MAILBOX_SIZE 0x100 +#define BKPSRAM_PM_CONTEXT_OFFSET (BKPSRAM_PM_MAILBOX_OFFSET + \ + BKPSRAM_PM_MAILBOX_SIZE) +#define BKPSRAM_PM_CONTEXT_SIZE 0xF00 + /* SYSRAM layout */ #define SYSRAM_SIZE 0x40000 #define SYSRAM_NS_SIZE (SYSRAM_SIZE - SYSRAM_SEC_SIZE) @@ -153,4 +240,38 @@ #define SYSRAM_SEC_SIZE SYSRAM_SIZE #endif +/* RETRAM layout */ +#define RETRAM_SIZE 0x10000 + +/* MCUSRAM layout */ +#define MCUSRAM_SIZE 0x60000 + +/* SoC part numbers and revisions */ +#define STM32MP1_CHIP_ID 0x500 + +#define STM32MP157C_PART_NB 0x05000000 +#define STM32MP157A_PART_NB 0x05000001 +#define STM32MP153C_PART_NB 0x05000024 +#define STM32MP153A_PART_NB 0x05000025 +#define STM32MP151C_PART_NB 0x0500002E +#define STM32MP151A_PART_NB 0x0500002F +#define STM32MP157F_PART_NB 0x05000080 +#define STM32MP157D_PART_NB 0x05000081 +#define STM32MP153F_PART_NB 0x050000A4 +#define STM32MP153D_PART_NB 0x050000A5 +#define STM32MP151F_PART_NB 0x050000AE +#define STM32MP151D_PART_NB 0x050000AF + +#define STM32MP1_CHIP_DEFAULT_VERSION 0 + +#define STM32MP1_REV_A 0x00001000 +#define STM32MP1_REV_B 0x00002000 +#define STM32MP1_REV_Z 0x00002001 + +/* OPP */ +#define PLAT_OPP_ID1 1U +#define PLAT_OPP_ID2 2U +#define PLAT_MAX_OPP_NB 2U +#define PLAT_MAX_PLLCFG_NB 6U + #endif /*PLATFORM_CONFIG_H*/ diff --git a/core/arch/arm/plat-stm32mp1/pm/context.c b/core/arch/arm/plat-stm32mp1/pm/context.c new file mode 100644 index 000000000..8dddb0c02 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/context.c @@ -0,0 +1,522 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "context.h" +#include "power.h" + +#define TRAINING_AREA_SIZE 64 + +/* + * STANDBY_CONTEXT_MAGIC0: + * Context provides magic, resume entry, zq0cr0 zdata and DDR training buffer. + * + * STANDBY_CONTEXT_MAGIC1: + * Context provides magic, resume entry, zq0cr0 zdata, DDR training buffer + * and PLL1 dual OPP settings structure (86 bytes). + */ +#define STANDBY_CONTEXT_MAGIC0 (0x0001 << 16) +#define STANDBY_CONTEXT_MAGIC1 (0x0002 << 16) + +#if CFG_STM32MP15_PM_CONTEX_VERSION == 1 +#define STANDBY_CONTEXT_MAGIC (STANDBY_CONTEXT_MAGIC0 | TRAINING_AREA_SIZE) +#elif CFG_STM32MP15_PM_CONTEX_VERSION == 2 +#define STANDBY_CONTEXT_MAGIC (STANDBY_CONTEXT_MAGIC1 | TRAINING_AREA_SIZE) +#else +#error Invalid value for CFG_STM32MP15_PM_CONTEX_VERSION +#endif + +#if (PLAT_MAX_OPP_NB != 2) || (PLAT_MAX_PLLCFG_NB != 6) +#error STANDBY_CONTEXT_MAGIC1 does not support expected PLL1 settings +#endif + +/* pll_settings structure size definitions (reference to clock driver) */ +#define PLL1_SETTINGS_SIZE (((PLAT_MAX_OPP_NB * \ + (PLAT_MAX_PLLCFG_NB + 3)) + 1) * \ + sizeof(uint32_t)) + +/* + * Context saved in TEE RAM during lower power sequence. + * Can be allocated if to big for static allocation. + * + * @stgen_cnt_h: Upper 32bit of the STGEN counter + * @stgen_cnt_l: Lower 32bit of the STGEN counter + * @rtc: RTC time read at suspend + */ +struct pm_context { + uint32_t stgen_cnt_h; + uint32_t stgen_cnt_l; + struct stm32_rtc_calendar rtc; +}; + +static struct pm_context plat_ctx; + +/* + * BKPSRAM contains a mailbox used with early boot stages for resume sequence. + * The mailbox content data that must be restored before OP-TEE is resumed. + * + * @magic: magic value read by early boot stage for consistency + * @zq0cr0_zdata: DDRPHY configuration to be restored. + * @ddr_training_backup: DDR area saved at suspend and backed up at resume + */ +struct pm_mailbox { + uint32_t magic; + uint32_t core0_resume_ep; + uint32_t zq0cr0_zdata; + uint8_t ddr_training_backup[TRAINING_AREA_SIZE]; +#if CFG_STM32MP15_PM_CONTEX_VERSION >= 2 + uint8_t pll1_settings[PLL1_SETTINGS_SIZE]; +#endif +}; + +/* + * BKPSRAM contains OP-TEE resume instruction sequence which restores + * TEE RAM content. The BKPSRAM contains restoration materials + * (key, tag) and the resume entry point in restored TEE RAM. + */ +static struct retram_resume_ctx *get_retram_resume_ctx(void) +{ + vaddr_t bkpsram_base = stm32mp_bkpsram_base(); + vaddr_t context_base = bkpsram_base + BKPSRAM_PM_CONTEXT_OFFSET; + + return (struct retram_resume_ctx *)context_base; +} + +static struct pm_mailbox *get_pm_mailbox(void) +{ + vaddr_t bkpsram_base = stm32mp_bkpsram_base(); + vaddr_t mailbox_base = bkpsram_base + BKPSRAM_PM_MAILBOX_OFFSET; + + return (struct pm_mailbox *)mailbox_base; +} + +#if TRACE_LEVEL >= TRACE_DEBUG +static void __maybe_unused dump_context(void) +{ + struct pm_mailbox *mailbox = get_pm_mailbox(); + struct retram_resume_ctx *ctx = get_retram_resume_ctx(); + + clk_enable(RTCAPB); + + DMSG("Backup registers: address 0x%" PRIx32 ", magic 0x%" PRIx32, + *(uint32_t *)stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS), + *(uint32_t *)stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER)); + + clk_disable(RTCAPB); + + clk_enable(BKPSRAM); + + DMSG("BKPSRAM mailbox: 0x%" PRIx32 ", zd 0x%" PRIx32 ", ep 0x%" PRIx32, + mailbox->magic, mailbox->zq0cr0_zdata, + mailbox->core0_resume_ep); + + DMSG("BKPSRAM context: teeram backup @%" PRIx32 ", resume @0x%" PRIx32, + ctx->teeram_bkp_pa, ctx->resume_pa); + + clk_disable(BKPSRAM); +} +#else +static void __maybe_unused dump_context(void) +{ +} +#endif + +/* + * Save and restore functions + */ +static void save_time(void) +{ + vaddr_t stgen = stm32mp_stgen_base(); + + plat_ctx.stgen_cnt_h = io_read32(stgen + CNTCVU_OFFSET); + plat_ctx.stgen_cnt_l = io_read32(stgen + CNTCVL_OFFSET); + if (plat_ctx.stgen_cnt_l < 10) + plat_ctx.stgen_cnt_h = io_read32(stgen + CNTCVU_OFFSET); + + clk_enable(RTC); + stm32_rtc_get_calendar(&plat_ctx.rtc); +} + +#if TRACE_LEVEL >= TRACE_DEBUG +static void print_ccm_decryption_duration(void) +{ + vaddr_t stgen = stm32mp_stgen_base(); + struct retram_resume_ctx *ctx = get_retram_resume_ctx(); + + clk_enable(BKPSRAM); + + DMSG("CCM decryption duration %llums", + ((unsigned long long)ctx->stgen_cnt * 1000) / + io_read32(stgen + CNTFID_OFFSET)); + + clk_enable(BKPSRAM); +} +#else +static void print_ccm_decryption_duration(void) +{ +} +#endif + +static void restore_time(void) +{ + struct stm32_rtc_calendar current_calendar = { }; + unsigned long long stdby_time_in_ms = 0; + unsigned long long cnt = 0; + vaddr_t stgen = stm32mp_stgen_base(); + struct retram_resume_ctx __maybe_unused *ctx = get_retram_resume_ctx(); + + stm32_rtc_get_calendar(¤t_calendar); + stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar, + &plat_ctx.rtc); + + cnt = ((uint64_t)plat_ctx.stgen_cnt_h << 32) | plat_ctx.stgen_cnt_l; + cnt += (stdby_time_in_ms * io_read32(stgen + CNTFID_OFFSET)) / 1000U; + + io_clrbits32(stgen + CNTCR_OFFSET, CNTCR_EN); + io_write32(stgen + CNTCVL_OFFSET, (uint32_t)cnt); + io_write32(stgen + CNTCVU_OFFSET, (uint32_t)(cnt >> 32)); + io_setbits32(stgen + CNTCR_OFFSET, CNTCR_EN); + + /* Balance clock enable(RTC) at save_time() */ + clk_disable(RTC); + + print_ccm_decryption_duration(); +} + +static bool __maybe_unused pm_cb_is_valid(void (*cb)(enum pm_op op, void *hdl), + void *hdl) +{ + void *cb_voidp = (void *)(vaddr_t)cb; + paddr_t cb_phy = virt_to_phys(cb_voidp); + paddr_t hdl_phy = virt_to_phys(hdl); + bool valid = false; + + valid = (phys_to_virt(cb_phy, MEM_AREA_TEE_RAM_RX) == cb_voidp) && + ((phys_to_virt(hdl_phy, MEM_AREA_TEE_RAM_RX) == hdl) || + (phys_to_virt(hdl_phy, MEM_AREA_TEE_RAM_RO) == hdl) || + (phys_to_virt(hdl_phy, MEM_AREA_TEE_RAM_RW) == hdl)); + + if (!valid) + EMSG("pm_cb mandates unpaged arguments %p %p", cb_voidp, hdl); + + return valid; +} + +uintptr_t stm32mp_pm_retram_resume_ep(void) +{ + struct retram_resume_ctx *ctx = get_retram_resume_ctx(); + + return (uintptr_t)&ctx->resume_sequence; +} + +/* Clear the content of the PM mailbox */ +void stm32mp_pm_wipe_context(void) +{ + struct retram_resume_ctx *ctx = get_retram_resume_ctx(); + struct pm_mailbox *mailbox = get_pm_mailbox(); + + clk_enable(BKPSRAM); + + memset(ctx, 0xa5, sizeof(*ctx)); + memset(mailbox, 0xa5, sizeof(*mailbox)); + + clk_disable(BKPSRAM); +} + +static struct mobj *teeram_bkp_mobj; + +static void init_retram_resume_resources(void) +{ + struct retram_resume_ctx *ctx = get_retram_resume_ctx(); + size_t __maybe_unused csize = 0; + paddr_t __maybe_unused pa = 0; + + COMPILE_TIME_ASSERT(sizeof(struct pm_mailbox) < + BKPSRAM_PM_MAILBOX_SIZE); + COMPILE_TIME_ASSERT(sizeof(struct retram_resume_ctx) < + BKPSRAM_PM_CONTEXT_SIZE); + csize = (vaddr_t)stm32mp_bkpsram_image_end - + (vaddr_t)stm32mp_bkpsram_resume; + assert((sizeof(*ctx) + csize) < BKPSRAM_PM_CONTEXT_SIZE); + + teeram_bkp_mobj = mobj_mm_alloc(mobj_sec_ddr, TEE_RAM_PH_SIZE, + &tee_mm_sec_ddr); + if (!teeram_bkp_mobj) + panic(); + + assert((mobj_get_va(teeram_bkp_mobj, 0) != NULL) && + (mobj_get_pa(teeram_bkp_mobj, 0, 0, &pa) == 0)); + + clk_enable(BKPSRAM); + memset(ctx, 0, sizeof(*ctx)); + clk_disable(BKPSRAM); +} + +/* + * When returning from STANDBY, the 64 first bytes of DDR will be overwritten + * during DDR DQS training. This area must then be saved before going to + * standby in the PM mailbox with the earlier boot stages. + */ +static void save_ddr_training_area(void) +{ + struct pm_mailbox *mailbox = get_pm_mailbox(); + size_t size = sizeof(mailbox->ddr_training_backup); + paddr_t pa = DDR_BASE; + void *va = phys_to_virt(pa, MEM_AREA_RAM_NSEC); + + memcpy(&mailbox->ddr_training_backup[0], va, size); + +} + +/* + * When returning from STANDBY, warm boot boot stage needs to access to PLL1 + * settings. This avoids to re-compute them and optimizes performances. This + * structure must then be saved before going to STANDBY in the PM mailbox + * shared with the warm boot boot stage. + */ +#if CFG_STM32MP15_PM_CONTEX_VERSION >= 2 +static void save_pll1_settings(void) +{ + struct pm_mailbox *mailbox = get_pm_mailbox(); + size_t size = sizeof(mailbox->pll1_settings); + uint8_t *data = &mailbox->pll1_settings[0]; + + stm32mp1_clk_lp_save_opp_pll1_settings(data, size); +} +#endif + +static void load_earlyboot_pm_mailbox(void) +{ + struct pm_mailbox *mailbox = get_pm_mailbox(); + + COMPILE_TIME_ASSERT(sizeof(struct pm_mailbox) < + BKPSRAM_PM_MAILBOX_SIZE); + + assert(clk_is_enabled(BKPSRAM)); + + memset(mailbox, 0, sizeof(*mailbox)); + + mailbox->zq0cr0_zdata = get_ddrphy_calibration(); + + save_ddr_training_area(); + +#if CFG_STM32MP15_PM_CONTEX_VERSION >= 2 + save_pll1_settings(); +#endif +} + +#if defined(CFG_STM32_RNG) && defined(CFG_STM32_CRYP) +/* + * CRYP relies on standard format for CCM IV/B0/CRT0 data. Our sequence uses + * no AAD, 4 bytes to encode the payload byte size and a 11 byte nonce. + */ +#define PM_CCM_Q 4 +#define PM_CCM_Q_FLAGS (PM_CCM_Q - 1) +#define PM_CCM_TAG_LEN 16 +#define PM_CCM_TAG_FLAGS (((PM_CCM_TAG_LEN - 2) / 2) << 3) + +static void save_teeram_in_ddr(void) +{ + struct retram_resume_ctx *ctx = get_retram_resume_ctx(); + size_t __maybe_unused size = (vaddr_t)stm32mp_bkpsram_image_end - + (vaddr_t)stm32mp_bkpsram_resume; + paddr_t pa = 0; + struct ccm_unpg_ctx *ccm = &ctx->ccm_ctx; + void *teeram = phys_to_virt(TEE_RAM_START, MEM_AREA_ROM_SEC); + void *teeram_bkp = mobj_get_va(teeram_bkp_mobj, 0); + + COMPILE_TIME_ASSERT(PM_CTX_CCM_KEY_SIZE == sizeof(ccm->key)); + COMPILE_TIME_ASSERT(PM_CTX_CCM_CTR1_SIZE == sizeof(ccm->ctr1)); + COMPILE_TIME_ASSERT(PM_CTX_CCM_B0_SIZE == sizeof(ccm->b0)); + COMPILE_TIME_ASSERT(PM_CTX_CCM_CTR0_SIZE == sizeof(ccm->ctr0)); + COMPILE_TIME_ASSERT(PM_CTX_CCM_TAG_SIZE == sizeof(ccm->tag)); + + assert(clk_is_enabled(BKPSRAM) && + clk_is_enabled(CRYP1)); + + memcpy(ctx->resume_sequence, + (void *)(vaddr_t)stm32mp_bkpsram_resume, size); + + memset(ctx, 0, sizeof(*ctx)); + ctx->resume_pa = virt_to_phys((void *)(vaddr_t)stm32mp_sysram_resume); + if (mobj_get_pa(teeram_bkp_mobj, 0, 0, &pa)) + panic(); + + ctx->teeram_bkp_pa = (uint32_t)pa; + ctx->cryp1_base = (uint32_t)phys_to_virt(CRYP1_BASE, MEM_AREA_IO_SEC); + ctx->rcc_base = (uint32_t)phys_to_virt(RCC_BASE, MEM_AREA_IO_SEC); + ctx->stgen_base = (uint32_t)phys_to_virt(STGEN_BASE, MEM_AREA_IO_SEC); + + if (stm32_rng_read((uint8_t *)ccm->key, sizeof(ccm->key))) + panic(); + + assert(((PM_CCM_TAG_FLAGS & ~0x38U) | (PM_CCM_Q_FLAGS & ~0x07U)) == 0); + COMPILE_TIME_ASSERT(PM_CCM_Q <= 4); + COMPILE_TIME_ASSERT(TEE_RAM_PH_SIZE > UINT16_MAX); + COMPILE_TIME_ASSERT(TEE_RAM_PH_SIZE < UINT32_MAX); + + if (stm32_rng_read((uint8_t *)ccm->ctr1, sizeof(ccm->ctr1))) + panic(); + + ccm->ctr1[0] &= GENMASK_32(24, 0); + memcpy(ccm->b0, ccm->ctr1, sizeof(ccm->b0)); + memcpy(ccm->ctr0, ccm->ctr1, sizeof(ccm->ctr0)); + + ccm->ctr0[0] |= PM_CCM_Q_FLAGS << 24; + ccm->ctr0[3] = 0; + ccm->ctr1[0] |= PM_CCM_Q_FLAGS << 24; + ccm->ctr1[3] = 1; + ccm->b0[0] |= (PM_CCM_Q_FLAGS | PM_CCM_TAG_FLAGS) << 24; + ccm->b0[3] = TEE_RAM_PH_SIZE; + + stm32mp_ccm_encrypt_teeram(ctx, teeram_bkp, teeram, TEE_RAM_PH_SIZE); + dcache_clean_range(teeram_bkp, TEE_RAM_PH_SIZE); + + memcpy(ctx->ccm_ref_tag, ccm->tag, sizeof(ctx->ccm_ref_tag)); + + DMSG("CCM encryption duration %llums", + ((unsigned long long)ctx->stgen_cnt * 1000) / + io_read32(ctx->stgen_base + CNTFID_OFFSET)); + ctx->stgen_cnt = 0; +} +#else +static void save_teeram_in_ddr(void) +{ + panic("Mandates RNG and CRYP support"); +} +#endif /*CFG_STM32_RNG*/ + +/* Finalize the PM mailbox now that everything is loaded */ +static void enable_pm_mailbox(unsigned int suspend) +{ + struct pm_mailbox *mailbox = get_pm_mailbox(); + uint32_t magic = 0; + uint32_t hint = 0; + + assert(clk_is_enabled(BKPSRAM) && + clk_is_enabled(RTCAPB)); + + if (suspend) { + magic = BOOT_API_A7_CORE0_MAGIC_NUMBER; + mailbox->magic = STANDBY_CONTEXT_MAGIC; + + hint = virt_to_phys(&get_retram_resume_ctx()->resume_sequence); + } else { + mailbox->magic = 0; + } + + io_write32(stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER), magic); + io_write32(stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS), hint); + + mailbox->core0_resume_ep = hint; +} + +static void gate_pm_context_clocks(bool enable) +{ + static bool clocks_enabled; + + if (enable) { + assert(!clocks_enabled); + clk_enable(BKPSRAM); + clk_enable(RTCAPB); + clk_enable(CRYP1); + clocks_enabled = true; + return; + } + + /* Suspended TEE RAM state left the clocks enabled */ + if (clocks_enabled) { + clk_disable(BKPSRAM); + clk_disable(RTCAPB); + clk_disable(CRYP1); + clocks_enabled = false; + } +} + +/* + * Context (TEE RAM content + peripherals) must be restored + * only if system may reach STANDBY state. + */ +TEE_Result stm32mp_pm_save_context(unsigned int soc_mode) +{ + TEE_Result res = TEE_ERROR_GENERIC; + + save_time(); + + if (!need_to_backup_cpu_context(soc_mode)) { + if (need_to_backup_stop_context(soc_mode)) + stm32mp1_clk_save_context_for_stop(); + + return TEE_SUCCESS; + } + + gate_pm_context_clocks(true); + load_earlyboot_pm_mailbox(); + res = pm_change_state(PM_OP_SUSPEND, 0); + if (res) + return res; + + save_teeram_in_ddr(); + enable_pm_mailbox(1); + + return TEE_SUCCESS; +} + +void stm32mp_pm_restore_context(unsigned int soc_mode) +{ + if (need_to_backup_cpu_context(soc_mode)) { + if (pm_change_state(PM_OP_RESUME, 0)) + panic(); + + gate_pm_context_clocks(false); + } else if (need_to_backup_stop_context(soc_mode)) { + stm32mp1_clk_restore_context_for_stop(); + } + + restore_time(); +} + +void stm32mp_pm_shutdown_context(void) +{ + gate_pm_context_clocks(true); + load_earlyboot_pm_mailbox(); + enable_pm_mailbox(0); + gate_pm_context_clocks(false); +} + +static TEE_Result init_pm_support(void) +{ + init_retram_resume_resources(); + + stm32mp_pm_wipe_context(); + + return TEE_SUCCESS; +} +driver_init(init_pm_support); diff --git a/core/arch/arm/plat-stm32mp1/pm/context.h b/core/arch/arm/plat-stm32mp1/pm/context.h new file mode 100644 index 000000000..a806d685b --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/context.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + */ + +#ifndef __STM32MP_PM_CONTEXT_H__ +#define __STM32MP_PM_CONTEXT_H__ + +#ifndef __ASSEMBLER__ +#include +#include +#include +#include +#include +#include +#endif + +#define PM_CTX_CCM_KEY_SIZE 32 +#define PM_CTX_CCM_CTR1_SIZE 16 +#define PM_CTX_CCM_B0_SIZE 16 +#define PM_CTX_CCM_CTR0_SIZE 16 +#define PM_CTX_CCM_TAG_SIZE 16 + +#ifndef __ASSEMBLER__ +/* + * All materials for the CCM sequence using CRYP support are preloaded + * in this specific structure. Note that the sequence does not use AAD. + * + * @key: AES key material buffer + * @ctr1: Preformatted 128bit CTR1 block + * @ctr1: Preformatted 128bit B0 block + * @ctr1: Preformatted 128bit CTR0 block + * @tag: Buffer where the generated CCM tag is stored + */ +struct ccm_unpg_ctx { + uint32_t key[PM_CTX_CCM_KEY_SIZE / sizeof(uint32_t)]; + uint32_t ctr1[PM_CTX_CCM_CTR1_SIZE / sizeof(uint32_t)]; + uint32_t b0[PM_CTX_CCM_B0_SIZE / sizeof(uint32_t)]; + uint32_t ctr0[PM_CTX_CCM_CTR0_SIZE / sizeof(uint32_t)]; + uint32_t tag[PM_CTX_CCM_TAG_SIZE / sizeof(uint32_t)]; +}; + +/* + * This structure is used by pm_helpers.S at early resume from retention RAM. + * It is defined here and used by context_asm_defines.c to generate offset + * macros for the assembly implementation in pm_helpers.S. + * + * To lower the memory footprint of suspend sequence, The same function is + * used for encryption (executed from TEE RAM with MMU enabled) and for + * decryption (executed from BKPSRAM with MMU disabled). Therefore some + * required addresses are provided by the caller through this structure + * especially some SoC interface registers that are likely to have different + * physical and virtual addresses. + * + * @resume_pa: OP-TEE resume physical entry in TEE RAM (once restored) + * @teeram_bkp_pa: Physical base address in TEE RAM backup in DDR + * @cryp1_base: Base address of the CRYP1 registers (physical or virtual) + * @rcc_base: Base address of the RCC registers (physical or virtual) + * @stgen_base: Base address of the STGEN registers (physical or virtual) + * @stgen_cnt: STGEN cycle counter backup cell and measure of cycles spent + * @ccm_ref_tag: 128bit arrays storing tag generated during encryption + * @ccm_ctx: Structure storing CCM configuration and generated tag + * @resume_sequence: Code/data array for the BKPSRAM resume sequence + */ +struct retram_resume_ctx { + uint32_t resume_pa; + uint32_t teeram_bkp_pa; + uint32_t cryp1_base; + uint32_t rcc_base; + uint32_t stgen_base; + uint32_t stgen_cnt; + uint8_t ccm_ref_tag[PM_CTX_CCM_TAG_SIZE]; + struct ccm_unpg_ctx ccm_ctx; + /* Last start the resume routine ARM (32bit) instructions sequence */ + uint32_t resume_sequence[]; +}; + +extern const uint8_t stm32mp_bkpsram_image_end[]; +void stm32mp_bkpsram_resume(void); +void stm32mp_sysram_resume(void); + +void stm32mp_cpu_reset_state(void); + +TEE_Result stm32mp_pm_save_context(unsigned int soc_mode); +void stm32mp_pm_restore_context(unsigned int soc_mode); +void stm32mp_pm_shutdown_context(void); +void stm32mp_pm_wipe_context(void); + +int stm32mp1_set_pm_domain_state(enum stm32mp1_pm_domain domain, bool status); + +uint32_t stm32mp1_get_lp_soc_mode(uint32_t psci_mode); +int stm32mp1_set_lp_deepest_soc_mode(uint32_t psci_mode, uint32_t soc_mode); + +uintptr_t stm32mp_pm_retram_resume_ep(void); + +int stm32mp_ccm_encrypt_teeram(struct retram_resume_ctx *ctx, + void *dst, void *src, size_t size); +int stm32mp_ccm_decrypt_teeram(struct retram_resume_ctx *ctx, + void *dst, void *src, size_t size); +#endif /*__ASSEMBLER__*/ + +#endif /*__STM32MP_PM_CONTEXT_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c b/core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c new file mode 100644 index 000000000..34c797f52 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018, STMicroelectronics + * Copyright (c) 2018, Linaro Limited + */ + +#include + +#include "context.h" + +#define OFFSET_OF_CTX_STRUCT(_f) offsetof(struct retram_resume_ctx, _f) +#define OFFSET_OF_CMM_CTX_STRUCT(_f) (OFFSET_OF_CTX_STRUCT(ccm_ctx) + \ + offsetof(struct ccm_unpg_ctx, _f)) +DEFINES +{ + DEFINE(PM_CTX_RESUME_PA, OFFSET_OF_CTX_STRUCT(resume_pa)); + DEFINE(PM_CTX_TEERAM_BKP_PA, OFFSET_OF_CTX_STRUCT(teeram_bkp_pa)); + DEFINE(PM_CTX_CRYP1_BASE, OFFSET_OF_CTX_STRUCT(cryp1_base)); + DEFINE(PM_CTX_RCC_BASE, OFFSET_OF_CTX_STRUCT(rcc_base)); + DEFINE(PM_CTX_STGEN_BASE, OFFSET_OF_CTX_STRUCT(stgen_base)); + DEFINE(PM_CTX_STGEN_CNT, OFFSET_OF_CTX_STRUCT(stgen_cnt)); + DEFINE(PM_CTX_CCM_KEY, OFFSET_OF_CMM_CTX_STRUCT(key)); + DEFINE(PM_CTX_CCM_CTR1, OFFSET_OF_CMM_CTX_STRUCT(ctr1)); + DEFINE(PM_CTX_CCM_B0, OFFSET_OF_CMM_CTX_STRUCT(b0)); + DEFINE(PM_CTX_CCM_CTR0, OFFSET_OF_CMM_CTX_STRUCT(ctr0)); + DEFINE(PM_CTX_CCM_TAG, OFFSET_OF_CMM_CTX_STRUCT(tag)); + DEFINE(PM_CTX_CCM_REF_TAG, OFFSET_OF_CTX_STRUCT(ccm_ref_tag)); +} diff --git a/core/arch/arm/plat-stm32mp1/pm/low_power.c b/core/arch/arm/plat-stm32mp1/pm/low_power.c new file mode 100644 index 000000000..f06d8273d --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/low_power.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "context.h" +#include "power.h" + +#define TIMEOUT_US_1MS 1000 + +#define PWRLP_TEMPO_5_HSI 5 + +static uint8_t gicd_rcc_wakeup; +static uint8_t gicc_pmr; + +struct pwr_lp_config { + uint32_t pwr_cr1; + uint32_t pwr_mpucr; + const char *regul_suspend_node_name; +}; + +#define PWR_CR1_MASK (PWR_CR1_LPDS | PWR_CR1_LPCFG | PWR_CR1_LVDS) +#define PWR_MPUCR_MASK (PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | PWR_MPUCR_PDDS) + +static const struct pwr_lp_config config_pwr[STM32_PM_MAX_SOC_MODE] = { + [STM32_PM_CSLEEP_RUN] = { + .pwr_cr1 = 0U, + .pwr_mpucr = 0U, + .regul_suspend_node_name = NULL, + }, + [STM32_PM_CSTOP_ALLOW_STOP] = { + .pwr_cr1 = 0U, + .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF, + .regul_suspend_node_name = NULL, + }, + [STM32_PM_CSTOP_ALLOW_LP_STOP] = { + .pwr_cr1 = PWR_CR1_LPDS, + .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF, + .regul_suspend_node_name = "lp-stop", + }, + [STM32_PM_CSTOP_ALLOW_LPLV_STOP] = { + .pwr_cr1 = PWR_CR1_LVDS | PWR_CR1_LPDS | PWR_CR1_LPCFG, + .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF, + .regul_suspend_node_name = "lplv-stop", + }, + [STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR] = { + .pwr_cr1 = 0U, + .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | + PWR_MPUCR_PDDS, + .regul_suspend_node_name = "standby-ddr-sr", + }, + [STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF] = { + .pwr_cr1 = 0U, + .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | + PWR_MPUCR_PDDS, + .regul_suspend_node_name = "standby-ddr-off", + }, + [STM32_PM_SHUTDOWN] = { + .pwr_cr1 = 0U, + .pwr_mpucr = 0U, + .regul_suspend_node_name = "standby-ddr-off", + }, +}; + +static void set_rcc_it_priority(uint8_t *it_prio, uint8_t *pmr) +{ + *it_prio = itr_set_ipriority(RCC_WAKEUP_IT, GIC_HIGHEST_SEC_PRIORITY); + *pmr = itr_set_pmr(STM32MP_GIC_PRIORITY_CSTOP); +} + +static void restore_rcc_it_priority(uint8_t it_prio, uint8_t pmr) +{ + (void)itr_set_ipriority(RCC_WAKEUP_IT, it_prio); + (void)itr_set_pmr(pmr); +} + +static void stm32_apply_pmic_suspend_config(uint32_t mode) +{ + const char *name = config_pwr[mode].regul_suspend_node_name; + + assert(mode < ARRAY_SIZE(config_pwr)); + + if (stm32mp_with_pmic() && name) { + stm32mp_get_pmic(); + stm32mp_pmic_apply_lp_config(name); + stm32mp_pmic_apply_boot_on_config(); + stm32mp_put_pmic(); + } +} + +#define CONSOLE_FLUSH_DELAY_MS 10 + +#if TRACE_LEVEL >= TRACE_DEBUG +static void wait_console_flushed(void) +{ + console_flush(); + mdelay(CONSOLE_FLUSH_DELAY_MS); +} +#else +static void wait_console_flushed(void) +{ +} +#endif + +static void cpu_wfi(void) +{ + dsb(); + isb(); + wfi(); +} + +void stm32_pm_cpu_wfi(void) +{ + wait_console_flushed(); + cpu_wfi(); +} + +/* If IWDG is not supported, provide a stubbed weak watchdog kicker */ +void __weak stm32_iwdg_refresh(uint32_t __unused instance) +{ +} + +#define ARM_CNTXCTL_IMASK BIT(1) + +static void stm32mp_mask_timer(void) +{ + /* Mask timer interrupts */ + write_cntp_ctl(read_cntp_ctl() | ARM_CNTXCTL_IMASK); + write_cntv_ctl(read_cntv_ctl() | ARM_CNTXCTL_IMASK); +} + +/* + * stm32_enter_cstop - Prepare CSTOP mode + * + * @mode - Target low power mode + */ +void stm32_enter_cstop(uint32_t mode) +{ + uint32_t pwr_cr1 = config_pwr[mode].pwr_cr1; + vaddr_t pwr_base = stm32_pwr_base(); + vaddr_t rcc_base = stm32_rcc_base(); + + stm32mp_syscfg_disable_io_compensation(); + + /* Save Self-Refresh (SR) mode and switch to Software SR mode */ + ddr_save_sr_mode(DDR_SSR_MODE); + + stm32_apply_pmic_suspend_config(mode); + + if (stm32mp_with_pmic() && (mode == STM32_PM_CSTOP_ALLOW_LP_STOP)) + pwr_cr1 |= PWR_CR1_LPCFG; + + /* Workaround for non secure cache issue: this should not be needed */ + dcache_op_all(DCACHE_OP_CLEAN_INV); + + /* Clear RCC interrupt before enabling it */ + io_setbits32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF); + + /* Enable RCC Wake-up */ + io_setbits32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); + + /* Configure low power mode */ + io_clrsetbits32(pwr_base + PWR_MPUCR_OFF, PWR_MPUCR_MASK, + config_pwr[mode].pwr_mpucr); + io_clrsetbits32(pwr_base + PWR_CR1_OFF, PWR_CR1_MASK, pwr_cr1); + + /* Clear RCC pending interrupt flags */ + io_write32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_MASK); + + /* Request CSTOP mode to RCC */ + io_setbits32(rcc_base + RCC_MP_SREQSETR, + RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1); + + stm32_iwdg_refresh(IWDG2_INST); + + set_rcc_it_priority(&gicd_rcc_wakeup, &gicc_pmr); + + if (ddr_standby_sr_entry() != 0) + panic(); + + if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) { + /* Keep retention and backup RAM content in standby */ + io_setbits32(pwr_base + PWR_CR2_OFF, PWR_CR2_BREN | + PWR_CR2_RREN); + + while ((io_read32(pwr_base + PWR_CR2_OFF) & + (PWR_CR2_BRRDY | PWR_CR2_RRRDY)) == 0U) + ; + } +} + +/* + * stm32_exit_cstop - Exit from CSTOP mode + */ +void stm32_exit_cstop(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + + if (ddr_standby_sr_exit()) + panic(); + + /* Restore Self-Refresh mode saved in stm32_enter_cstop() */ + ddr_restore_sr_mode(); + + restore_rcc_it_priority(gicd_rcc_wakeup, gicc_pmr); + + /* Disable STOP request */ + io_setbits32(rcc_base + RCC_MP_SREQCLRR, + RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1); + + /* Disable RCC Wake-up */ + io_clrbits32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); + + dsb(); + isb(); + + /* Disable retention and backup RAM content after stop */ + io_clrbits32(stm32_pwr_base() + PWR_CR2_OFF, PWR_CR2_BREN | PWR_CR2_RREN); + + stm32mp_syscfg_enable_io_compensation(); +} + +/* + * GIC support required in low power sequences and reset sequences + */ +#define GICC_IAR 0x00C +#define GICC_IT_ID_MASK 0x3ff +#define GICC_EOIR 0x010 +#define GICC_HPPIR 0x018 +#define GICC_AHPPIR 0x028 +#define GIC_PENDING_G1_INTID 1022U +#define GIC_SPURIOUS_INTERRUPT 1023U +#define GIC_NUM_INTS_PER_REG 32 +#define GIC_MAX_SPI_ID 1020 +#define GICD_ICENABLER(n) (0x180 + (n) * 4) + +static void clear_pending_interrupts(void) +{ + uint32_t id = 0; + vaddr_t gicc_base = get_gicc_base(); + vaddr_t gicd_base = get_gicd_base(); + + do { + id = io_read32(gicc_base + GICC_HPPIR) & GICC_IT_ID_MASK; + + /* + * Find out which interrupt it is under the + * assumption that the GICC_CTLR.AckCtl bit is 0. + */ + if (id == GIC_PENDING_G1_INTID) + id = io_read32(gicc_base + GICC_AHPPIR) & GICC_IT_ID_MASK; + + if (id < GIC_MAX_SPI_ID) { + size_t idx = id / GIC_NUM_INTS_PER_REG; + uint32_t mask = 1 << (id % GIC_NUM_INTS_PER_REG); + + io_write32(gicc_base + GICC_EOIR, id); + + io_write32(gicd_base + GICD_ICENABLER(idx), mask); + + dsb_ishst(); + } + } while (id < GIC_MAX_SPI_ID); +} + +void stm32mp_gic_set_end_of_interrupt(uint32_t it) +{ + vaddr_t gicc_base = get_gicc_base(); + + io_write32(gicc_base + GICC_EOIR, it); +} + +static void __noreturn wait_cpu_reset(void) +{ +#ifdef STM32MP1_USE_MPU0_RESET + dcache_op_all(DCACHE_OP_CLEAN_INV); + write_sctlr(read_sctlr() & ~SCTLR_C); + dcache_op_all(DCACHE_OP_CLEAN_INV); + __asm__("clrex"); + + dsb(); + isb(); +#else + psci_armv7_cpu_off(); +#endif + + for ( ; ; ) { + clear_pending_interrupts(); + wfi(); + } +} + +#ifdef STM32MP1_USE_MPU0_RESET +/* + * tzc_source_ip contains the TZC transaction source IPs that need to be reset + * before a C-A7 subsystem is reset (i.e. independent reset): + * - C-A7 subsystem is reset separately later in the sequence, + * - C-M4 subsystem is not concerned here, + * - DAP is excluded for debug purpose, + * - IPs are stored with their ETZPC IDs (STM32MP1_ETZPC_MAX_ID if not + * applicable) because some of them need to be reset only if they are not + * configured in MCU isolation mode inside ETZPC device tree. + */ +struct tzc_source_ip { + uint16_t reset_id; + uint16_t clock_id; + uint32_t decprot_id; +}; + +#define _TZC_FIXED(res, clk) \ + { \ + .reset_id = (res), \ + .clock_id = (clk), \ + .decprot_id = STM32MP1_ETZPC_MAX_ID, \ + } + +#define _TZC_COND(res, clk, decprot) \ + { \ + .reset_id = (res), \ + .clock_id = (clk), \ + .decprot_id = (decprot), \ + } + +static const struct tzc_source_ip __maybe_unused tzc_source_ip[] = { + _TZC_FIXED(LTDC_R, LTDC_PX), + _TZC_FIXED(GPU_R, GPU), + _TZC_FIXED(USBH_R, USBH), + _TZC_FIXED(SDMMC1_R, SDMMC1_K), + _TZC_FIXED(SDMMC2_R, SDMMC2_K), + _TZC_FIXED(MDMA_R, MDMA), + _TZC_COND(USBO_R, USBO_K, STM32MP1_ETZPC_OTG_ID), + _TZC_COND(SDMMC3_R, SDMMC3_K, STM32MP1_ETZPC_SDMMC3_ID), + _TZC_COND(ETHMAC_R, ETHMAC, STM32MP1_ETZPC_ETH_ID), + _TZC_COND(DMA1_R, DMA1, STM32MP1_ETZPC_DMA1_ID), + _TZC_COND(DMA2_R, DMA2, STM32MP1_ETZPC_DMA2_ID), +}; + +static void reset_peripherals(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + size_t __maybe_unused id = 0; + + for (id = 0U; id < ARRAY_SIZE(tzc_source_ip); id++) { + const struct tzc_source_ip *tzc = &tzc_source_ip[id]; + + if (!stm32_clock_is_enabled(tzc->clock_id) || + ((tzc->decprot_id != STM32MP1_ETZPC_MAX_ID) && + (etzpc_get_decprot(tzc->decprot_id) == + ETZPC_DECPROT_MCU_ISOLATION))) + continue; + + if (tzc->reset_id != GPU_R) { + stm32_reset_assert(tzc->reset_id, TIMEOUT_US_1MS); + stm32_reset_deassert(tzc->reset_id, TIMEOUT_US_1MS); + } else { + /* GPU reset automatically cleared by hardware */ + io_setbits32(rcc_base + RCC_AHB6RSTSETR, + RCC_AHB6RSTSETR_GPURST); + } + } +} +#endif /* STM32MP1_USE_MPU0_RESET */ + +static void __noreturn reset_cores(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + uint32_t reset_mask = RCC_MP_GRSTCSETR_MPUP0RST | + RCC_MP_GRSTCSETR_MPUP1RST; + uint32_t target_mask = 0; + + /* Mask timer interrupts */ + stm32mp_mask_timer(); + +#ifdef STM32MP1_USE_MPU0_RESET + reset_peripherals(); +#endif + + if (get_core_pos() == 0) + target_mask = TARGET_CPU1_GIC_MASK; + else + target_mask = TARGET_CPU0_GIC_MASK; + + itr_raise_sgi(GIC_SEC_SGI_1, target_mask); + + clear_pending_interrupts(); + + io_write32(rcc_base + RCC_MP_GRSTCSETR, reset_mask); + + wait_cpu_reset(); +} + +/* + * stm32_pm_cpus_reset - Reset only cpus + */ +void __noreturn stm32_cores_reset(void) +{ + reset_cores(); +} +DECLARE_KEEP_PAGER(stm32_cores_reset); + +static __maybe_unused void reset_other_core(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + uint32_t reset_mask = 0; + uint32_t target_mask = 0; + + if (get_core_pos() == 0) { + reset_mask = RCC_MP_GRSTCSETR_MPUP1RST; + target_mask = TARGET_CPU1_GIC_MASK; + } else { + reset_mask = RCC_MP_GRSTCSETR_MPUP0RST; + target_mask = TARGET_CPU0_GIC_MASK; + } + + itr_raise_sgi(GIC_SEC_SGI_1, target_mask); + + io_write32(rcc_base + RCC_MP_GRSTCSETR, reset_mask); +} + +/* + * stm32_enter_cstop_shutdown - Shutdown CPUs to target low power mode + * @mode - Target low power mode + */ +void __noreturn stm32_enter_cstop_shutdown(uint32_t mode) +{ + switch (mode) { + case STM32_PM_SHUTDOWN: + if (stm32mp_with_pmic()) { + wait_console_flushed(); + stm32mp_get_pmic(); + stpmic1_switch_off(); + udelay(100); + } + break; + case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR: + case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF: +#ifdef STM32MP1_USE_MPU0_RESET + stm32mp_pm_shutdown_context(); + reset_other_core(); + stm32_enter_cstop(mode); + dsb(); + isb(); + for ( ; ; ) + wfi(); +#else + if (stm32mp_with_pmic()) { + wait_console_flushed(); + stm32mp_get_pmic(); + stpmic1_switch_off(); + udelay(100); + } +#endif + break; + default: + break; + } + + panic(); +} + +/* + * stm32_enter_cstop_reset - Reset CPUs to target low power mode + * @mode - Target low power mode + */ +void __noreturn stm32_enter_cstop_reset(uint32_t mode) +{ + vaddr_t rcc = stm32_rcc_base(); + + switch (mode) { + case STM32_PM_SHUTDOWN: + io_write32(rcc + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); + udelay(100); + break; + default: + IMSG("Forced system reset"); + wait_console_flushed(); + io_write32(rcc + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); + udelay(100); + break; + } + + panic(); +} + +/* + * stm32_enter_csleep - enter CSLEEP state while WFI and exit in CRUN + * + * Configure PWR for CSLEEP state. CPU shall execute a WFI and return + * once a interrupt is pending. + */ +void stm32_enter_csleep(void) +{ + vaddr_t pwr_base = stm32_pwr_base(); + + io_clrsetbits32(pwr_base + PWR_MPUCR_OFF, PWR_MPUCR_MASK, + config_pwr[STM32_PM_CSLEEP_RUN].pwr_mpucr); + io_clrsetbits32(pwr_base + PWR_CR1_OFF, PWR_CR1_MASK, + config_pwr[STM32_PM_CSLEEP_RUN].pwr_cr1); + + stm32_pm_cpu_wfi(); +} + +/* RCC Wakeup interrupt is used to wake from suspeneded mode */ +static enum itr_return rcc_wakeup_it_handler(struct itr_handler *hdl __unused) +{ + /* This interrupt is not expected to be handled */ + panic("RCC wakeup interrupt"); + return ITRR_HANDLED; +} + +static struct itr_handler rcc_wakeup_handler = { + .it = RCC_WAKEUP_IT, + .handler = rcc_wakeup_it_handler, +}; +DECLARE_KEEP_PAGER(rcc_wakeup_handler); + +/* SGI9 (secure SGI 1) informs targeted CPU it shall reset */ +static enum itr_return sgi9_it_handler(struct itr_handler *handler) +{ + stm32mp_mask_timer(); + + stm32mp_gic_set_end_of_interrupt(handler->it); + + clear_pending_interrupts(); + + wait_cpu_reset(); + + panic("Core reset"); + + return ITRR_HANDLED; +} + +static struct itr_handler sgi9_reset_handler = { + .it = GIC_SEC_SGI_1, + .handler = sgi9_it_handler, +}; +DECLARE_KEEP_PAGER(sgi9_reset_handler); + +static TEE_Result init_low_power(void) +{ + vaddr_t pwr_base = stm32_pwr_base(); + vaddr_t rcc_base = stm32_rcc_base(); + + itr_add(&rcc_wakeup_handler); + itr_enable(rcc_wakeup_handler.it); + + itr_add(&sgi9_reset_handler); + itr_enable(sgi9_reset_handler.it); + + /* Enable retention for BKPSRAM and BKPREG */ + io_mask32(pwr_base + PWR_CR2_OFF, + PWR_CR2_BREN | PWR_CR2_RREN, PWR_CR2_BREN | PWR_CR2_RREN); + + /* + * Configure Standby mode available for MCU by default + * and allow to switch in standby SoC in all case + */ + io_setbits32(pwr_base + PWR_MCUCR_OFF, PWR_MCUCR_PDDS); + + /* Disable STOP request */ + io_setbits32(rcc_base + RCC_MP_SREQCLRR, + RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1); + + /* Wait 5 HSI periods before re-enabling PLLs after STOP modes */ + io_clrsetbits32(rcc_base + RCC_PWRLPDLYCR, RCC_PWRLPDLYCR_PWRLP_DLY_MASK, + PWRLP_TEMPO_5_HSI); + + return TEE_SUCCESS; +} +service_init(init_low_power); + +/* + * CPU low power sequences + */ +void __noreturn stm32_pm_cpu_power_down_wfi(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + + if (get_core_pos() == 0) { + void (*reset_ep)(void) = stm32mp_sysram_resume; + + stm32_pm_cpu_wfi(); + + /* STANDBY not reached: resume from retained SYSRAM */ + stm32_exit_cstop(); + stm32mp_cpu_reset_state(); + reset_ep(); + panic(); + } + + dcache_op_level1(DCACHE_OP_CLEAN); + io_write32(rcc_base + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPUP1RST); + cpu_wfi(); + panic(); +} diff --git a/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S b/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S new file mode 100644 index 000000000..63142a08e --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S @@ -0,0 +1,729 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2018, STMicroelectronics + * Copyright (c) 2017 NXP + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "context.h" + +/* + * Right bit shift distance to reach timeout from a 1s STGEN freq count + * Value N relates to 1000ms / 2^N, i.e 7 relates to 7.8125ms=~8ms + */ +#define CCM_TIMEOUT_128MS 2 +#define CCM_TIMEOUT_8MS 7 +#define CCM_TIMEOUT_1MS 10 +#define CCM_TIMEOUT_16US 16 +#define CCM_TIMEOUT CCM_TIMEOUT_8MS + +/* + * CRYP interface register used for AES CCM + */ +#define CRYP_CR 0x000 +#define CRYP_SR 0x004 +#define CRYP_DIN 0x008 +#define CRYP_DOUT 0x00c +#define CRYP_KEYR_BASE 0x020 +#define CRYP_IVR_BASE 0x040 + +#define CRYP_CR_ALGODIR_DECRYPT BIT(2) +#define CRYP_CR_ALGOMODE_MASK (BIT(19) | GENMASK_32(5, 3)) +#define CRYP_CR_ALGOMODE(m) (((m & BIT(3)) << 16) | (m & 0x7) << 3) +#define ALGOMODE_AES_CCM 0x9 +#define CRYP_CR_DATATYPE_SHIFT 6 +#define CRYP_CR_DATATYPE_8BIT (2 << CRYP_CR_DATATYPE_SHIFT) +#define CRYP_CR_KEYSIZE_SHIFT 8 +#define CRYP_CR_KEYSIZE_256BIT (2U << CRYP_CR_KEYSIZE_SHIFT) +#define CRYP_CR_CRYPEN BIT(15) +#define CRYP_CR_FFLUSH BIT(14) +#define CRYP_CR_GCM_CCMPH_SHIFT 16 +#define CRYP_CR_PHASE_MASK (0x3 << CRYP_CR_GCM_CCMPH_SHIFT) +#define CRYP_CR_INIT_PHASE (0 << CRYP_CR_GCM_CCMPH_SHIFT) +#define CRYP_CR_HEADER_PHASE (1 << CRYP_CR_GCM_CCMPH_SHIFT) +#define CRYP_CR_PAYLOAD_PHASE (2 << CRYP_CR_GCM_CCMPH_SHIFT) +#define CRYP_CR_FINAL_PHASE (3 << CRYP_CR_GCM_CCMPH_SHIFT) + +#define CRYP_SR_BUSY BIT(4) +#define CRYP_SR_OFFU BIT(3) +#define CRYP_SR_OFNE BIT(2) +#define CRYP_SR_IFNF BIT(1) +#define CRYP_SR_IFEM BIT(0) + +/* + * Enable TRACE_SYSRAM_RESTORE to get some UART console traces + * at resume time. + */ +#if defined(TRACE_SYSRAM_RESTORE) + +#define UART_BASE UART4_BASE +#define UART_ISR_OFF 0x1c +#define UART_TDR_OFF 0x28 +#define USART_ISR_TXE_TXFNF (1<< 7) + + .macro PRINT_CHAR _reg0, _reg1, _char + /* Trace only at resume when MMU is OFF */ + read_sctlr \_reg0 + ands \_reg0, #SCTLR_M + 101: + bne 102f + mov_imm \_reg0, UART4_BASE + ldr \_reg1, [\_reg0, #UART_ISR_OFF] + ands \_reg1, #USART_ISR_TXE_TXFNF + beq 101b + mov_imm \_reg1, (\_char) + str \_reg1, [\_reg0, #UART_TDR_OFF] + 102: + .endm +#else + .macro PRINT_CHAR _reg0, _reg1, _char + .endm +#endif + + /* Bound of the binary image loaded in retained memory */ + .global stm32mp_bkpsram_image_end + +/* + * stm32mp_bkpsram_resume - Restore TEE RAM from backup memory and resume into + * + * This function executes at early resume from suspend state. It is the + * entrypoint of the OP-TEE provided to early boot stage when SoC wakes. + * This code is located in a retained memory, MMU disabled. This function + * shall restore TEE RAM content for OP-TEE to resume execution. Once + * TEE RAM is restored, this function branches to the resident resume entry + * point in TEE_RAM. This function and its resources shall execute in place. + */ +FUNC stm32mp_bkpsram_resume , : +UNWIND( .cantunwind) + + PRINT_CHAR r0, r1, '0' + + /* + * Almost all sequences here expect PM context structure base address + * from CPU register r11. + */ + mov_imm r11, (BKPSRAM_BASE + BKPSRAM_PM_CONTEXT_OFFSET) + + /* stm32mp_ccm_teeram needs some HW interface base addresss */ + mov_imm r0, CRYP1_BASE + str r0, [r11, #PM_CTX_CRYP1_BASE] + mov_imm r0, RCC_BASE + str r0, [r11, #PM_CTX_RCC_BASE] + mov_imm r0, STGEN_BASE + str r0, [r11, #PM_CTX_STGEN_BASE] + + bl _clear_early_mailbox + bl _prepare_time + + mov_imm r0, TEE_RAM_START + ldr r1, [r11, #PM_CTX_TEERAM_BKP_PA] + mov_imm r2, TEE_RAM_PH_SIZE + mov_imm r3, 1 + bl stm32mp_ccm_teeram + cmp r0, #0 + bne _failed + + PRINT_CHAR r0, r1, 'T' + PRINT_CHAR r0, r1, 'a' + PRINT_CHAR r0, r1, 'g' + PRINT_CHAR r0, r1, '\n' + + /* Compare the generated and reference tags */ + add r8, r11, #PM_CTX_CCM_TAG + add r9, r11, #PM_CTX_CCM_REF_TAG + ldm r8, {r2-r5} + ldm r9, {r6-r9} + mov r0, #0 + cmp r2, r6 + addeq r0, #1 + cmp r3, r7 + addeq r0, #1 + cmp r4, r8 + addeq r0, #1 + cmp r5, r9 + addeq r0, #1 + cmp r0, #4 + bne _failed + bl _save_resume_time + + PRINT_CHAR r1, r2, 'O' + PRINT_CHAR r1, r2, 'k' + PRINT_CHAR r1, r2, '\n' + + /* Resume into the restored TEE RAM */ + ldr r1, [r11, #PM_CTX_RESUME_PA] + bx r1 + +_failed: + PRINT_CHAR r0, r12, 'F' + PRINT_CHAR r0, r12, '\n' + + /* Clear context including key and reference tag */ + mov r0, #0xa5 + mov_imm r12, BKPSRAM_PM_CONTEXT_SIZE + add r12, r11, r12 +1: str r0, [r11], #4 + cmp r11, r12 + blt 1b + b . + + /* + * _clear_early_mailbox - Wipe mailbox in case of reset + * + * Sratches r0-r4. + * All other CPU registers are preserved. + */ +_clear_early_mailbox: + /* Clear the backup registers (first enable RTCAPB clock) */ + mov_imm r0, (RCC_BASE + RCC_MP_APB5ENSETR) + mov_imm r2, RCC_MP_APB5ENSETR_RTCAPBEN + ldr r1, [r0] + ands r1, r1, r2 + moveq r1, r2 + movne r1, #0 + str r2, [r0] + mov_imm r2, (TAMP_BASE + TAMP_BKP_REGISTER_OFF) + mov_imm r3, (BCKR_CORE1_MAGIC_NUMBER * 4) + mov_imm r4, BOOT_API_A7_RESET_MAGIC_NUMBER + str r4, [r2, r3] + mov_imm r3, (BCKR_CORE1_BRANCH_ADDRESS * 4) + mov r4, #0 + str r4, [r2, r3] + /* Restore RTCAPB clock initial state */ + str r1, [r0, #RCC_MP_ENCLRR_OFFSET] + bx lr + + /* + * prepare_time - save/reset cycle counter to prevent later overflow + * + * Save current 32bit lower counter and reset to 0 so that later + * timeout test do not need to care about overflow. + * + * Expects r11 is context base and lr is return address. + * Scrathes r0-r2. + * All other CPU registers are preserved. + */ +_prepare_time: + ldr r2, [r11, #PM_CTX_STGEN_BASE] + /* Disable STGEN counter */ + ldr r1, [r2, #CNTCR_OFFSET] + bic r1, r1, #CNTCR_EN + str r1, [r2, #CNTCR_OFFSET] +1: ldr r1, [r2, #CNTSR_OFFSET] + tst r1, #CNTCR_EN + bne 1b + /* Save and reset STGEN counter */ + ldr r0, [r2, #CNTCVL_OFFSET] + str r0, [r11, #PM_CTX_STGEN_CNT] + mov r0, #0 + str r0, [r2, #CNTCVL_OFFSET] + ldr r0, [r2, #CNTCVU_OFFSET] + str r0, [r2, #CNTCVU_OFFSET] + /* Enable STGEN counter */ + ldr r1, [r2, #CNTCR_OFFSET] + orr r1, r1, #CNTCR_EN + str r1, [r2, #CNTCR_OFFSET] + bx lr + + /* + * save_resume_time - save time spent and restore STGEN cycle counter + * + * Restore STGEN counter to initial value incremented by the current + * count. Note 32bit upper may need to be incremented. + * + * Expects r11 is context base and lr is return address. + * Scrathes r0-r3. + * All other CPU registers are preserved. + */ +_save_resume_time: + /* Compute update STGEN counter 32bit LSB value */ + ldr r2, [r11, #PM_CTX_STGEN_BASE] + ldr r0, [r11, #PM_CTX_STGEN_CNT] + ldr r3, [r2, #CNTCVL_OFFSET] + str r3, [r11, #PM_CTX_STGEN_CNT] + adds r0, r0, r3 + /* Disable STGEN */ + ldr r1, [r2, #CNTCR_OFFSET] + bic r1, r1, #CNTCR_EN + str r1, [r2, #CNTCR_OFFSET] +1: ldr r1, [r2, #CNTSR_OFFSET] + tst r1, #CNTCR_EN + bne 1b + /* Update counter (increment 32bit MSB if requried) */ + str r0, [r2, #CNTCVL_OFFSET] + ldr r0, [r2, #CNTCVU_OFFSET] + addcs r0, r0, #1 + str r0, [r2, #CNTCVU_OFFSET] /* Write CNTCVU value ... */ + ldr r0, [r2, #CNTCVU_OFFSET] /* ... and wait it is set */ + /* Enable STGEN */ + ldr r0, [r2, #CNTCR_OFFSET] + orr r0, r0, #CNTCR_EN + str r0, [r2, #CNTCR_OFFSET] + bx lr + + /* + * _setup_cryp1 - Enable CRYP1 hardware: reset & clock + * _reset_cryp1 - Reset CRYP1 hardware + * + * Function call before and after CCM sequence. Note that the CRYP1 + * clock remain enabled. It is disabled later by the resume sequence. + * + * Expects r11 is context base and lr is return address. + * Scratches r0-r3. + */ +_setup_cryp1: + ldr r1, [r11, #PM_CTX_RCC_BASE] + mov_imm r0, RCC_MP_AHB5ENSETR_CRYP1EN + str r0, [r1, #RCC_MP_AHB5ENSETR] + /* Intentionnally fall through reset_cryp1 */ +_reset_cryp1: + ldr r3, [r11, #PM_CTX_RCC_BASE] + mov_imm r0, RCC_AHB5RSTSETR_CRYP1RST + str r0, [r3, #RCC_AHB5RSTSETR] +1: ldr r1, [r3, #RCC_AHB5RSTSETR] + ands r1, r1, r0 + beq 1b + mov_imm r0, RCC_AHB5RSTSETR_CRYP1RST + str r0, [r3, #RCC_AHB5RSTCLRR] +1: ldr r1, [r3, #RCC_AHB5RSTSETR] + ands r1, r1, r0 + bne 1b + bx lr + + /* + * _ccm_arm_8ms_timeout - Init 8ms threshold for _ccm_failed_on_timeout + * _ccm_fail_on_timeout - Check STGEN counter against timeout threshold + * + * These function are used by the macro wait_flag_timeout_8ms. The + * former loads the timeout in CPU register r0 while the later get the + * timeout counter threshold from CPU register r0. + * + * Expect r11 is context base and lr is return address. + * Scratch r0-r1. + * All other CPU registers are preserved. + */ +_ccm_arm_8ms_timeout: + ldr r1, [r11, #PM_CTX_STGEN_BASE] + ldr r0, [r1, #CNTFID_OFFSET] + lsrs r0, r0, #CCM_TIMEOUT + moveq r0, #1 + ldr r1, [r1, #CNTCVL_OFFSET] + adds r0, r0, r1 + bcs _ccm_failed_on_timeout + bx lr + +_ccm_fail_on_timeout: + + ldr r1, [r11, #PM_CTX_STGEN_BASE] + ldr r1, [r1, #CNTCVL_OFFSET] + cmp r1, r0 + bge _ccm_failed_on_timeout + bx lr + +_ccm_failed_on_timeout: + PRINT_CHAR r0, r1, 'T' + PRINT_CHAR r0, r1, 'o' + PRINT_CHAR r0, r1, '\n' + b _ccm_failed + + /* + * Macro WAIT_FLAG_TIMEOUT compares timeout threshold (r0) with + * current time and branches the CCM failure entry on timeout. + * It is assumed the 32bit timestamps cannot overflow. + */ + .macro WAIT_FLAG_TIMEOUT register_offset, bit_mask, awaited_mask + bl _ccm_arm_8ms_timeout + 1: + bl _ccm_fail_on_timeout + ldr r1, [r10, #(\register_offset)] + and r1, r1, #(\bit_mask) + cmp r1, #(\awaited_mask) + bne 1b + .endm + +/* + * stm32mp_ccm_teeram - Size optimzed unpaged CCM encryption/decryption + * + * This sequence encrypts or decrypts a input block using AES CCM with a + * 256bit key and no AAD and generates the CCM tag. The key, CTR0, CTR1 + * and B0 block are read from PM context structure. The generated tag is + * stored in the PM context structure. + * + * This function is executed from TEE RAM during suspend sequence to generate + * the encrypted data and the tag. This function is also executed from BKPSRAM + * called with MMU disabled. Therefore this sequence shall be comply with + * position independent code constraints. + * + * Expects at entry: + * lr = caller return address + * r11 = retram_resume_ctx structure base address + * r0 = Destination buffer for the output data (ciphertext or plaintext) + * r1 = Source buffer for the input data (plaintext or ciphertext) + * r2 = Input (and output) data size in bytes + * r3 = 1 if decrypting, 0 if encrypting + */ +stm32mp_ccm_teeram: + /* + * Use of the CPU registers in the whole stm32mp_ccm_teeram sequence + * + * sp: preserved, not used + * lr: scratch register used to call subroutines. + * r12: saves the caller link register for final return + * r11: context from BKPSRAM + * r10: CRYP1 base address + * r9: destination buffer + * r8: source buffer to cipher + * r7: data byte counter + * r0-r6 are scratch registers + */ + mov r12, lr + ldr r10, [r11, #PM_CTX_CRYP1_BASE] + mov r9, r0 + mov r8, r1 + mov r7, r2 + mov r6, r3 + + PRINT_CHAR r0, r1, '1' + + bl _setup_cryp1 + + PRINT_CHAR r0, r1, '2' + + mov_imm r0, (CRYP_CR_ALGOMODE(ALGOMODE_AES_CCM) | \ + CRYP_CR_DATATYPE_8BIT | CRYP_CR_FFLUSH | \ + CRYP_CR_KEYSIZE_256BIT) + cmp r6, #0 + orrne r0, r0, #CRYP_CR_ALGODIR_DECRYPT + str r0, [r10, #CRYP_CR] + + PRINT_CHAR r0, r1, '3' + + /* Check data alignment (addresses and size) */ + ands r0, r7, #0x0F + bne _ccm_failed + ands r0, r8, #0x03 + bne _ccm_failed + ands r0, r9, #0x03 + bne _ccm_failed + + PRINT_CHAR r0, r1, '4' + + ldr r0, [r11, #PM_CTX_CCM_KEY] + str r0, [r10, #CRYP_KEYR_BASE] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 4)] + str r0, [r10, #(CRYP_KEYR_BASE + 4)] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 8)] + str r0, [r10, #(CRYP_KEYR_BASE + 8)] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 12)] + str r0, [r10, #(CRYP_KEYR_BASE + 12)] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 16)] + str r0, [r10, #(CRYP_KEYR_BASE + 16)] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 20)] + str r0, [r10, #(CRYP_KEYR_BASE + 20)] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 24)] + str r0, [r10, #(CRYP_KEYR_BASE + 24)] + ldr r0, [r11, #(PM_CTX_CCM_KEY + 28)] + str r0, [r10, #(CRYP_KEYR_BASE + 28)] + + ldr r0, [r11, #PM_CTX_CCM_CTR1] + str r0, [r10, #CRYP_IVR_BASE] + ldr r0, [r11, #(PM_CTX_CCM_CTR1 + 4)] + str r0, [r10, #(CRYP_IVR_BASE + 4)] + ldr r0, [r11, #(PM_CTX_CCM_CTR1 + 8)] + str r0, [r10, #(CRYP_IVR_BASE + 8)] + ldr r0, [r11, #(PM_CTX_CCM_CTR1 + 12)] + str r0, [r10, #(CRYP_IVR_BASE + 12)] + + /* Setup CRYP for the CCM Init Phase */ + ldr r0, [r10, #CRYP_CR] + orr r0, r0, #(CRYP_CR_CRYPEN | CRYP_CR_INIT_PHASE) + str r0, [r10, #CRYP_CR] + ldr r0, [r10, #CRYP_CR] + + ldr r0, [r11, #PM_CTX_CCM_B0] + str r0, [r10, #CRYP_DIN] + ldr r0, [r11, #(PM_CTX_CCM_B0 + 4)] + str r0, [r10, #CRYP_DIN] + ldr r0, [r11, #(PM_CTX_CCM_B0 + 8)] + str r0, [r10, #CRYP_DIN] + ldr r0, [r11, #(PM_CTX_CCM_B0 + 12)] + str r0, [r10, #CRYP_DIN] + + PRINT_CHAR r0, r1, '5' + + WAIT_FLAG_TIMEOUT CRYP_CR, CRYP_CR_CRYPEN, 0 + + /* Setup CRYP for the CCM Payload phase */ + ldr r0, [r10, #CRYP_CR] + bic r0, r0, #CRYP_CR_PHASE_MASK + orr r0, r0, #CRYP_CR_PAYLOAD_PHASE + orr r0, r0, #CRYP_CR_CRYPEN + str r0, [r10, #CRYP_CR] + ldr r0, [r10, #CRYP_CR] + + PRINT_CHAR r0, r1, '\n' + +_next_block: + PRINT_CHAR r0, r1, 'b' + + WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_IFEM, CRYP_SR_IFEM + + /* Feed input data, r8 stores the current source buffer */ + ldr r0, [r8], #4 + str r0, [r10, #CRYP_DIN] + ldr r0, [r8], #4 + str r0, [r10, #CRYP_DIN] + ldr r0, [r8], #4 + str r0, [r10, #CRYP_DIN] + ldr r0, [r8], #4 + str r0, [r10, #CRYP_DIN] + + WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_OFNE, CRYP_SR_OFNE + + /* Store output data, r9 stores the current source buffer */ + ldr r0, [r10, #CRYP_DOUT] + str r0, [r9], #4 + ldr r0, [r10, #CRYP_DOUT] + str r0, [r9], #4 + ldr r0, [r10, #CRYP_DOUT] + str r0, [r9], #4 + /* Before last 32bit word, the output FIFO shall not be empty */ + ldr r0, [r10, #CRYP_SR] + ands r0, r0, #CRYP_SR_OFNE + beq _ccm_failed + /* After last 32bit word for this 128block, FIFO shall be empty */ + ldr r0, [r10, #CRYP_DOUT] + str r0, [r9], #4 + ldr r0, [r10, #CRYP_SR] + ands r0, r0, #CRYP_SR_OFNE + bne _ccm_failed + + /* Another round if remaining data */ + subs r7, r7, #16 + bne _next_block; + + PRINT_CHAR r0, r1, '\n' + PRINT_CHAR r0, r1, '6' + + WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_BUSY, 0 + + /* + * Data processing completed, now remains the tag generation. + * Here expect SR[IFNF]=SR[OFNE]=1 and all others bits are 0. + */ + ldr r0, [r10, #CRYP_SR] + cmp r0, #(CRYP_SR_IFEM | CRYP_SR_IFNF) + bne _ccm_failed + + PRINT_CHAR r0, r1, '7' + + /* Setup CRYP1 for the CCM Final Phase */ + ldr r0, [r10, #CRYP_CR] + bic r0, r0, #CRYP_CR_CRYPEN + str r0, [r10, #CRYP_CR] + ldr r0, [r10, #CRYP_CR] + bic r0, r0, #CRYP_CR_PHASE_MASK + bic r0, r0, #CRYP_CR_ALGODIR_DECRYPT + orr r0, r0, #CRYP_CR_FINAL_PHASE + orr r0, r0, #CRYP_CR_CRYPEN + str r0, [r10, #CRYP_CR] + ldr r0, [r10, #CRYP_CR] + + /* Load CTR0 to generate the tag */ + ldr r0, [r11, #PM_CTX_CCM_CTR0] + str r0, [r10, #CRYP_DIN] + ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 4)] + str r0, [r10, #CRYP_DIN] + ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 8)] + str r0, [r10, #CRYP_DIN] + ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 12)] + str r0, [r10, #CRYP_DIN] + + PRINT_CHAR r0, r1, '8' + + WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_OFNE, CRYP_SR_OFNE + + /* Store generated tag in the PM_CTX structure */ + ldr r0, [r10, #CRYP_DOUT] + str r0, [r11, #PM_CTX_CCM_TAG] + ldr r0, [r10, #CRYP_DOUT] + str r0, [r11, #(PM_CTX_CCM_TAG + 4)] + ldr r0, [r10, #CRYP_DOUT] + str r0, [r11, #(PM_CTX_CCM_TAG + 8)] + /* Before last 32bit word, the output FIFO shall not be empty */ + ldr r0, [r10, #CRYP_SR] + ands r0, r0, #CRYP_SR_OFNE + beq _ccm_failed + /* After last 32bit word for this 128block, FIFO shall be empty */ + ldr r0, [r10, #CRYP_DOUT] + str r0, [r11, #(PM_CTX_CCM_TAG + 12)] + ldr r0, [r10, #CRYP_SR] + ands r0, r0, #CRYP_SR_OFNE + bne _ccm_failed + + PRINT_CHAR r0, r1, '9' + + /* Successful return */ + bl _reset_cryp1 + mov r0, #0 + bx r12 + +_ccm_failed: + + PRINT_CHAR r0, r1, 'K' + PRINT_CHAR r0, r1, 'O' + + bl _reset_cryp1 + mov r0, #1 + bx r12 + +/* End address of the PIC resume sequence copy in retained RAM */ +stm32mp_bkpsram_image_end: + nop + +END_FUNC stm32mp_bkpsram_resume + +/* + * int stm32mp_ccm_encrypt_teeram(ctx, dst, src, len) + */ +FUNC stm32mp_ccm_encrypt_teeram , : + push {r4-r12, lr} +UNWIND( .save {r4-r12, lr}) + mov r11, r0 + mov r0, r1 + mov r1, r2 + mov r2, r3 + mov r3, #0 + push {r0-r3} + bl _prepare_time + pop {r0-r3} + bl stm32mp_ccm_teeram + bl _save_resume_time + pop {r4-r12, pc} +END_FUNC stm32mp_ccm_encrypt_teeram + +/* + * int stm32mp_ccm_decrypt_teeram(ctx, cryp_base, dst, src) + */ +FUNC stm32mp_ccm_decrypt_teeram , : + push {r4-r12, lr} +UNWIND( .save {r4-r12, lr}) + mov r11, r0 + mov r0, r1 + mov r1, r2 + mov r2, r3 + mov r3, #1 + push {r0-r3} + bl _prepare_time + pop {r0-r3} + bl stm32mp_ccm_teeram + bl _save_resume_time + pop {r4-r12, pc} +END_FUNC stm32mp_ccm_decrypt_teeram + +/* + * stm32mp_sysram_resume - Resume OP-TEE execution + * + * This function is the entry point of OP-TEE core resume sequence in the TEE + * RAM. When TEE RAM is lost during a power cycle, stm32mp_bkpsram_resume() is + * called to restore TEE RAM content and branch to this stm32mp_sysram_resume() + * routine. + * + * This function calls the OP-TEE core generic PM resume API + * sm_pm_cpu_resume(). + */ +FUNC stm32mp_sysram_resume, : +UNWIND( .cantunwind) + /* Invalidate the data cache */ + + read_clidr r2 + ubfx r3, r2, #CLIDR_LOC_SHIFT, #CLIDR_FIELD_WIDTH + lsl r3, r3, #CSSELR_LEVEL_SHIFT + mov r1, #0 + +loop1: + add r10, r1, r1, LSR #1 // Work out 3x current cache level + mov r12, r2, LSR r10 // extract cache type bits from clidr + and r12, r12, #7 // mask the bits for current cache only + cmp r12, #2 // see what cache we have at this level + blo level_done // no cache or only instruction cache at this level + + write_csselr r1 // select current cache level in csselr + isb // isb to sych the new cssr&csidr + read_ccsidr r12 // read the new ccsidr + and r10, r12, #7 // extract the length of the cache lines + add r10, r10, #4 // add 4 (r10 = line length offset) + ubfx r4, r12, #3, #10 // r4 = maximum way number (right aligned) + clz r5, r4 // r5 = the bit position of the way size increment + mov r9, r4 // r9 working copy of the aligned max way number + +loop2: + ubfx r7, r12, #13, #15 // r7 = max set number (right aligned) + +loop3: + orr r0, r1, r9, LSL r5 // factor in the way number and cache level into r0 + orr r0, r0, r7, LSL r10 // factor in the set number + + write_dcisw r0 + + subs r7, r7, #1 // decrement the set number + bhs loop3 + subs r9, r9, #1 // decrement the way number + bhs loop2 +level_done: + add r1, r1, #2 // increment the cache number + cmp r3, r1 + dsb sy // ensure completion of previous cache maintenance instruction + bhi loop1 + + mov r6, #0 + write_csselr r6 //select cache level 0 in csselr + dsb sy + isb + + /* Resume sequence executes in Monitor mode */ + cps #CPSR_MODE_MON + + blx plat_cpu_reset_early + b sm_pm_cpu_resume +END_FUNC stm32mp_sysram_resume + +/* + * stm32mp_cpu_reset_state - set CPU in a reset like state + * + * Disable CPU env (interrupts, cache, SMP, MMU) and return. + * Preserve the execution mode in CPSR. + */ +FUNC stm32mp_cpu_reset_state, : + push {r12, lr} +UNWIND( .save {r12, lr}) + + cpsid aif + + bl psci_armv7_cpu_off + + write_bpiall + dsb + isb + read_sctlr r0 + bic r0, r0, #SCTLR_M + bic r0, r0, #SCTLR_I + write_sctlr r0 + dsb sy + isb + + pop {r12, pc} +END_FUNC stm32mp_cpu_reset_state diff --git a/core/arch/arm/plat-stm32mp1/pm/power.h b/core/arch/arm/plat-stm32mp1/pm/power.h new file mode 100644 index 000000000..4a5578c63 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/power.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + */ + +#ifndef __STM32MP_PM_POWER_H__ +#define __STM32MP_PM_POWER_H__ + +#include +#include +#include + +bool need_to_backup_cpu_context(unsigned int soc_mode); +bool need_to_backup_stop_context(unsigned int soc_mode); + +void stm32_enter_csleep(void); + +void stm32_enter_cstop(uint32_t mode); +void stm32_exit_cstop(void); + +void stm32_enter_cstop_shutdown(uint32_t mode) __noreturn; +void stm32_enter_cstop_reset(uint32_t mode) __noreturn; + +void stm32_pm_cpu_power_down_wfi(void) __noreturn; +void stm32_pm_cpu_wfi(void); + +#endif /*__STM32MP_PM_POWER_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/pm/power_config.c b/core/arch/arm/plat-stm32mp1/pm/power_config.c new file mode 100644 index 000000000..61e4f6800 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/pm/power_config.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "context.h" +#include "power.h" + +#define DT_PWR_COMPAT "st,stm32mp1,pwr-reg" +#define SYSTEM_SUSPEND_SUPPORTED_MODES "system_suspend_supported_soc_modes" +#define SYSTEM_OFF_MODE "system_off_soc_mode" + +static uint32_t deepest_suspend_mode; +static uint32_t system_off_mode; +static uint8_t stm32mp1_supported_soc_modes[STM32_PM_MAX_SOC_MODE]; + +/* Boot with all domains ON */ +static bool stm32mp1_pm_dom[STM32MP1_PD_MAX_PM_DOMAIN] = { + [STM32MP1_PD_VSW] = false, + [STM32MP1_PD_CORE_RET] = false, + [STM32MP1_PD_CORE] = false +}; + +bool need_to_backup_cpu_context(unsigned int soc_mode) +{ + switch (soc_mode) { + case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR: + return true; + case STM32_PM_CSLEEP_RUN: + case STM32_PM_CSTOP_ALLOW_STOP: + case STM32_PM_CSTOP_ALLOW_LP_STOP: + case STM32_PM_CSTOP_ALLOW_LPLV_STOP: + case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF: + case STM32_PM_SHUTDOWN: + return false; + default: + EMSG("Invalid mode 0x%x", soc_mode); + panic(); + } +} + +bool need_to_backup_stop_context(unsigned int soc_mode) +{ + switch (soc_mode) { + case STM32_PM_CSTOP_ALLOW_STOP: + case STM32_PM_CSTOP_ALLOW_LP_STOP: + case STM32_PM_CSTOP_ALLOW_LPLV_STOP: + return true; + default: + return false; + } +} + +static bool get_pm_domain_state(uint8_t mode) +{ + bool res = true; + enum stm32mp1_pm_domain id = STM32MP1_PD_MAX_PM_DOMAIN; + + while (res && (id > mode)) { + id--; + res &= stm32mp1_pm_dom[id]; + } + + return res; +} + +int stm32mp1_set_pm_domain_state(enum stm32mp1_pm_domain domain, bool status) +{ + if (domain >= STM32MP1_PD_MAX_PM_DOMAIN) + return -1; + + stm32mp1_pm_dom[domain] = status; + + return 0; +} + +#ifdef CFG_DT +static int fdt_read_uint32_array(void *fdt, int node, const char *prop_name, + uint32_t *array, uint32_t count) +{ + const fdt32_t *cuint = NULL; + int len = 0; + uint32_t i = 0; + + cuint = fdt_getprop(fdt, node, prop_name, &len); + if (!cuint) + return -FDT_ERR_NOTFOUND; + + if ((uint32_t)len != (count * sizeof(uint32_t))) + return -FDT_ERR_BADLAYOUT; + + for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { + *array = fdt32_to_cpu(*cuint); + array++; + cuint++; + } + + return 0; +} + +static void save_supported_mode(void *fdt, int pwr_node) +{ + int len = 0; + uint32_t count = 0; + unsigned int i = 0; + uint32_t supported[ARRAY_SIZE(stm32mp1_supported_soc_modes)] = { }; + const void *prop = 0; + + prop = fdt_getprop(fdt, pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES, &len); + if (!prop) + panic(); + + count = (uint32_t)len / sizeof(uint32_t); + if (count > STM32_PM_MAX_SOC_MODE) + panic(); + + if (fdt_read_uint32_array(fdt, pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES, + &supported[0], count) < 0) + panic("PWR DT"); + + for (i = 0; i < count; i++) { + if (supported[i] >= STM32_PM_MAX_SOC_MODE) + panic("Invalid mode"); + + stm32mp1_supported_soc_modes[supported[i]] = true; + } +} +#endif + +static bool is_supported_mode(uint32_t soc_mode) +{ + assert(soc_mode < ARRAY_SIZE(stm32mp1_supported_soc_modes)); + return stm32mp1_supported_soc_modes[soc_mode] == 1; +} + +uint32_t stm32mp1_get_lp_soc_mode(uint32_t psci_mode) +{ + uint32_t mode = 0; + + if (psci_mode == PSCI_MODE_SYSTEM_OFF) + return system_off_mode; + + mode = deepest_suspend_mode; + + if ((mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) && + (!get_pm_domain_state(STM32MP1_PD_CORE_RET) || + !is_supported_mode(mode))) + mode = STM32_PM_CSTOP_ALLOW_LPLV_STOP; + + if ((mode == STM32_PM_CSTOP_ALLOW_LPLV_STOP) && + (!get_pm_domain_state(STM32MP1_PD_CORE) || + !is_supported_mode(mode))) + mode = STM32_PM_CSTOP_ALLOW_LP_STOP; + + if ((mode == STM32_PM_CSTOP_ALLOW_LP_STOP) && + !is_supported_mode(mode)) + mode = STM32_PM_CSTOP_ALLOW_STOP; + + if ((mode == STM32_PM_CSTOP_ALLOW_STOP) && + !is_supported_mode(mode)) + mode = STM32_PM_CSLEEP_RUN; + + return mode; +} + +int stm32mp1_set_lp_deepest_soc_mode(uint32_t psci_mode, uint32_t soc_mode) +{ + if (soc_mode >= STM32_PM_MAX_SOC_MODE) + return -1; + + if (psci_mode == PSCI_MODE_SYSTEM_SUSPEND) { + deepest_suspend_mode = soc_mode; + + if (!IS_ENABLED(CFG_STM32_CRYP) && + deepest_suspend_mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) + deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_LPLV_STOP; + } + + if (psci_mode == PSCI_MODE_SYSTEM_OFF) + system_off_mode = soc_mode; + + return 0; +} + +#ifdef CFG_DT +static int dt_get_pwr_node(void *fdt) +{ + return fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); +} + +static TEE_Result stm32mp1_init_lp_states(void) +{ + void *fdt = NULL; + int pwr_node = -1; + const fdt32_t *cuint = NULL; + + fdt = get_embedded_dt(); + if (fdt) + pwr_node = dt_get_pwr_node(fdt); + + if (pwr_node >= 0) + cuint = fdt_getprop(fdt, pwr_node, SYSTEM_OFF_MODE, NULL); + + if (!fdt || (pwr_node < 0) || !cuint) { + IMSG("No power configuration found in DT"); + return TEE_SUCCESS; + } + + system_off_mode = fdt32_to_cpu(*cuint); + + /* Initialize suspend support to the deepest possible mode */ + if (IS_ENABLED(CFG_STM32_CRYP)) + deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR; + else + deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_LPLV_STOP; + + save_supported_mode(fdt, pwr_node); + + DMSG("Power configuration: shutdown to %u, suspend to %u", + stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF), + stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND)); + + return TEE_SUCCESS; +} +#else +static TEE_Result stm32mp1_init_lp_states(void) +{ + if (IS_ENABLED(CFG_STM32_CRYP)) + deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR; + else + deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_LPLV_STOP; + + system_off_mode = STM32_PM_SHUTDOWN; + + DMSG("Power configuration: shutdown to %u, suspend to %u", + stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF), + stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND)); + + return TEE_SUCCESS; +} +#endif +service_init(stm32mp1_init_lp_states); diff --git a/core/arch/arm/plat-stm32mp1/pm/psci.c b/core/arch/arm/plat-stm32mp1/pm/psci.c index 9c472c796..65f583d2e 100644 --- a/core/arch/arm/plat-stm32mp1/pm/psci.c +++ b/core/arch/arm/plat-stm32mp1/pm/psci.c @@ -1,16 +1,23 @@ // SPDX-License-Identifier: BSD-2-Clause /* - * Copyright (c) 2017-2018, STMicroelectronics + * Copyright (c) 2017-2020, STMicroelectronics */ #include #include +#include #include +#include +#include +#include #include #include #include #include +#include +#include #include +#include #include #include #include @@ -20,10 +27,17 @@ #include #include #include +#include #include #include #include +#include +#include #include +#include + +#include "context.h" +#include "power.h" #define CONSOLE_FLUSH_DELAY_MS 10 @@ -57,10 +71,9 @@ int psci_affinity_info(uint32_t affinity, uint32_t lowest_affinity_level) DMSG("core %zu, state %u", pos, core_state[pos]); - if ((pos >= CFG_TEE_CORE_NB_CORE) || - (lowest_affinity_level > PSCI_AFFINITY_LEVEL_ON)) { + if (pos >= CFG_TEE_CORE_NB_CORE || + lowest_affinity_level > PSCI_AFFINITY_LEVEL_ON) return PSCI_RET_INVALID_PARAMETERS; - } switch (core_state[pos]) { case CORE_OFF: @@ -82,38 +95,33 @@ int psci_affinity_info(uint32_t affinity, uint32_t lowest_affinity_level) */ void stm32mp_register_online_cpu(void) { - assert(core_state[0] == CORE_OFF); + assert(core_state[0] == CORE_OFF || core_state[0] == CORE_RET); core_state[0] = CORE_ON; } #else -static void __noreturn stm32_pm_cpu_power_down_wfi(void) -{ - dcache_op_level1(DCACHE_OP_CLEAN); - - io_write32(stm32_rcc_base() + RCC_MP_GRSTCSETR, - RCC_MP_GRSTCSETR_MPUP1RST); - - dsb(); - isb(); - wfi(); - panic(); -} - void stm32mp_register_online_cpu(void) { size_t pos = get_core_pos(); uint32_t exceptions = lock_state_access(); if (pos == 0) { - assert(core_state[pos] == CORE_OFF); + assert((core_state[pos] == CORE_OFF) || + (core_state[pos] == CORE_RET)); } else { if (core_state[pos] != CORE_AWAKE) { core_state[pos] = CORE_OFF; unlock_state_access(exceptions); - stm32_pm_cpu_power_down_wfi(); + if (IS_ENABLED(CFG_PM)) + stm32_pm_cpu_power_down_wfi(); panic(); } - stm32_clock_disable(RTCAPB); + + /* Clear hold in pen flag */ + io_write32(stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER), + BOOT_API_A7_RESET_MAGIC_NUMBER); + + /* Balance BKPREG clock gating */ + clk_disable(RTCAPB); } core_state[pos] = CORE_ON; @@ -134,11 +142,16 @@ static void release_secondary_early_hpen(size_t __unused pos) raise_sgi0_as_secure(); udelay(20); + clk_enable(RTCAPB); + io_write32(stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS), TEE_LOAD_ADDR); io_write32(stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER), BOOT_API_A7_CORE1_MAGIC_NUMBER); + dsb_ishst(); + clk_disable(RTCAPB); + dsb_ishst(); itr_raise_sgi(GIC_SEC_SGI_0, TARGET_CPU1_GIC_MASK); } @@ -207,44 +220,188 @@ int psci_cpu_off(void) unlock_state_access(exceptions); /* Enable BKPREG access for the disabled CPU */ - stm32_clock_enable(RTCAPB); + clk_enable(RTCAPB); thread_mask_exceptions(THREAD_EXCP_ALL); - stm32_pm_cpu_power_down_wfi(); + if (IS_ENABLED(CFG_PM)) + stm32_pm_cpu_power_down_wfi(); panic(); } #endif -/* Override default psci_system_off() with platform specific sequence */ -void __noreturn psci_system_off(void) +#ifdef CFG_PM +static int enter_cstop_suspend(unsigned int soc_mode) { - DMSG("core %u", get_core_pos()); + int rc = 1; + + if (read_isr()) + return rc; + + stm32_enter_cstop(soc_mode); + + if (need_to_backup_cpu_context(soc_mode)) { + stm32_pm_cpu_power_down_wfi(); + } else { + stm32_pm_cpu_wfi(); + rc = 0; + } + + stm32_exit_cstop(); + + return rc; +} + +static int plat_suspend(uint32_t arg) +{ + unsigned int soc_mode = arg; + size_t pos = get_core_pos(); + int rc = 1; + + if (read_isr()) + return rc; + + /* No need to lock state access as CPU is alone when here */ + assert(core_state[pos] == CORE_ON); + core_state[pos] = CORE_RET; + + if (stm32mp_pm_save_context(soc_mode) == TEE_SUCCESS) + rc = enter_cstop_suspend(soc_mode); + + stm32mp_pm_restore_context(soc_mode); + stm32mp_pm_wipe_context(); + + assert(core_state[pos] == CORE_RET); + core_state[pos] = CORE_ON; + + return rc; +} + +static void plat_resume(uint32_t arg) +{ + unsigned int soc_mode = arg; + + stm32mp_register_online_cpu(); + + assert(core_state[get_core_pos()] == CORE_ON); + + stm32mp_pm_restore_context(soc_mode); +} - if (TRACE_LEVEL >= TRACE_DEBUG) { - console_flush(); - mdelay(CONSOLE_FLUSH_DELAY_MS); +static bool plat_can_suspend(void) +{ + size_t pos = get_core_pos(); + size_t n = 0; + uint32_t exceptions = 0; + bool rc = true; + + if (!IS_ENABLED(CFG_STM32_RNG)) + return false; + + if (CFG_TEE_CORE_NB_CORE == 1) + return true; + + exceptions = lock_state_access(); + + for (n = 0; n < ARRAY_SIZE(core_state); n++) { + if (n == pos) + continue; + + if (core_state[n] == CORE_AWAKE) { + /* State core as lost and proceed suspend */ + core_state[n] = CORE_OFF; + } + + if (core_state[n] != CORE_OFF) + rc = false; + } + + unlock_state_access(exceptions); + + return rc; +} + +/* Override default psci_system_suspend() with platform specific sequence */ +int psci_system_suspend(uintptr_t entry, uint32_t context_id __unused, + struct sm_nsec_ctx *nsec) +{ + int ret = PSCI_RET_INVALID_PARAMETERS; + uint32_t soc_mode = 0; + int __maybe_unused pos = get_core_pos(); + + DMSG("core %u", pos); + + if (!plat_can_suspend()) + return PSCI_RET_DENIED; + + soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND); + + switch (soc_mode) { + case STM32_PM_CSLEEP_RUN: + stm32_enter_csleep(); + nsec->mon_lr = (uint32_t)entry; + return PSCI_RET_SUCCESS; + case STM32_PM_SHUTDOWN: + stm32_enter_cstop_shutdown(soc_mode); + panic(); + default: + /* Others are suspended mode: at least some context to backup */ + break; } - if (stm32mp_with_pmic()) { - stm32mp_get_pmic(); - stpmic1_switch_off(); - udelay(100); + assert(cpu_mmu_enabled() && core_state[pos] == CORE_ON); + + if (need_to_backup_cpu_context(soc_mode)) { + if (!IS_ENABLED(CFG_STM32_CRYP)) + return PSCI_RET_DENIED; + + sm_save_unbanked_regs(&nsec->ub_regs); + /* + * sm_pm_cpu_suspend(arg, func) saves the CPU core context in TEE RAM + * then calls func(arg) to run the platform lower power sequence. + * + * If platform fails to suspend, sm_pm_cpu_suspend() returns with a + * non null return code. When sm_pm_cpu_suspend() returns 0 platform + * context must be restored. + */ + ret = sm_pm_cpu_suspend((uint32_t)soc_mode, plat_suspend); + if (ret == 0) { + plat_resume((uint32_t)soc_mode); + sm_restore_unbanked_regs(&nsec->ub_regs); + } + } else { + ret = plat_suspend((uint32_t)soc_mode); } - panic(); + if (ret == 0) { + nsec->mon_lr = (uint32_t)entry; + IMSG("Resumed"); + return PSCI_RET_SUCCESS; + } + + return PSCI_RET_INTERNAL_FAILURE; +} + +/* Override default psci_system_off() with platform specific sequence */ +void __noreturn psci_system_off(void) +{ + uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF); + + DMSG("core %u", get_core_pos()); + + stm32_enter_cstop_shutdown(soc_mode); } /* Override default psci_system_reset() with platform specific sequence */ void __noreturn psci_system_reset(void) { - vaddr_t rcc_base = stm32_rcc_base(); + uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF); DMSG("core %u", get_core_pos()); - io_write32(rcc_base + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); - udelay(100); - panic(); + stm32_enter_cstop_reset(soc_mode); } +#endif /*CFG_PM*/ + /* Override default psci_cpu_on() with platform supported features */ int psci_features(uint32_t psci_fid) @@ -261,6 +418,7 @@ int psci_features(uint32_t psci_fid) return PSCI_RET_SUCCESS; return PSCI_RET_NOT_SUPPORTED; case PSCI_SYSTEM_OFF: + case PSCI_SYSTEM_SUSPEND: if (stm32mp_with_pmic()) return PSCI_RET_SUCCESS; return PSCI_RET_NOT_SUPPORTED; diff --git a/core/arch/arm/plat-stm32mp1/pm/sub.mk b/core/arch/arm/plat-stm32mp1/pm/sub.mk index c8ae8f915..d652958e3 100644 --- a/core/arch/arm/plat-stm32mp1/pm/sub.mk +++ b/core/arch/arm/plat-stm32mp1/pm/sub.mk @@ -1 +1,7 @@ +asm-defines-y += context_asm_defines.c + +srcs-$(CFG_PM) += context.c +srcs-$(CFG_PM) += low_power.c +srcs-$(CFG_PM) += pm_helpers.S +srcs-$(CFG_PM) += power_config.c srcs-$(CFG_PSCI_ARM32) += psci.c diff --git a/core/arch/arm/plat-stm32mp1/remoteproc_pta.c b/core/arch/arm/plat-stm32mp1/remoteproc_pta.c new file mode 100644 index 000000000..27b0dfa07 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/remoteproc_pta.c @@ -0,0 +1,528 @@ + // SPDX-License-Identifier: BSD-2-Clause + /* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTA_NAME "remoteproc.pta" + +#define STM32_M4_FW_ID 0 + +/* Firmware states */ +enum rproc_load_state { + REMOTEPROC_OFF = 0, + REMOTEPROC_ON, +}; + +/* + * struct rproc_ta_etzpc_rams - memory protection strategy table + * @pa - Memory physical base address from current CPU space + * @size - Memory region byte size + * @etzpc_id - associated ETZPC identifier. + * @attr - memory access permission according to @etzpc_decprot_attributes + */ +struct rproc_ta_etzpc_rams { + paddr_t pa; + size_t size; + uint32_t etzpc_id; + enum etzpc_decprot_attributes attr; +}; + +/* + * struct rproc_ta_memory_region - Represent a remote processor memory mapping + * @pa - Memory physical base address from current CPU space + * @da - Memory physical base address from remote processor space + * @size - Memory region byte size + */ +struct rproc_ta_memory_region { + paddr_t pa; + paddr_t da; + size_t size; +}; + +static const struct rproc_ta_etzpc_rams rproc_ta_mp1_m4_rams[] = { + /* MCU SRAM 1*/ + { + .pa = MCUSRAM_BASE, + .size = 0x20000, + .etzpc_id = STM32MP1_ETZPC_SRAM1_ID, + .attr = ETZPC_DECPROT_MCU_ISOLATION, + }, + /* MCU SRAM 2*/ + { + .pa = MCUSRAM_BASE + 0x20000, + .size = 0x20000, + .etzpc_id = STM32MP1_ETZPC_SRAM2_ID, + .attr = ETZPC_DECPROT_MCU_ISOLATION, + }, + + /* MCU SRAM 3*/ + { + /* Used as shared memory between the NS and the coprocessor */ + .pa = MCUSRAM_BASE + 0x40000, + .size = 0x10000, + .etzpc_id = STM32MP1_ETZPC_SRAM3_ID, + .attr = ETZPC_DECPROT_NS_RW, + }, + /* MCU SRAM 4*/ + /* Not used reserved by NS for MDMA */ + { + .pa = MCUSRAM_BASE + 0x50000, + .size = 0x10000, + .etzpc_id = STM32MP1_ETZPC_SRAM4_ID, + .attr = ETZPC_DECPROT_NS_RW, + }, + + /* MCU RETRAM */ + { + .pa = RETRAM_BASE, + .size = RETRAM_SIZE, + .etzpc_id = STM32MP1_ETZPC_RETRAM_ID, + .attr = ETZPC_DECPROT_MCU_ISOLATION, + }, +}; + +static const struct rproc_ta_memory_region rproc_ta_mp1_m4_mems[] = { + /* MCU SRAM */ + { .pa = MCUSRAM_BASE, .da = 0x10000000, .size = MCUSRAM_SIZE }, + /* Alias of the MCU SRAM */ + { .pa = MCUSRAM_BASE, .da = 0x30000000, .size = MCUSRAM_SIZE }, + /* RETRAM */ + { .pa = RETRAM_BASE, .da = 0x00000000, .size = RETRAM_SIZE }, +}; + +static enum rproc_load_state rproc_ta_state; + +static TEE_Result rproc_pta_capabilities(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_NONE); + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + /* Support only ELF format */ + params[1].value.a = PTA_REMOTEPROC_ELF_FMT; + + /* + * Due to stm32mp1 pager, secure memory is too expensive. Support hash + * protected image only, so that firmware image can be loaded from + * non-secure memory. + */ + params[2].value.a = PTA_REMOTEPROC_FW_WITH_HASH_TABLE; + + return TEE_SUCCESS; +} + +static TEE_Result da_to_pa(paddr_t da, size_t size, paddr_t *pa) +{ + const struct rproc_ta_memory_region *mems = rproc_ta_mp1_m4_mems; + size_t i = 0; + + DMSG("da addr: %#"PRIxPA" size: %zu", da, size); + + for (i = 0; i < ARRAY_SIZE(rproc_ta_mp1_m4_mems); i++) { + if (da >= mems[i].da && + (da + size) <= (mems[i].da + mems[i].size)) { + *pa = da - mems[i].da + mems[i].pa; + DMSG("da %#"PRIxPA" to pa %#"PRIxPA, da, *pa); + + return TEE_SUCCESS; + } + } + + return TEE_ERROR_ACCESS_DENIED; +} + +static TEE_Result rproc_pta_load_segment(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT); + TEE_Result res = TEE_ERROR_GENERIC; + paddr_t pa = 0; + uint8_t *dst = 0; + uint8_t *src = params[1].memref.buffer; + size_t size = params[1].memref.size; + uint8_t *hash = params[3].memref.buffer; + paddr_t da = (paddr_t)reg_pair_to_64(params[2].value.b, + params[2].value.a); + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + if (!hash || params[3].memref.size != TEE_SHA256_HASH_SIZE) + return TEE_ERROR_BAD_PARAMETERS; + + /* Only STM32_M4_FW_ID supported */ + if (params[0].value.a != STM32_M4_FW_ID) { + EMSG("Unsupported firmware ID %#"PRIx32, params[0].value.a); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (rproc_ta_state != REMOTEPROC_OFF) + return TEE_ERROR_BAD_STATE; + + /* Get the physical address in A7 mapping */ + res = da_to_pa(da, size, &pa); + if (res) + return res; + + /* Get the associated va */ + dst = (void *)core_mmu_get_va(pa, MEM_AREA_IO_SEC); + + /* Copy the segment to the remote processor memory*/ + memcpy(dst, src, size); + + /* Verify that loaded segment is valid */ + res = hash_sha256_check(hash, dst, size); + if (res) + memset(dst, 0, size); + + return res; +} + +static TEE_Result rproc_pta_set_memory(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT); + TEE_Result res = TEE_ERROR_GENERIC; + paddr_t pa = 0; + vaddr_t dst = 0; + paddr_t da = params[1].value.a; + size_t size = params[2].value.a; + char value = (char)params[3].value.a; + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + /* Only STM32_M4_FW_ID supported */ + if (params[0].value.a != STM32_M4_FW_ID) { + EMSG("Unsupported firmware ID %#"PRIx32, params[0].value.a); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (rproc_ta_state != REMOTEPROC_OFF) + return TEE_ERROR_BAD_STATE; + + /* Get the physical address in CPU mapping */ + res = da_to_pa(da, size, &pa); + if (res) + return res; + + dst = core_mmu_get_va(pa, MEM_AREA_IO_SEC); + + memset((void *)dst, value, size); + + return TEE_SUCCESS; +} + +static TEE_Result rproc_pta_da_to_pa(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT); + TEE_Result res = TEE_ERROR_GENERIC; + paddr_t da = params[1].value.a; + size_t size = params[2].value.a; + paddr_t pa = 0; + + DMSG("Conversion for address %#"PRIxPA" size %zu", da, size); + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + /* Only STM32_M4_FW_ID supported */ + if (params[0].value.a != STM32_M4_FW_ID) { + EMSG("Unsupported firmware ID %#"PRIx32, params[0].value.a); + return TEE_ERROR_NOT_SUPPORTED; + } + + /* Target address is expected 32bit, ensure 32bit MSB are zero */ + if (params[1].value.b || params[2].value.b) + return TEE_ERROR_BAD_PARAMETERS; + + res = da_to_pa(da, size, &pa); + if (res) + return res; + + reg_pair_from_64((uint64_t)pa, ¶ms[3].value.b, ¶ms[3].value.a); + + return TEE_SUCCESS; +} + +static void rproc_pta_mem_protect(bool secure_access) +{ + unsigned int i = 0; + const struct rproc_ta_etzpc_rams *ram = NULL; + + /* + * MCU RAM banks access permissions for MCU memories depending on + * rproc_ta_mp1_m4_rams[]. + * If memory bank is declared as MCU isolated: + * if secure_access then set to secure world read/write permission + * else set to MCU isolated + * else apply memory permission as defined in rproc_ta_mp1_m4_rams[]. + */ + for (i = 0; i < ARRAY_SIZE(rproc_ta_mp1_m4_rams); i++) { + enum etzpc_decprot_attributes attr = ETZPC_DECPROT_MAX; + + ram = &rproc_ta_mp1_m4_rams[i]; + attr = ram->attr; + + if (secure_access && attr == ETZPC_DECPROT_MCU_ISOLATION) + attr = ETZPC_DECPROT_S_RW; + + etzpc_configure_decprot(ram->etzpc_id, attr); + } +} + +static TEE_Result rproc_pta_start(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + vaddr_t rcc_base = stm32_rcc_base(); + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + /* Only STM32_M4_FW_ID supported */ + if (params[0].value.a != STM32_M4_FW_ID) { + EMSG("Unsupported firmware ID %#"PRIx32, params[0].value.a); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (rproc_ta_state != REMOTEPROC_OFF) + return TEE_ERROR_BAD_STATE; + + clk_enable(CK_MCU); + + /* Configure the Cortex-M4 RAMs as expected to run the firmware */ + rproc_pta_mem_protect(false); + + /* + * The firmware is started by deasserting the hold boot and + * asserting back to avoid auto restart on a crash. + * No need to release the MCU reset as it is automatically released by + * the hardware. + */ + io_setbits32(rcc_base + RCC_MP_GCR, RCC_MP_GCR_BOOT_MCU); + io_clrbits32(rcc_base + RCC_MP_GCR, RCC_MP_GCR_BOOT_MCU); + + rproc_ta_state = REMOTEPROC_ON; + + return TEE_SUCCESS; +} + +static TEE_Result rproc_pta_stop(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + const struct rproc_ta_etzpc_rams *ram = NULL; + vaddr_t rcc_base = stm32_rcc_base(); + unsigned int i = 0; + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + /* Only STM32_M4_FW_ID supported */ + if (params[0].value.a != STM32_M4_FW_ID) { + EMSG("Unsupported firmware ID %#"PRIx32, params[0].value.a); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (rproc_ta_state != REMOTEPROC_ON) + return TEE_ERROR_BAD_STATE; + + /* The firmware is stopped (reset with holdboot is active) */ + io_clrbits32(rcc_base + RCC_MP_GCR, RCC_MP_GCR_BOOT_MCU); + + stm32_reset_set(MCU_R); + + clk_disable(CK_MCU); + + /* + * Cortex-M4 memories are cleaned and access rights restored for the + * secure context. + */ + rproc_pta_mem_protect(true); + for (i = 0; i < ARRAY_SIZE(rproc_ta_mp1_m4_rams); i++) { + ram = &rproc_ta_mp1_m4_rams[i]; + if (ram->attr == ETZPC_DECPROT_MCU_ISOLATION) { + memset((void *)core_mmu_get_va(ram->pa, + MEM_AREA_IO_SEC), + 0, ram->size); + } + } + rproc_ta_state = REMOTEPROC_OFF; + + return TEE_SUCCESS; +} + +static TEE_Result rproc_pta_verify_rsa_signature(TEE_Param *hash, + TEE_Param *sig, uint32_t algo) +{ + struct rsa_public_key key = { }; + TEE_Result res = TEE_ERROR_GENERIC; + uint32_t e = TEE_U32_TO_BIG_ENDIAN(rproc_pub_key_exponent); + size_t hash_size = (size_t)hash->memref.size; + size_t sig_size = (size_t)sig->memref.size; + + res = crypto_acipher_alloc_rsa_public_key(&key, sig_size); + if (res) + return TEE_ERROR_SECURITY; + + res = crypto_bignum_bin2bn((uint8_t *)&e, sizeof(e), key.e); + if (res) + goto out; + + res = crypto_bignum_bin2bn(rproc_pub_key_modulus, + rproc_pub_key_modulus_size, key.n); + if (res) + goto out; + + res = crypto_acipher_rsassa_verify(algo, &key, hash_size, + hash->memref.buffer, hash_size, + sig->memref.buffer, sig_size); + +out: + crypto_acipher_free_rsa_public_key(&key); + + return res; +} + +static TEE_Result rproc_pta_verify_digest(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + struct rproc_pta_key_info *keyinfo = NULL; + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT); + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + /* Only STM32_M4_FW_ID supported */ + if (params[0].value.a != STM32_M4_FW_ID) { + EMSG("Unsupported firmware ID %#"PRIx32, params[0].value.a); + return TEE_ERROR_NOT_SUPPORTED; + } + + if (rproc_ta_state != REMOTEPROC_OFF) + return TEE_ERROR_BAD_STATE; + + keyinfo = params[1].memref.buffer; + + if (!keyinfo || + RPROC_PTA_GET_KEYINFO_SIZE(keyinfo) != params[1].memref.size) + return TEE_ERROR_BAD_PARAMETERS; + + if (keyinfo->algo != TEE_ALG_RSASSA_PKCS1_V1_5_SHA256) + return TEE_ERROR_NOT_SUPPORTED; + + return rproc_pta_verify_rsa_signature(¶ms[2], ¶ms[3], + keyinfo->algo); +} + +static TEE_Result rproc_pta_invoke_command(void *pSessionContext __unused, + uint32_t cmd_id, + uint32_t param_types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + switch (cmd_id) { + case PTA_REMOTEPROC_HW_CAPABILITIES: + return rproc_pta_capabilities(param_types, params); + case PTA_REMOTEPROC_LOAD_SEGMENT_SHA256: + return rproc_pta_load_segment(param_types, params); + case PTA_REMOTEPROC_SET_MEMORY: + return rproc_pta_set_memory(param_types, params); + case PTA_REMOTEPROC_FIRMWARE_START: + return rproc_pta_start(param_types, params); + case PTA_REMOTEPROC_FIRMWARE_STOP: + return rproc_pta_stop(param_types, params); + case PTA_REMOTEPROC_FIRMWARE_DA_TO_PA: + return rproc_pta_da_to_pa(param_types, params); + case PTA_REMOTEPROC_VERIFY_DIGEST: + return rproc_pta_verify_digest(param_types, params); + default: + break; + } + + return TEE_ERROR_NOT_IMPLEMENTED; +} + +/* + * Trusted Application entry points + */ +static TEE_Result + rproc_pta_open_session(uint32_t param_types __unused, + TEE_Param params[TEE_NUM_PARAMS] __unused, + void **sess_ctx __unused) +{ + struct tee_ta_session *s = tee_ta_get_calling_session(); + + /* Check that we're called from a user TA */ + if (!s) + return TEE_ERROR_ACCESS_DENIED; + + if (!is_user_ta_ctx(s->ctx)) + return TEE_ERROR_ACCESS_DENIED; + + return TEE_SUCCESS; +} + +static TEE_Result rproc_pta_init(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + + /* Configure the Cortex-M4 rams access right for secure context only */ + rproc_pta_mem_protect(true); + + /* Initialise the context */ + rproc_ta_state = REMOTEPROC_OFF; + + /* Ensure that the MCU is HOLD */ + io_clrbits32(rcc_base + RCC_MP_GCR, RCC_MP_GCR_BOOT_MCU); + stm32_reset_set(MCU_R); + + return TEE_SUCCESS; +} +service_init_late(rproc_pta_init); + +pseudo_ta_register(.uuid = PTA_REMOTEPROC_UUID, .name = PTA_NAME, + .flags = PTA_DEFAULT_FLAGS, + .invoke_command_entry_point = rproc_pta_invoke_command, + .open_session_entry_point = rproc_pta_open_session); diff --git a/core/arch/arm/plat-stm32mp1/reset.S b/core/arch/arm/plat-stm32mp1/reset.S index 8a1ab6494..0a11d915a 100644 --- a/core/arch/arm/plat-stm32mp1/reset.S +++ b/core/arch/arm/plat-stm32mp1/reset.S @@ -3,7 +3,7 @@ * Copyright (c) 2018, STMicroelectronics */ -#include +#include #include #include @@ -21,7 +21,33 @@ FUNC plat_cpu_reset_early , : mov_imm r1, STM32MP1_NSACR_PRESERVE_MASK and r0, r0, r1 write_nsacr r0 + isb + + read_actlr r0 + orr r0, r0, #ACTLR_SMP + write_actlr r0 + + /* + * Always reset CNTVOFF for the dear non secure world. + * This operation requires being in Monitor mode and + * non secure state. + */ + mrs r1, cpsr + cps #CPSR_MODE_MON + isb + + read_scr r2 + orr r0, r2, #SCR_NS + write_scr r0 + isb + + mov r0, #0 + write_cntvoff r0, r0 + write_scr r2 isb + msr cpsr, r1 + isb + bx lr END_FUNC plat_cpu_reset_early diff --git a/core/arch/arm/plat-stm32mp1/rproc_pub_key.h b/core/arch/arm/plat-stm32mp1/rproc_pub_key.h new file mode 100644 index 000000000..9b1db4271 --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/rproc_pub_key.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef RPROC_PUB_KEY_H +#define RPROC_PUB_KEY_H + +#include + +extern const uint32_t rproc_pub_key_exponent; +extern const uint8_t rproc_pub_key_modulus[]; +extern const size_t rproc_pub_key_modulus_size; + +#endif /*RPROC_PUB_KEY_H*/ + diff --git a/core/arch/arm/plat-stm32mp1/scmi_server.c b/core/arch/arm/plat-stm32mp1/scmi_server.c index dce8c169e..169e69ee7 100644 --- a/core/arch/arm/plat-stm32mp1/scmi_server.c +++ b/core/arch/arm/plat-stm32mp1/scmi_server.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-2-Clause /* - * Copyright (c) 2019, STMicroelectronics + * Copyright (c) 2019-2020, STMicroelectronics */ #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -312,9 +314,22 @@ const char *plat_scmi_clock_get_name(unsigned int agent_id, return clock->name; } -int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id, - size_t start_index, unsigned long *array, - size_t *nb_elts) +int32_t plat_scmi_clock_rates_array(unsigned int agent_id __unused, + unsigned int scmi_id __unused, + size_t start_index __unused, + unsigned long *array __unused, + size_t *nb_elts __unused) +{ + /* + * Explicitly do not expose clock rates by array since not + * fully supported by Linux kernel as of v5.4.24. + */ + return SCMI_NOT_SUPPORTED; +} + +int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id, + unsigned int scmi_id, + unsigned long *array) { struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); @@ -324,16 +339,48 @@ int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id, if (!stm32mp_nsec_can_access_clock(clock->clock_id)) return SCMI_DENIED; - /* Exposed clocks are currently fixed rate clocks */ - if (start_index) - return SCMI_INVALID_PARAMETERS; + switch (scmi_id) { + case CK_SCMI0_MPU: + /* + * Pretend we support all rates for MPU clock, + * CLOCK_RATE_SET will reject unsupported rates. + */ + array[0] = 0U; + array[1] = UINT32_MAX; + array[2] = 1U; + break; + default: + array[0] = clk_get_rate(clock->clock_id); + array[1] = array[0]; + array[2] = 0U; + break; + } - if (!array) - *nb_elts = 1; - else if (*nb_elts == 1) - *array = stm32_clock_get_rate(clock->clock_id); - else - return SCMI_GENERIC_ERROR; + return SCMI_SUCCESS; +} + +int32_t plat_scmi_clock_set_rate(unsigned int agent_id, unsigned int scmi_id, + unsigned long rate) +{ + struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id); + int ret = SCMI_DENIED; + + if (!clock) + return SCMI_NOT_FOUND; + if (!stm32mp_nsec_can_access_clock(clock->clock_id)) + return SCMI_DENIED; + + switch (scmi_id) { + case CK_SCMI0_MPU: + ret = stm32mp1_set_opp_khz(rate / 1000); + if (ret) + return SCMI_INVALID_PARAMETERS; + break; + default: + if (rate != clk_get_rate(clock->clock_id)) + return SCMI_INVALID_PARAMETERS; + break; + } return SCMI_SUCCESS; } @@ -346,7 +393,7 @@ unsigned long plat_scmi_clock_get_rate(unsigned int agent_id, if (!clock || !stm32mp_nsec_can_access_clock(clock->clock_id)) return 0; - return stm32_clock_get_rate(clock->clock_id); + return clk_get_rate(clock->clock_id); } int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id) @@ -373,13 +420,13 @@ int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id, if (enable_not_disable) { if (!clock->enabled) { DMSG("SCMI clock %u enable", scmi_id); - stm32_clock_enable(clock->clock_id); + clk_enable(clock->clock_id); clock->enabled = true; } } else { if (clock->enabled) { DMSG("SCMI clock %u disable", scmi_id); - stm32_clock_disable(clock->clock_id); + clk_disable(clock->clock_id); clock->enabled = false; } } @@ -483,6 +530,19 @@ int32_t plat_scmi_rd_set_state(unsigned int agent_id, unsigned int scmi_id, return SCMI_SUCCESS; } +static TEE_Result stm32_scmi_pm(enum pm_op op, unsigned int pm_hint __unused, + const struct pm_callback_handle *hdl __unused) +{ + size_t i = 0; + + if (op == PM_OP_RESUME) + for (i = 0; i < ARRAY_SIZE(scmi_channel); i++) + scmi_smt_init_agent_channel(&scmi_channel[i]); + + return TEE_SUCCESS; +} +DECLARE_KEEP_PAGER(stm32_scmi_pm); + /* * Platform SCMI voltage domains */ @@ -810,6 +870,8 @@ static TEE_Result stm32mp1_init_scmi_server(void) size_t i = 0; size_t j = 0; + register_pm_driver_cb(stm32_scmi_pm, NULL); + for (i = 0; i < ARRAY_SIZE(scmi_channel); i++) { struct scmi_msg_channel *chan = &scmi_channel[i]; @@ -834,7 +896,7 @@ static TEE_Result stm32mp1_init_scmi_server(void) /* Sync SCMI clocks with their targeted initial state */ if (clk->enabled && stm32mp_nsec_can_access_clock(clk->clock_id)) - stm32_clock_enable(clk->clock_id); + clk_enable(clk->clock_id); } for (j = 0; j < res->rd_count; j++) { diff --git a/core/arch/arm/plat-stm32mp1/shared_resources.c b/core/arch/arm/plat-stm32mp1/shared_resources.c index 3d1609353..7ad3d7b9c 100644 --- a/core/arch/arm/plat-stm32mp1/shared_resources.c +++ b/core/arch/arm/plat-stm32mp1/shared_resources.c @@ -1,14 +1,14 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) 2017-2019, STMicroelectronics + * Copyright (c) 2017-2020, STMicroelectronics */ #include #include -#include #include #include #include +#include #include #include #include @@ -147,6 +147,9 @@ static const char __maybe_unused *shres2str_id_tbl[STM32MP1_SHRES_COUNT] = { static __maybe_unused const char *shres2str_id(enum stm32mp_shres id) { + if (id >= ARRAY_SIZE(shres2str_id_tbl)) + panic("Invalid shared resource ID"); + return shres2str_id_tbl[id]; } @@ -407,6 +410,91 @@ void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin) } } +#ifdef CFG_STM32_ETZPC +struct shres2decprot { + enum stm32mp_shres shres_id; + unsigned int decprot_id; +}; + +#define SHRES2DECPROT(shres, decprot) { \ + .shres_id = shres, \ + .decprot_id = decprot, \ + } + +static const struct shres2decprot shres2decprot_tbl[] = { + SHRES2DECPROT(STM32MP1_SHRES_IWDG1, STM32MP1_ETZPC_IWDG1_ID), + SHRES2DECPROT(STM32MP1_SHRES_USART1, STM32MP1_ETZPC_USART1_ID), + SHRES2DECPROT(STM32MP1_SHRES_SPI6, STM32MP1_ETZPC_SPI6_ID), + SHRES2DECPROT(STM32MP1_SHRES_I2C4, STM32MP1_ETZPC_I2C4_ID), + SHRES2DECPROT(STM32MP1_SHRES_RNG1, STM32MP1_ETZPC_RNG1_ID), + SHRES2DECPROT(STM32MP1_SHRES_HASH1, STM32MP1_ETZPC_HASH1_ID), + SHRES2DECPROT(STM32MP1_SHRES_CRYP1, STM32MP1_ETZPC_CRYP1_ID), + SHRES2DECPROT(STM32MP1_SHRES_I2C6, STM32MP1_ETZPC_I2C6_ID), +}; + +static enum stm32mp_shres decprot2shres(unsigned int decprot_id) +{ + size_t i = 0; + + for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) + if (shres2decprot_tbl[i].decprot_id == decprot_id) + return shres2decprot_tbl[i].shres_id; + + DMSG("No shared resource for DECPROT ID %u", decprot_id); + return STM32MP1_SHRES_COUNT; +} + +void stm32mp_register_etzpc_decprot(unsigned int id, + enum etzpc_decprot_attributes attr) +{ + enum shres_state state = SHRES_SECURE; + bool write_secure = false; + unsigned int id_shres = STM32MP1_SHRES_COUNT; + + switch (attr) { + case ETZPC_DECPROT_S_RW: + state = SHRES_SECURE; + break; + case ETZPC_DECPROT_NS_R_S_W: + case ETZPC_DECPROT_MCU_ISOLATION: + case ETZPC_DECPROT_NS_RW: + state = SHRES_NON_SECURE; + break; + default: + panic(); + } + + write_secure = attr == ETZPC_DECPROT_NS_R_S_W || + attr == ETZPC_DECPROT_S_RW; + + switch (id) { + case STM32MP1_ETZPC_STGENC_ID: + case STM32MP1_ETZPC_BKPSRAM_ID: + if (state != SHRES_SECURE) + panic("ETZPC: STGEN & BKSRAM should be secure"); + break; + case STM32MP1_ETZPC_DDRCTRL_ID: + case STM32MP1_ETZPC_DDRPHYC_ID: + /* We assume these must always be write-only to secure world */ + if (!write_secure) + panic("ETZPC: DDRCTRL & DDRPHY should be write secure"); + break; + default: + id_shres = decprot2shres(id); + if (id_shres >= STM32MP1_SHRES_COUNT) { + if (write_secure) { + DMSG("ETZPC: cannot secure DECPROT %s", + shres2str_id(id_shres)); + panic(); + } + } else { + register_periph(id_shres, state); + } + break; + } +} +#endif /*CFG_STM32_ETZPC*/ + static void lock_registering(void) { registering_locked = true; @@ -614,13 +702,39 @@ static void config_lock_decprot(uint32_t decprot_id, etzpc_lock_decprot(decprot_id); } +static bool decprot_is_write_secure(uint32_t decprot_id) +{ + enum etzpc_decprot_attributes attr = etzpc_get_decprot(decprot_id); + + return attr == ETZPC_DECPROT_S_RW || + attr == ETZPC_DECPROT_NS_R_S_W; +} + +static bool decprot_is_secure(uint32_t decprot_id) +{ + enum etzpc_decprot_attributes attr = etzpc_get_decprot(decprot_id); + + return attr == ETZPC_DECPROT_S_RW; +} + static void set_etzpc_secure_configuration(void) { /* Some peripherals shall be secure */ - config_lock_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW); - config_lock_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW); - config_lock_decprot(STM32MP1_ETZPC_DDRCTRL_ID, ETZPC_DECPROT_S_RW); - config_lock_decprot(STM32MP1_ETZPC_DDRPHYC_ID, ETZPC_DECPROT_S_RW); + if (!decprot_is_secure(STM32MP1_ETZPC_STGENC_ID)) + config_lock_decprot(STM32MP1_ETZPC_STGENC_ID, + ETZPC_DECPROT_S_RW); + + if (!decprot_is_secure(STM32MP1_ETZPC_BKPSRAM_ID)) + config_lock_decprot(STM32MP1_ETZPC_BKPSRAM_ID, + ETZPC_DECPROT_S_RW); + + if (!decprot_is_write_secure(STM32MP1_ETZPC_DDRCTRL_ID)) + config_lock_decprot(STM32MP1_ETZPC_DDRCTRL_ID, + ETZPC_DECPROT_NS_R_S_W); + + if (!decprot_is_write_secure(STM32MP1_ETZPC_DDRPHYC_ID)) + config_lock_decprot(STM32MP1_ETZPC_DDRPHYC_ID, + ETZPC_DECPROT_NS_R_S_W); /* Configure ETZPC with peripheral registering */ config_lock_decprot(STM32MP1_ETZPC_IWDG1_ID, @@ -651,27 +765,35 @@ static void check_rcc_secure_configuration(void) { bool secure = stm32_rcc_is_secure(); bool mckprot = stm32_rcc_is_mckprot(); + bool need_secure = false; + bool need_mckprot = false; enum stm32mp_shres id = STM32MP1_SHRES_COUNT; - bool have_error = false; - if (stm32mp_is_closed_device() && !secure) - panic(); + if (stm32mp_is_closed_device() && !secure) { + DMSG("stm32mp1: closed device mandates OP-TEE to secure RCC"); + need_secure = true; + } for (id = 0; id < STM32MP1_SHRES_COUNT; id++) { if (shres_state[id] != SHRES_SECURE) continue; - if ((mckprot_resource(id) && !mckprot) || !secure) { - EMSG("RCC %s MCKPROT %s and %s (%u) secure", - secure ? "secure" : "non-secure", - mckprot ? "set" : "not set", - shres2str_id(id), id); - have_error = true; - } + need_secure = true; + if (mckprot_resource(id)) + need_mckprot = true; + + if ((mckprot_resource(id) && !mckprot) || !secure) + EMSG("Error: RCC TZEN=%u MCKPROT=%u while %s is secure", + secure, mckprot, shres2str_id(id)); } - if (have_error) + DMSG("RCC/PWR secure hardening: TZEN %sable, MCKPROT %sable", + secure ? "en" : "dis", mckprot ? "en" : "dis"); + + if (need_secure && !secure) panic(); + + stm32mp1_clk_mcuss_protect(need_mckprot); } static void set_gpio_secure_configuration(void) diff --git a/core/arch/arm/plat-stm32mp1/stm32_util.h b/core/arch/arm/plat-stm32mp1/stm32_util.h index 6e4ac7499..efb364998 100644 --- a/core/arch/arm/plat-stm32mp1/stm32_util.h +++ b/core/arch/arm/plat-stm32mp1/stm32_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause */ /* - * Copyright (c) 2018-2019, STMicroelectronics + * Copyright (c) 2018-2020, STMicroelectronics */ #ifndef __STM32_UTIL_H__ @@ -9,11 +9,23 @@ #include #include #include +#include #include #include +/* SoC versioning and device ID */ +TEE_Result stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version); +TEE_Result stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id); + +/* OPP service */ +bool stm32mp_supports_cpu_opp(uint32_t opp_id); + /* Backup registers and RAM utils */ vaddr_t stm32mp_bkpreg(unsigned int idx); +vaddr_t stm32mp_bkpsram_base(void); + +/* Platform util for the STGEN driver */ +vaddr_t stm32mp_stgen_base(void); /* * SYSCFG IO compensation. @@ -25,6 +37,7 @@ void stm32mp_syscfg_disable_io_compensation(void); /* Platform util for the GIC */ vaddr_t get_gicc_base(void); vaddr_t get_gicd_base(void); +void stm32mp_gic_set_end_of_interrupt(uint32_t it); /* * Platform util functions for the GPIO driver @@ -43,6 +56,18 @@ vaddr_t stm32_get_gpio_bank_base(unsigned int bank); unsigned int stm32_get_gpio_bank_offset(unsigned int bank); unsigned int stm32_get_gpio_bank_clock(unsigned int bank); +/* + * Platform util for the IWDG driver + */ + +/* Get IWDG_* enable flags mask from watchdog configuration read from fuses */ +unsigned long stm32_get_iwdg_otp_config(vaddr_t pbase); + +/* Conversion between IWDG instance IDs and hardware resources */ +size_t stm32mp_iwdg_instance2irq(unsigned int instance); +unsigned int stm32mp_iwdg_irq2instance(size_t irq); +unsigned int stm32mp_iwdg_iomem2instance(vaddr_t pbase); + /* Platform util for PMIC support */ bool stm32mp_with_pmic(void); @@ -62,15 +87,6 @@ static inline void stm32mp_register_online_cpu(void) uint32_t may_spin_lock(unsigned int *lock); void may_spin_unlock(unsigned int *lock, uint32_t exceptions); -/* - * Util for clock gating and to get clock rate for stm32 and platform drivers - * @id: Target clock ID, ID used in clock DT bindings - */ -void stm32_clock_enable(unsigned long id); -void stm32_clock_disable(unsigned long id); -unsigned long stm32_clock_get_rate(unsigned long id); -bool stm32_clock_is_enabled(unsigned long id); - /* Return true if @clock_id is shared by secure and non-secure worlds */ bool stm32mp_nsec_can_access_clock(unsigned long clock_id); @@ -84,6 +100,22 @@ static inline bool stm32mp_nsec_can_access_pmic_regu(const char *name __unused) } #endif +/* PM sequences specific to SoC STOP mode support */ +void stm32mp1_clk_save_context_for_stop(void); +void stm32mp1_clk_restore_context_for_stop(void); + +/* Protect the MCU clock subsytem */ +void stm32mp1_clk_mcuss_protect(bool enable); + +/* + * Util for PLL1 settings management based on DT OPP table content. + */ +int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage); +void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data, size_t size); +bool stm32mp1_clk_pll1_settings_are_valid(void); +int stm32mp1_set_opp_khz(uint32_t freq_khz); +int stm32mp1_round_opp_khz(uint32_t *freq_khz); + /* * Util for reset signal assertion/desassertion for stm32 and platform drivers * @id: Target peripheral ID, ID used in reset DT bindings @@ -123,6 +155,27 @@ struct stm32_bsec_static_cfg { void stm32mp_get_bsec_static_cfg(struct stm32_bsec_static_cfg *cfg); +/* Reset function for early watchdog management */ +void stm32mp_platform_reset(int cpu); + +/* Clock calibration. Returns 0 on success */ +#ifdef CFG_STM32_CLKCALIB +int stm32mp_start_clock_calib(unsigned int clock_id); +#else +static inline int stm32mp_start_clock_calib(unsigned int clock_id __unused) +{ + return 1; +} +#endif + +/* Platform util for the RTC driver */ +bool stm32_rtc_get_read_twice(void); + +/* Platform util for the ETZPC driver */ + +/* Convert a ETZPC mode from DT binding to ETZPC DECPROT configuration */ +enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode); + /* * Return true if platform is in closed_device mode */ @@ -294,4 +347,8 @@ bool stm32mp_gpio_bank_is_non_secure(unsigned int bank); /* Register parent clocks of @clock (ID used in clock DT bindings) as secure */ void stm32mp_register_clock_parents_secure(unsigned long clock_id); +/* Register a resource identified by a ETZPC DECPROT identifier */ +void stm32mp_register_etzpc_decprot(unsigned int id, + enum etzpc_decprot_attributes attr); + #endif /*__STM32_UTIL_H__*/ diff --git a/core/arch/arm/plat-stm32mp1/stm32mp_pm.h b/core/arch/arm/plat-stm32mp1/stm32mp_pm.h new file mode 100644 index 000000000..4265db9dd --- /dev/null +++ b/core/arch/arm/plat-stm32mp1/stm32mp_pm.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2017-2018, STMicroelectronics + */ +#ifndef __STM32MP_PM_H__ +#define __STM32MP_PM_H__ + +#define PSCI_MODE_SYSTEM_SUSPEND 0 +#define PSCI_MODE_SYSTEM_OFF 1 + +enum stm32mp1_pm_domain { + STM32MP1_PD_VSW, + STM32MP1_PD_CORE_RET, + STM32MP1_PD_CORE, + STM32MP1_PD_MAX_PM_DOMAIN +}; + +void __noreturn stm32_cores_reset(void); + +#endif /*__STM32MP_PM_H__*/ + diff --git a/core/arch/arm/plat-stm32mp1/sub.mk b/core/arch/arm/plat-stm32mp1/sub.mk index 69df1ced5..ae2041741 100644 --- a/core/arch/arm/plat-stm32mp1/sub.mk +++ b/core/arch/arm/plat-stm32mp1/sub.mk @@ -6,6 +6,15 @@ srcs-$(CFG_STM32_RNG) += rng_seed.c srcs-y += scmi_server.c srcs-y += shared_resources.c srcs-$(CFG_TZC400) += plat_tzc400.c +srcs-$(CFG_RPROC_PTA) += remoteproc_pta.c + +ifeq ($(CFG_RPROC_PTA),y) +gensrcs-y += rproc_pub_key +produce-rproc_pub_key = rproc_pub_key.c +depends-rproc_pub_key = $(CFG_RPROC_SIGN_KEY) scripts/pem_to_pub_c.py +recipe-rproc_pub_key = $(PYTHON3) scripts/pem_to_pub_c.py --prefix rproc_pub_key \ + --key $(CFG_RPROC_SIGN_KEY) --out $(sub-dir-out)/rproc_pub_key.c +endif subdirs-y += drivers subdirs-y += nsec-service diff --git a/core/arch/arm/sm/pm_a32.S b/core/arch/arm/sm/pm_a32.S index a927b1e77..3e0080af4 100644 --- a/core/arch/arm/sm/pm_a32.S +++ b/core/arch/arm/sm/pm_a32.S @@ -65,25 +65,30 @@ a9_suspend: a7_suspend: read_fcseidr r4 read_tpidruro r5 - stmia r0!, {r4 - r5} - read_dacr r4 + read_dacr r6 + stmia r0!, {r4 - r6} #ifdef CFG_WITH_LPAE -#error "Not supported" + read_ttbr0_64bit r4, r5 + read_ttbr1_64bit r6, r7 + read_mair0 r8 + read_mair1 r9 + stmia r0!, {r4 - r9} #else - read_ttbr0 r5 - read_ttbr1 r6 - read_ttbcr r7 + read_ttbr0 r4 + read_ttbr1 r5 + read_prrr r6 + read_nmrr r7 + stmia r0!, {r4 - r7} #endif - read_sctlr r8 - read_actlr r9 - read_cpacr r10 - read_mvbar r11 - stmia r0!, {r4 - r11} - read_prrr r4 - read_nmrr r5 - read_vbar r6 - read_nsacr r7 - stmia r0, {r4 - r7} + read_ttbcr r4 + read_actlr r5 + read_cpacr r6 + read_mvbar r7 + read_vbar r8 + read_nsacr r9 + read_sctlr r10 + stmia r0, {r4 - r10} + pop {r4 - r11} bx lr END_FUNC sm_pm_cpu_do_suspend @@ -146,50 +151,50 @@ UNWIND( .cantunwind) cmp r5, r4 beq a7_resume - /* - * A9 needs PCR/DIAG - */ + /* A9 needs PCR/DIAG */ ldmia r0!, {r4 - r5} write_pcr r4 write_diag r5 - a7_resume: - /* v7 resume */ + /* Armv7 generic resume */ mov ip, #0 /* Invalidate icache to PoU */ write_iciallu /* set reserved context */ write_contextidr ip - ldmia r0!, {r4 - r5} + ldmia r0!, {r4 - r6} write_fcseidr r4 write_tpidruro r5 - ldmia r0!, {r4 - r11} /* Invalidate entire TLB */ write_tlbiall - write_dacr r4 + write_dacr r6 #ifdef CFG_WITH_LPAE -#error "Not supported -" + ldmia r0!, {r4 - r9} + write_ttbr0_64bit r4, r5 + write_ttbr1_64bit r6, r7 + write_mair0 r8 + write_mair1 r9 #else - write_ttbr0 r5 - write_ttbr1 r6 - write_ttbcr r7 + ldmia r0!, {r4 - r7} + write_ttbr0 r4 + write_ttbr1 r5 + write_prrr r6 + write_nmrr r7 #endif - - ldmia r0, {r4 - r7} - write_prrr r4 - write_nmrr r5 - write_vbar r6 - write_nsacr r7 - - write_actlr r9 - write_cpacr r10 - write_mvbar r11 + ldmia r0!, {r4 - r10} + write_ttbcr r4 + write_actlr r5 + write_cpacr r6 + write_mvbar r7 + write_vbar r8 + write_nsacr r9 write_bpiall isb dsb /* MMU will be enabled here */ - write_sctlr r8 + write_sctlr r10 isb + mov r0, #0 b suspend_return END_FUNC sm_pm_cpu_do_resume diff --git a/core/arch/arm/tee/entry_std.c b/core/arch/arm/tee/entry_std.c index 424c4c677..92db391d4 100644 --- a/core/arch/arm/tee/entry_std.c +++ b/core/arch/arm/tee/entry_std.c @@ -588,4 +588,4 @@ static TEE_Result default_mobj_init(void) return TEE_SUCCESS; } -driver_init_late(default_mobj_init); +service_init(default_mobj_init); diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c b/core/drivers/clk/clk-stm32mp15.c similarity index 50% rename from core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c rename to core/drivers/clk/clk-stm32mp15.c index c8dbbb7ae..794fd5e75 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c +++ b/core/drivers/clk/clk-stm32mp15.c @@ -1,25 +1,47 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0+) /* - * Copyright (C) 2018-2019, STMicroelectronics + * Copyright (C) 2018-2020, STMicroelectronics */ #include +#include #include #include +#include #include #include #include +#include #include #include #include +#include #include #include #include #include #include +#include #include #include +#define DT_OPP_COMPAT "operating-points-v2" + +/* PLL settings computation related definitions */ +#define POST_DIVM_MIN 8000000 +#define POST_DIVM_MAX 16000000 +#define DIVM_MIN 0 +#define DIVM_MAX 63 +#define DIVN_MIN 24 +#define DIVN_MAX 99 +#define DIVP_MIN 0 +#define DIVP_MAX 127 +#define FRAC_MAX 8192 +#define VCO_MIN 800000000 +#define VCO_MAX 1600000000 + +#define PLL1_SETTINGS_VALID_ID 0x504C4C31 /* "PLL1" */ + /* Identifiers for root oscillators */ enum stm32mp_osc_id { _HSI = 0, @@ -85,11 +107,14 @@ enum stm32mp1_parent_sel { _UART24_SEL, _UART35_SEL, _UART78_SEL, + _SDMMC12_SEL, + _SDMMC3_SEL, _AXISS_SEL, _MCUSS_SEL, _USBPHY_SEL, _USBO_SEL, _RTC_SEL, + _MPU_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -160,6 +185,16 @@ enum stm32mp1_div_id { _DIV_NB, }; +enum stm32mp1_pllcfg { + PLLCFG_M, + PLLCFG_N, + PLLCFG_P, + PLLCFG_Q, + PLLCFG_R, + PLLCFG_O, + PLLCFG_NB +}; + enum stm32mp1_plltype { PLL_800, PLL_1600, @@ -212,6 +247,21 @@ struct stm32mp1_clk_pll { enum stm32mp_osc_id refclk[REFCLK_SIZE]; }; +struct stm32mp1_pll { + uint8_t refclk_min; + uint8_t refclk_max; + uint8_t divn_max; +}; + +/* Compact structure of 32bit cells, copied raw when suspending */ +struct stm32mp1_pll_settings { + uint32_t valid_id; + uint32_t freq[PLAT_MAX_OPP_NB]; + uint32_t volt[PLAT_MAX_OPP_NB]; + uint32_t cfg[PLAT_MAX_OPP_NB][PLAT_MAX_PLLCFG_NB]; + uint32_t frac[PLAT_MAX_OPP_NB]; +}; + #define N_S 0 /* Non-secure can access RCC interface */ #define SEC 1 /* RCC[TZEN] protects RCC interface */ @@ -380,6 +430,18 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), +#ifdef STM32MP1_USE_MPU0_RESET + _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 0, LTDC_PX, _UNKNOWN_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 0, DMA1, _UNKNOWN_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 1, DMA2, _UNKNOWN_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 5, GPU, _UNKNOWN_SEL), + _CLK_SC_FIXED(N_S, RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK), + _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), + _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), +#endif _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), }; @@ -406,6 +468,10 @@ static const uint8_t rng1_parents[] = { _CSI, _PLL4_R, _LSE, _LSI }; +static const uint8_t mpu_parents[] = { + _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */ +}; + /* Parents for (some) non-secure clocks */ #ifdef CFG_WITH_NSEC_UARTS static const uint8_t uart6_parents[] = { @@ -429,6 +495,24 @@ static const uint8_t rtc_parents[] = { _UNKNOWN_ID, _LSE, _LSI, _HSE }; +#ifdef STM32MP1_USE_MPU0_RESET +static const uint8_t usbphy_parents[] = { + _HSE_KER, _PLL4_R, _HSE_KER_DIV2 +}; + +static const uint8_t usbo_parents[] = { + _PLL4_R, _USB_PHY_48 +}; + +static const uint8_t sdmmc12_parents[] = { + _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER +}; + +static const uint8_t sdmmc3_parents[] = { + _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER +}; +#endif + static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { /* Secure aware clocks */ _CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), @@ -437,6 +521,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { _CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents), _CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents), _CLK_PARENT(_RTC_SEL, RCC_BDCR, 0, 0x3, rtc_parents), + _CLK_PARENT(_MPU_SEL, RCC_MPCKSELR, 0, 0x3, mpu_parents), + _CLK_PARENT(_AXISS_SEL, RCC_ASSCKSELR, 0, 0x3, axiss_parents), + _CLK_PARENT(_MCUSS_SEL, RCC_MSSCKSELR, 0, 0x3, mcuss_parents), /* Always non-secure clocks (maybe used in some way in secure world) */ #ifdef CFG_WITH_NSEC_UARTS _CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), @@ -444,8 +531,26 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { _CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, uart234578_parents), _CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, uart234578_parents), #endif - _CLK_PARENT(_AXISS_SEL, RCC_ASSCKSELR, 0, 0x3, axiss_parents), - _CLK_PARENT(_MCUSS_SEL, RCC_MSSCKSELR, 0, 0x3, mcuss_parents), +#ifdef STM32MP1_USE_MPU0_RESET + _CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, sdmmc12_parents), + _CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents), + _CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), + _CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), +#endif +}; + +/* Define characteristics of PLL according type */ +static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { + [PLL_800] = { + .refclk_min = 4, + .refclk_max = 16, + .divn_max = 99, + }, + [PLL_1600] = { + .refclk_min = 8, + .refclk_max = 16, + .divn_max = 199, + }, }; /* PLLNCFGR2 register divider by output */ @@ -549,6 +654,10 @@ static unsigned long osc_frequency(enum stm32mp_osc_id idx) static unsigned int gate_refcounts[NB_GATES]; static unsigned int refcount_lock; +/* Storage of the precomputed SoC settings for PLL1 various OPPs */ +static struct stm32mp1_pll_settings pll1_settings; +static uint32_t current_opp_khz; + static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) { return &stm32mp1_clk_gate[idx]; @@ -591,7 +700,7 @@ static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) return (enum stm32mp1_parent_id)gate_ref(i)->fixed; } -static int stm32mp1_clk_get_parent(unsigned long id) +static int __clk_get_parent(unsigned long id) { const struct stm32mp1_clk_sel *sel = NULL; enum stm32mp1_parent_id parent_id = 0; @@ -701,7 +810,153 @@ static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, return dfout; } -static unsigned long get_clock_rate(int p) +static void pll_start(enum stm32mp1_pll_id pll_id) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uint32_t pllxcr = stm32_rcc_base() + pll->pllxcr; + + if (io_read32(pllxcr) & RCC_PLLNCR_PLLON) + return; + + io_clrsetbits32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | + RCC_PLLNCR_DIVREN, RCC_PLLNCR_PLLON); +} + +#define PLLRDY_TIMEOUT_US (200 * 1000) + +static int pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uint32_t pllxcr = stm32_rcc_base() + pll->pllxcr; + uint64_t start = 0; + + start = timeout_init_us(PLLRDY_TIMEOUT_US); + /* Wait PLL lock */ + while (!(io_read32(pllxcr) & RCC_PLLNCR_PLLRDY)) + if (timeout_elapsed(start)) { + EMSG("PLL%d start failed @ 0x%"PRIx32": 0x%"PRIx32, + pll_id, pllxcr, io_read32(pllxcr)); + return -1; + } + + /* Start the requested output */ + io_setbits32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); + + return 0; +} + +static int pll_stop(enum stm32mp1_pll_id pll_id) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uint32_t pllxcr = stm32_rcc_base() + pll->pllxcr; + uint64_t start = 0; + + /* Stop all output */ + io_clrbits32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | + RCC_PLLNCR_DIVREN); + + /* Stop PLL */ + io_clrbits32(pllxcr, RCC_PLLNCR_PLLON); + + start = timeout_init_us(PLLRDY_TIMEOUT_US); + /* Wait PLL stopped */ + while (!(io_read32(pllxcr) & RCC_PLLNCR_PLLRDY)) + if (timeout_elapsed(start)) { + EMSG("PLL%d stop failed @ 0x%"PRIx32": 0x%"PRIx32, + pll_id, pllxcr, io_read32(pllxcr)); + + return -1; + } + + return 0; +} + +static uint32_t pll_compute_pllxcfgr2(uint32_t *pllcfg) +{ + uint32_t value = 0; + + value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & + RCC_PLLNCFGR2_DIVP_MASK; + value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & + RCC_PLLNCFGR2_DIVQ_MASK; + value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & + RCC_PLLNCFGR2_DIVR_MASK; + + return value; +} + +static void pll_config_output(enum stm32mp1_pll_id pll_id, uint32_t *pllcfg) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t rcc_base = stm32_rcc_base(); + uint32_t value = 0; + + value = pll_compute_pllxcfgr2(pllcfg); + + io_write32(rcc_base + pll->pllxcfgr2, value); +} + +static int pll_compute_pllxcfgr1(const struct stm32mp1_clk_pll *pll, + uint32_t *pllcfg, uint32_t *cfgr1) +{ + uint32_t rcc_base = stm32_rcc_base(); + enum stm32mp1_plltype type = pll->plltype; + unsigned long refclk = 0; + uint32_t ifrge = 0; + uint32_t src = 0; + + src = io_read32(rcc_base + pll->rckxselr) & + RCC_SELR_REFCLK_SRC_MASK; + + refclk = osc_frequency(pll->refclk[src]) / + (pllcfg[PLLCFG_M] + 1U); + + if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || + (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) + return -1; + + if ((type == PLL_800) && (refclk >= 8000000U)) + ifrge = 1U; + + *cfgr1 = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & + RCC_PLLNCFGR1_DIVN_MASK; + *cfgr1 |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & + RCC_PLLNCFGR1_DIVM_MASK; + *cfgr1 |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & + RCC_PLLNCFGR1_IFRGE_MASK; + + return 0; +} + +static int pll_config(enum stm32mp1_pll_id pll_id, uint32_t *pllcfg, + uint32_t fracv) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uint32_t rcc_base = stm32_rcc_base(); + uint32_t value = 0; + int ret = 0; + + ret = pll_compute_pllxcfgr1(pll, pllcfg, &value); + if (ret) + return ret; + + io_write32(rcc_base + pll->pllxcfgr1, value); + + /* Fractional configuration */ + io_write32(rcc_base + pll->pllxfracr, value); + + /* Frac must be enabled only once its configuration is loaded */ + value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; + io_write32(rcc_base + pll->pllxfracr, value); + value = io_read32(rcc_base + pll->pllxfracr); + io_write32(rcc_base + pll->pllxfracr, value | RCC_PLLNFRACR_FRACLE); + + pll_config_output(pll_id, pllcfg); + + return 0; +} + +static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) { uint32_t reg = 0; unsigned long clock = 0; @@ -964,7 +1219,7 @@ static bool clock_is_always_on(unsigned long id) } } -bool stm32_clock_is_enabled(unsigned long id) +static bool clk_stm32_is_enabled(unsigned long id) { int i = 0; @@ -978,13 +1233,13 @@ bool stm32_clock_is_enabled(unsigned long id) return __clk_is_enabled(gate_ref(i)); } -void stm32_clock_enable(unsigned long id) +static TEE_Result clk_stm32_enable(unsigned long id) { int i = 0; uint32_t exceptions = 0; if (clock_is_always_on(id)) - return; + return TEE_SUCCESS; i = stm32mp1_clk_get_gated_id(id); if (i < 0) { @@ -995,7 +1250,7 @@ void stm32_clock_enable(unsigned long id) if (gate_is_non_secure(gate_ref(i))) { /* Enable non-secure clock w/o any refcounting */ __clk_enable(gate_ref(i)); - return; + return TEE_SUCCESS; } exceptions = may_spin_lock(&refcount_lock); @@ -1006,9 +1261,11 @@ void stm32_clock_enable(unsigned long id) gate_refcounts[i]++; may_spin_unlock(&refcount_lock, exceptions); + + return TEE_SUCCESS; } -void stm32_clock_disable(unsigned long id) +static void clk_stm32_disable(unsigned long id) { int i = 0; uint32_t exceptions = 0; @@ -1067,16 +1324,16 @@ static long get_timer_rate(long parent_rate, unsigned int apb_bus) return parent_rate * (timgxpre + 1) * 2; } -unsigned long stm32_clock_get_rate(unsigned long id) +static unsigned long clk_stm32_get_rate(unsigned long id) { - int p = 0; + enum stm32mp1_parent_id p = _UNKNOWN_ID; unsigned long rate = 0; - p = stm32mp1_clk_get_parent(id); + p = __clk_get_parent(id); if (p < 0) return 0; - rate = get_clock_rate(p); + rate = __clk_get_parent_rate(p); if ((id >= TIM2_K) && (id <= TIM14_K)) rate = get_timer_rate(rate, 1); @@ -1210,7 +1467,7 @@ static void secure_parent_clocks(unsigned long parent_id) void stm32mp_register_clock_parents_secure(unsigned long clock_id) { - int parent_id = stm32mp1_clk_get_parent(clock_id); + enum stm32mp1_parent_id parent_id = __clk_get_parent(clock_id); if (parent_id < 0) { DMSG("No parent for clock %lu", clock_id); @@ -1220,6 +1477,14 @@ void stm32mp_register_clock_parents_secure(unsigned long clock_id) secure_parent_clocks(parent_id); } +static const struct clk_ops stm32mp_clk_ops = { + .enable = clk_stm32_enable, + .disable = clk_stm32_disable, + .is_enabled = clk_stm32_is_enabled, + .get_rate = clk_stm32_get_rate, +}; +DECLARE_KEEP_PAGER(stm32mp_clk_ops); + #ifdef CFG_EMBED_DTB static const char *stm32mp_osc_node_label[NB_OSC] = { [_LSI] = "clk-lsi", @@ -1291,15 +1556,15 @@ static void enable_static_secure_clocks(void) }; for (idx = 0; idx < ARRAY_SIZE(secure_enable); idx++) { - stm32_clock_enable(secure_enable[idx]); + clk_stm32_enable(secure_enable[idx]); stm32mp_register_clock_parents_secure(secure_enable[idx]); } if (CFG_TEE_CORE_NB_CORE > 1) - stm32_clock_enable(RTCAPB); + clk_stm32_enable(RTCAPB); } -static TEE_Result stm32mp1_clk_early_init(void) +static void stm32mp1_clk_early_init(void) { void *fdt = NULL; int node = 0; @@ -1308,18 +1573,21 @@ static TEE_Result stm32mp1_clk_early_init(void) int ignored = 0; fdt = get_embedded_dt(); - node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); - - if (node < 0 || _fdt_reg_base_address(fdt, node) != RCC_BASE) - panic(); - - if (_fdt_get_status(fdt, node) & DT_STATUS_OK_SEC) { - io_setbits32(stm32_rcc_base() + RCC_TZCR, RCC_TZCR_TZEN); + node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT); + + if (node < 0 || _fdt_reg_base_address(fdt, node) != RCC_BASE) { + /* Check non secure compatible */ + node = fdt_node_offset_by_compatible(fdt, -1, + DT_RCC_CLK_COMPAT); + if (node < 0 || _fdt_reg_base_address(fdt, node) != RCC_BASE) { + panic(); + } else { + io_clrbits32(stm32_rcc_base() + RCC_TZCR, + RCC_TZCR_TZEN); + IMSG("RCC is non secure"); + } } else { - if (io_read32(stm32_rcc_base() + RCC_TZCR) & RCC_TZCR_TZEN) - panic("Refuse to release RCC[TZEN]"); - - IMSG("RCC is non-secure"); + io_setbits32(stm32_rcc_base() + RCC_TZCR, RCC_TZCR_TZEN); } get_osc_freq_from_dt(fdt); @@ -1360,11 +1628,1024 @@ static TEE_Result stm32mp1_clk_early_init(void) if (ignored != 0) IMSG("DT clock tree configurations were ignored"); +} - enable_static_secure_clocks(); +/* + * Gets OPP parameters (frequency in KHz and voltage in mV) from an OPP table + * subnode. Platform HW support capabilities are also checked. + */ +static int get_opp_freqvolt_from_dt_subnode(void *fdt, int subnode, + uint32_t *freq_khz, + uint32_t *voltage_mv) +{ + const fdt64_t *cuint64 = NULL; + const fdt32_t *cuint32 = NULL; + uint64_t read_freq_64 = 0; + uint32_t read_voltage_32 = 0; + + assert(freq_khz); + assert(voltage_mv); + + cuint32 = fdt_getprop(fdt, subnode, "opp-supported-hw", NULL); + if (cuint32) + if (!stm32mp_supports_cpu_opp(fdt32_to_cpu(*cuint32))) { + DMSG("Invalid opp-supported-hw 0x%"PRIx32, + fdt32_to_cpu(*cuint32)); + return -FDT_ERR_BADVALUE; + } - return TEE_SUCCESS; + cuint64 = fdt_getprop(fdt, subnode, "opp-hz", NULL); + if (!cuint64) { + DMSG("Missing opp-hz"); + return -FDT_ERR_NOTFOUND; + } + + /* Frequency value expressed in KHz must fit on 32 bits */ + read_freq_64 = fdt64_to_cpu(*cuint64) / 1000ULL; + if (read_freq_64 > (uint64_t)UINT32_MAX) { + DMSG("Invalid opp-hz %"PRIu64, read_freq_64); + return -FDT_ERR_BADVALUE; + } + + cuint32 = fdt_getprop(fdt, subnode, "opp-microvolt", NULL); + if (!cuint32) { + DMSG("Missing opp-microvolt"); + return -FDT_ERR_NOTFOUND; + } + + /* Millivolt value must fit on 16 bits */ + read_voltage_32 = fdt32_to_cpu(*cuint32) / 1000U; + if (read_voltage_32 > UINT16_MAX) { + DMSG("Invalid opp-microvolt %"PRIu32, read_voltage_32); + return -FDT_ERR_BADVALUE; + } + + *freq_khz = (uint32_t)read_freq_64; + + *voltage_mv = read_voltage_32; + + return 0; +} + +/* + * Parses OPP table in DT and finds all parameters supported by the HW + * platform. If found, the corresponding frequency and voltage values are + * respectively stored in @pll1_settings structure. + * Note that @*count has to be set by caller to the effective size allocated + * for both tables. Its value is then replaced by the number of filled elements. + */ +static int get_all_opp_freqvolt_from_dt(uint32_t *count) +{ + void *fdt = NULL; + int node = 0; + int subnode = 0; + uint32_t idx = 0; + + assert(count); + + fdt = get_embedded_dt(); + node = fdt_node_offset_by_compatible(fdt, -1, DT_OPP_COMPAT); + if (node < 0) + return node; + + fdt_for_each_subnode(subnode, fdt, node) { + uint32_t read_freq = 0; + uint32_t read_voltage = 0; + + if (get_opp_freqvolt_from_dt_subnode(fdt, subnode, &read_freq, + &read_voltage)) + continue; + + if (idx >= *count) + return -FDT_ERR_NOSPACE; + + pll1_settings.freq[idx] = read_freq; + pll1_settings.volt[idx] = read_voltage; + idx++; + } + + if (!idx) + return -FDT_ERR_NOTFOUND; + + *count = idx; + + return 0; +} + +static int clk_compute_pll1_settings(unsigned long input_freq, int idx) +{ + unsigned long post_divm = 0; + unsigned long long output_freq = pll1_settings.freq[idx] * 1000U; + unsigned long long freq = 0; + unsigned long long vco = 0; + int divm = 0; + int divn = 0; + int divp = 0; + int frac = 0; + int i = 0; + unsigned int diff = 0; + unsigned int best_diff = UINT_MAX; + + /* Following parameters have always the same value */ + pll1_settings.cfg[idx][PLLCFG_Q] = 0; + pll1_settings.cfg[idx][PLLCFG_R] = 0; + pll1_settings.cfg[idx][PLLCFG_O] = PQR(1, 0, 0); + + for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) { + post_divm = input_freq / (unsigned long)(divm + 1); + + if ((post_divm < POST_DIVM_MIN) || + (post_divm > POST_DIVM_MAX)) + continue; + + for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) { + + freq = output_freq * (divm + 1) * (divp + 1); + + divn = (int)((freq / input_freq) - 1); + if ((divn < DIVN_MIN) || (divn > DIVN_MAX)) + continue; + + frac = (int)(((freq * FRAC_MAX) / input_freq) - + ((divn + 1) * FRAC_MAX)); + + /* 2 loops to refine the fractional part */ + for (i = 2; i != 0; i--) { + if (frac > FRAC_MAX) + break; + + vco = (post_divm * (divn + 1)) + + ((post_divm * (unsigned long long)frac) / + FRAC_MAX); + + if ((vco < (VCO_MIN / 2)) || + (vco > (VCO_MAX / 2))) { + frac++; + continue; + } + + freq = vco / (divp + 1); + if (output_freq < freq) + diff = (unsigned int)(freq - + output_freq); + else + diff = (unsigned int)(output_freq - + freq); + + if (diff < best_diff) { + pll1_settings.cfg[idx][PLLCFG_M] = divm; + pll1_settings.cfg[idx][PLLCFG_N] = divn; + pll1_settings.cfg[idx][PLLCFG_P] = divp; + pll1_settings.frac[idx] = frac; + + if (!diff) + return 0; + + best_diff = diff; + } + + frac++; + } + } + } + + if (best_diff == UINT_MAX) { + pll1_settings.cfg[idx][PLLCFG_O] = 0; + return -1; + } + + return 0; +} + +static int clk_get_pll1_settings(uint32_t clksrc, int index) +{ + unsigned long input_freq = 0; + unsigned int i = 0; + + for (i = 0; i < PLAT_MAX_OPP_NB; i++) + if (pll1_settings.freq[i] == pll1_settings.freq[index]) + break; + + if (((i == PLAT_MAX_OPP_NB) && + !stm32mp1_clk_pll1_settings_are_valid()) || + ((i < PLAT_MAX_OPP_NB) && !pll1_settings.cfg[i][PLLCFG_O])) { + /* + * Either PLL1 settings structure is completely empty, + * or these settings are not yet computed: do it. + */ + switch (clksrc) { + case CLK_PLL12_HSI: + input_freq = clk_stm32_get_rate(CK_HSI); + break; + case CLK_PLL12_HSE: + input_freq = clk_stm32_get_rate(CK_HSE); + break; + default: + panic(); + } + + return clk_compute_pll1_settings(input_freq, index); + } + + if (i < PLAT_MAX_OPP_NB) { + if (pll1_settings.cfg[i][PLLCFG_O]) + return 0; + + /* + * Index is in range and PLL1 settings are computed: + * use content to answer to the request. + */ + memcpy(&pll1_settings.cfg[index][0], &pll1_settings.cfg[i][0], + sizeof(uint32_t) * PLAT_MAX_PLLCFG_NB); + pll1_settings.frac[index] = pll1_settings.frac[i]; + + return 0; + } + + return -1; +} + +static int clk_save_current_pll1_settings(uint32_t buck1_voltage) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1); + uint32_t rcc_base = stm32_rcc_base(); + uint32_t freq = 0; + unsigned int i = 0; + + freq = UDIV_ROUND_NEAREST(clk_stm32_get_rate(CK_MPU), 1000L); + + for (i = 0; i < PLAT_MAX_OPP_NB; i++) + if (pll1_settings.freq[i] == freq) + break; + + if ((i == PLAT_MAX_OPP_NB) || + ((pll1_settings.volt[i] != buck1_voltage) && buck1_voltage)) + return -1; + + pll1_settings.cfg[i][PLLCFG_M] = (io_read32(rcc_base + pll->pllxcfgr1) & + RCC_PLLNCFGR1_DIVM_MASK) >> + RCC_PLLNCFGR1_DIVM_SHIFT; + + pll1_settings.cfg[i][PLLCFG_N] = (io_read32(rcc_base + pll->pllxcfgr1) & + RCC_PLLNCFGR1_DIVN_MASK) >> + RCC_PLLNCFGR1_DIVN_SHIFT; + + pll1_settings.cfg[i][PLLCFG_P] = (io_read32(rcc_base + pll->pllxcfgr2) & + RCC_PLLNCFGR2_DIVP_MASK) >> + RCC_PLLNCFGR2_DIVP_SHIFT; + + pll1_settings.cfg[i][PLLCFG_Q] = (io_read32(rcc_base + pll->pllxcfgr2) & + RCC_PLLNCFGR2_DIVQ_MASK) >> + RCC_PLLNCFGR2_DIVQ_SHIFT; + + pll1_settings.cfg[i][PLLCFG_R] = (io_read32(rcc_base + pll->pllxcfgr2) & + RCC_PLLNCFGR2_DIVR_MASK) >> + RCC_PLLNCFGR2_DIVR_SHIFT; + + pll1_settings.cfg[i][PLLCFG_O] = io_read32(rcc_base + pll->pllxcr) >> + RCC_PLLNCR_DIVEN_SHIFT; + + pll1_settings.frac[i] = (io_read32(rcc_base + pll->pllxfracr) & + RCC_PLLNFRACR_FRACV_MASK) >> + RCC_PLLNFRACR_FRACV_SHIFT; + + return i; +} + +static uint32_t stm32mp1_clk_get_pll1_current_clksrc(void) +{ + uint32_t value = 0; + const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1); + uint32_t rcc_base = stm32_rcc_base(); + + value = io_read32(rcc_base + pll->rckxselr); + + switch (value & RCC_SELR_REFCLK_SRC_MASK) { + case 0: + return CLK_PLL12_HSI; + case 1: + return CLK_PLL12_HSE; + default: + panic(); + } +} + +int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage) +{ + unsigned int i = 0; + int ret = 0; + int index = 0; + uint32_t count = PLAT_MAX_OPP_NB; + uint32_t clksrc = 0; + + ret = get_all_opp_freqvolt_from_dt(&count); + switch (ret) { + case 0: + break; + case -FDT_ERR_NOTFOUND: + DMSG("Cannot find all OPP info in DT: use default settings."); + return 0; + default: + EMSG("Inconsistent OPP settings found in DT, ignored."); + return 0; + } + + index = clk_save_current_pll1_settings(buck1_voltage); + + clksrc = stm32mp1_clk_get_pll1_current_clksrc(); + + for (i = 0; i < count; i++) { + if (index >= 0 && i == (unsigned int)index) + continue; + + ret = clk_get_pll1_settings(clksrc, i); + if (ret != 0) + return ret; + } + + pll1_settings.valid_id = PLL1_SETTINGS_VALID_ID; + + return 0; +} + +void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data, size_t size) +{ + if ((size != sizeof(pll1_settings)) || + !stm32mp1_clk_pll1_settings_are_valid()) + panic(); + + memcpy(data, &pll1_settings, size); +} + +bool stm32mp1_clk_pll1_settings_are_valid(void) +{ + return pll1_settings.valid_id == PLL1_SETTINGS_VALID_ID; +} +#else +static void stm32mp1_clk_early_init(void) +{ + vaddr_t rcc_base = stm32_rcc_base(); + + /* Expect booting from a secure setup */ + if ((io_read32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) == 0) + panic("RCC TZC[TZEN]"); +} + +int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage __unused) +{ + return 0; +} + +void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data __unused, + size_t size __unused) +{ +} + +bool stm32mp1_clk_pll1_settings_are_valid(void) +{ + return false; } -service_init(stm32mp1_clk_early_init); +static void enable_static_secure_clocks(void) +{ +} #endif /*CFG_EMBED_DTB*/ + +/* Start MPU OPP */ +#define CLKSRC_TIMEOUT_US (200 * 1000) +#define CLKDIV_TIMEOUT_US (200 * 1000) +#define CLK_MPU_PLL1P 0x00000202 +#define CLK_MPU_PLL1P_DIV 0x00000203 + +static int stm32mp1_set_clksrc(unsigned int clksrc) +{ + uintptr_t address = stm32_rcc_base() + (clksrc >> 4); + uint64_t timeout_ref = 0; + + io_clrsetbits32(address, RCC_SELR_SRC_MASK, clksrc & RCC_SELR_SRC_MASK); + + timeout_ref = timeout_init_us(CLKSRC_TIMEOUT_US); + while ((io_read32(address) & RCC_SELR_SRCRDY) == 0U) { + if (timeout_elapsed(timeout_ref)) { + EMSG("CLKSRC %u start failed @ 0x%"PRIxPTR": 0x%"PRIx32, + clksrc, address, io_read32(address)); + return -1; + } + } + + return 0; +} + +static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) +{ + uint64_t timeout_ref = 0; + + io_clrsetbits32(address, RCC_DIVR_DIV_MASK, clkdiv & RCC_DIVR_DIV_MASK); + + timeout_ref = timeout_init_us(CLKDIV_TIMEOUT_US); + while ((io_read32(address) & RCC_DIVR_DIVRDY) == 0U) { + if (timeout_elapsed(timeout_ref)) { + EMSG("CLKDIV 0x%x start failed @ 0x%"PRIxPTR": 0x%"PRIx32, + clkdiv, address, io_read32(address)); + return -1; + } + } + + return 0; +} + +/* + * Check if PLL1 can be configured on the fly. + * @result (-1) => config on the fly is not possible. + * (0) => config on the fly is possible. + * (+1) => same parameters as those in place, no need to reconfig. + * Return value is 0 if no error. + */ +static int is_pll_config_on_the_fly(enum stm32mp1_pll_id pll_id, + uint32_t *pllcfg, uint32_t fracv, + int *result) +{ + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uintptr_t rcc_base = stm32_rcc_base(); + uint32_t fracr = 0; + uint32_t value = 0; + int ret = 0; + + ret = pll_compute_pllxcfgr1(pll, pllcfg, &value); + if (ret) + return ret; + + if (io_read32(rcc_base + pll->pllxcfgr1) != value) { + /* Different DIVN/DIVM, can't config on the fly */ + *result = -1; + return 0; + } + + *result = true; + + fracr = fracv << RCC_PLLNFRACR_FRACV_SHIFT; + fracr |= RCC_PLLNFRACR_FRACLE; + value = pll_compute_pllxcfgr2(pllcfg); + + if ((io_read32(rcc_base + pll->pllxfracr) == fracr) && + (io_read32(rcc_base + pll->pllxcfgr2) == value)) + /* Same parameters, no need to config */ + *result = 1; + else + *result = 0; + + return 0; +} + +static int stm32mp1_get_mpu_div(uint32_t freq_khz) +{ + unsigned long freq_pll1_p; + unsigned long div; + + freq_pll1_p = __clk_get_parent_rate(_PLL1_P) / 1000UL; + if ((freq_pll1_p % freq_khz) != 0U) + return -1; + + div = freq_pll1_p / freq_khz; + + switch (div) { + case 1UL: + case 2UL: + case 4UL: + case 8UL: + case 16UL: + return __builtin_ffs(div) - 1; + default: + return -1; + } +} + +/* Configure PLL1 from input frequency OPP parameters */ +static int pll1_config_from_opp_khz(uint32_t freq_khz) +{ + unsigned int idx = 0; + int ret = 0; + int div = 0; + int config_on_the_fly = -1; + + for (idx = 0; idx < PLAT_MAX_OPP_NB; idx++) + if (pll1_settings.freq[idx] == freq_khz) + break; + + if (idx == PLAT_MAX_OPP_NB) + return -1; + + div = stm32mp1_get_mpu_div(freq_khz); + switch (div) { + case -1: + break; + case 0: + return stm32mp1_set_clksrc(CLK_MPU_PLL1P); + default: + ret = stm32mp1_set_clkdiv(div, stm32_rcc_base() + + RCC_MPCKDIVR); + if (ret == 0) + ret = stm32mp1_set_clksrc(CLK_MPU_PLL1P_DIV); + + return ret; + } + + ret = is_pll_config_on_the_fly(_PLL1, &pll1_settings.cfg[idx][0], + pll1_settings.frac[idx], + &config_on_the_fly); + if (ret) + return ret; + + if (config_on_the_fly == 1) + return 0; + + if (config_on_the_fly == -1) { + /* Switch to HSI and stop PLL1 before reconfiguration */ + ret = stm32mp1_set_clksrc(CLK_MPU_HSI); + if (ret) + return ret; + + ret = pll_stop(_PLL1); + if (ret) + return ret; + } + + ret = pll_config(_PLL1, &pll1_settings.cfg[idx][0], + pll1_settings.frac[idx]); + if (ret) + return ret; + + if (config_on_the_fly == -1) { + /* Start PLL1 and switch back to after reconfiguration */ + pll_start(_PLL1); + + ret = pll_output(_PLL1, pll1_settings.cfg[idx][PLLCFG_O]); + if (ret) + return ret; + + ret = stm32mp1_set_clksrc(CLK_MPU_PLL1P); + if (ret) + return ret; + } + + return 0; +} + +static void save_current_opp(void) +{ + unsigned long freq_khz = UDIV_ROUND_NEAREST(clk_stm32_get_rate(CK_MPU), + 1000UL); + if (freq_khz > (unsigned long)UINT32_MAX) + panic(); + + current_opp_khz = (uint32_t)freq_khz; +} + +int stm32mp1_set_opp_khz(uint32_t freq_khz) +{ + uint32_t mpu_src = 0; + + if (freq_khz == current_opp_khz) + return 0; + + if (!stm32mp1_clk_pll1_settings_are_valid()) { + /* + * No OPP table in DT or an error occurred during PLL1 + * settings computation, system can only work on current + * operating point so return error. + */ + return -1; + } + + /* Check that PLL1 is MPU clock source */ + mpu_src = io_read32(stm32_rcc_base() + RCC_MPCKSELR) & + RCC_SELR_SRC_MASK; + if ((mpu_src != RCC_MPCKSELR_PLL) && + (mpu_src != RCC_MPCKSELR_PLL_MPUDIV)) + return -1; + + if (pll1_config_from_opp_khz(freq_khz)) { + /* Restore original value */ + if (pll1_config_from_opp_khz(current_opp_khz)) { + EMSG("No CPU operating point can be set"); + panic(); + } + + return -1; + } + + current_opp_khz = freq_khz; + + return 0; +} + +int stm32mp1_round_opp_khz(uint32_t *freq_khz) +{ + unsigned int i = 0; + uint32_t round_opp = 0; + + if (!stm32mp1_clk_pll1_settings_are_valid()) { + /* + * No OPP table in DT, or an error occurred during PLL1 + * settings computation, system can only work on current + * operating point, so return current CPU frequency. + */ + *freq_khz = current_opp_khz; + + return 0; + } + + for (i = 0; i < PLAT_MAX_OPP_NB; i++) + if ((pll1_settings.freq[i] <= *freq_khz) && + (pll1_settings.freq[i] > round_opp)) + round_opp = pll1_settings.freq[i]; + + *freq_khz = round_opp; + + return 0; +} +/* End PMU OPP */ + +#ifdef CFG_PM +struct soc_stop_context { + uint32_t pll3cr; + uint32_t pll4cr; + uint32_t mssckselr; + uint32_t mcudivr; +}; + +static struct soc_stop_context soc_stop_ctx; + +static void save_pll34_state(void) +{ + uintptr_t rcc_base = stm32_rcc_base(); + struct soc_stop_context *ctx = &soc_stop_ctx; + + ctx->pll3cr = io_read32(rcc_base + RCC_PLL3CR); + ctx->pll4cr = io_read32(rcc_base + RCC_PLL4CR); +} + +static void save_mcu_subsys_clocks(void) +{ + uintptr_t rcc_base = stm32_rcc_base(); + struct soc_stop_context *ctx = &soc_stop_ctx; + + ctx->mssckselr = io_read32(rcc_base + RCC_MSSCKSELR); + ctx->mcudivr = io_read32(rcc_base + RCC_MCUDIVR) & + RCC_MCUDIV_MASK; +} + +static void restore_pll34_state(void) +{ + struct soc_stop_context *ctx = &soc_stop_ctx; + + /* Let PLL4 start while we're starting and waiting for PLL3 */ + if (ctx->pll4cr & RCC_PLLNCR_PLLON) + pll_start(_PLL4); + + if (ctx->pll3cr & RCC_PLLNCR_PLLON) { + pll_start(_PLL3); + if (pll_output(_PLL3, ctx->pll3cr >> RCC_PLLNCR_DIVEN_SHIFT)) { + EMSG("Failed to restore PLL3"); + panic(); + } + } + + if (ctx->pll4cr & RCC_PLLNCR_PLLON) { + if (pll_output(_PLL4, ctx->pll4cr >> RCC_PLLNCR_DIVEN_SHIFT)) { + EMSG("Failed to restore PLL4"); + panic(); + } + } +} + +static void restore_mcu_subsys_clocks(void) +{ + uintptr_t rcc_base = stm32_rcc_base(); + struct soc_stop_context *ctx = &soc_stop_ctx; + + io_write32(rcc_base + RCC_MSSCKSELR, ctx->mssckselr); + + if (stm32mp1_set_clkdiv(ctx->mcudivr, rcc_base + RCC_MCUDIVR)) { + EMSG("Failed to restore MCUDIVR"); + panic(); + } +} + +/* + * Sequence to save/restore the non-secure configuration. + * Restoring clocks and muxes need IPs to run on kernel clock + * hence on configuration is restored at resume, kernel clock + * should be disable: this mandates secure access. + * + * backup_mux*_cfg for the clock muxes. + * backup_clock_sc_cfg for the set/clear clock gating registers + * backup_clock_cfg for the regular full write registers + */ + +struct backup_mux_cfg { + uint16_t offset; + uint8_t value; + uint8_t bit_len; +}; + +#define MUXCFG(_offset, _bit_len) \ + { .offset = (_offset), .bit_len = (_bit_len) } + +struct backup_mux_cfg backup_mux0_cfg[] = { + MUXCFG(RCC_SDMMC12CKSELR, 3), + MUXCFG(RCC_SPI2S23CKSELR, 3), + MUXCFG(RCC_SPI45CKSELR, 3), + MUXCFG(RCC_I2C12CKSELR, 3), + MUXCFG(RCC_I2C35CKSELR, 3), + MUXCFG(RCC_LPTIM23CKSELR, 3), + MUXCFG(RCC_LPTIM45CKSELR, 3), + MUXCFG(RCC_UART24CKSELR, 3), + MUXCFG(RCC_UART35CKSELR, 3), + MUXCFG(RCC_UART78CKSELR, 3), + MUXCFG(RCC_SAI1CKSELR, 3), + MUXCFG(RCC_ETHCKSELR, 2), + MUXCFG(RCC_I2C46CKSELR, 3), + MUXCFG(RCC_RNG2CKSELR, 2), + MUXCFG(RCC_SDMMC3CKSELR, 3), + MUXCFG(RCC_FMCCKSELR, 2), + MUXCFG(RCC_QSPICKSELR, 2), + MUXCFG(RCC_USBCKSELR, 2), + MUXCFG(RCC_SPDIFCKSELR, 2), + MUXCFG(RCC_SPI2S1CKSELR, 3), + MUXCFG(RCC_CECCKSELR, 2), + MUXCFG(RCC_LPTIM1CKSELR, 3), + MUXCFG(RCC_UART6CKSELR, 3), + MUXCFG(RCC_FDCANCKSELR, 2), + MUXCFG(RCC_SAI2CKSELR, 3), + MUXCFG(RCC_SAI3CKSELR, 3), + MUXCFG(RCC_SAI4CKSELR, 3), + MUXCFG(RCC_ADCCKSELR, 2), + MUXCFG(RCC_DSICKSELR, 1), + MUXCFG(RCC_CPERCKSELR, 2), + MUXCFG(RCC_RNG1CKSELR, 2), + MUXCFG(RCC_STGENCKSELR, 2), + MUXCFG(RCC_UART1CKSELR, 3), + MUXCFG(RCC_SPI6CKSELR, 3), +}; + +struct backup_mux_cfg backup_mux4_cfg[] = { + MUXCFG(RCC_USBCKSELR, 1), +}; + +static void backup_mux_cfg(void) +{ + struct backup_mux_cfg *cfg = backup_mux0_cfg; + size_t count = ARRAY_SIZE(backup_mux0_cfg); + size_t i = 0; + uintptr_t base = stm32_rcc_base(); + + for (i = 0; i < count; i++) + cfg[i].value = io_read32(base + cfg[i].offset) & + GENMASK_32(cfg[i].bit_len - 1, 0); + + cfg = backup_mux4_cfg; + count = ARRAY_SIZE(backup_mux4_cfg); + + for (i = 0; i < count; i++) + cfg[i].value = io_read32(base + cfg[i].offset) & + GENMASK_32(4 + cfg[i].bit_len - 1, 4); +} + +static void restore_mux_cfg(void) +{ + struct backup_mux_cfg *cfg = backup_mux0_cfg; + size_t count = ARRAY_SIZE(backup_mux0_cfg); + size_t i = 0; + uintptr_t base = stm32_rcc_base(); + + for (i = 0; i < count; i++) + io_clrsetbits32(base + cfg[i].offset, + GENMASK_32(cfg[i].bit_len - 1, 0), + cfg[i].value); + + cfg = backup_mux4_cfg; + count = ARRAY_SIZE(backup_mux4_cfg); + + for (i = 0; i < count; i++) + io_clrsetbits32(base + cfg[i].offset, + GENMASK_32(4 + cfg[i].bit_len - 1, 4), + cfg[i].value); +} + +/* Structure is used for set/clear registers and for regular registers */ +struct backup_clock_cfg { + uint32_t offset; + uint32_t value; +}; + +static struct backup_clock_cfg backup_clock_sc_cfg[] = { + { .offset = RCC_MP_APB1ENSETR }, + { .offset = RCC_MP_APB2ENSETR }, + { .offset = RCC_MP_APB3ENSETR }, + { .offset = RCC_MP_APB4ENSETR }, + { .offset = RCC_MP_APB5ENSETR }, + { .offset = RCC_MP_AHB2ENSETR }, + { .offset = RCC_MP_AHB3ENSETR }, + { .offset = RCC_MP_AHB4ENSETR }, + { .offset = RCC_MP_AHB5ENSETR }, + { .offset = RCC_MP_AHB6ENSETR }, + { .offset = RCC_MP_MLAHBENSETR }, +}; + +static struct backup_clock_cfg backup_clock_cfg[] = { + { .offset = RCC_TZCR}, + { .offset = RCC_MCO1CFGR }, + { .offset = RCC_MCO2CFGR }, + { .offset = RCC_PLL3CR }, + { .offset = RCC_PLL4CR }, + { .offset = RCC_PLL4CFGR2 }, + { .offset = RCC_MCUDIVR }, + { .offset = RCC_MSSCKSELR }, +}; + +static void backup_sc_cfg(void) +{ + struct backup_clock_cfg *cfg = backup_clock_sc_cfg; + size_t count = ARRAY_SIZE(backup_clock_sc_cfg); + size_t i = 0; + uintptr_t base = stm32_rcc_base(); + + for (i = 0; i < count; i++) + cfg[i].value = io_read32(base + cfg[i].offset); +} + +static void restore_sc_cfg(void) +{ + struct backup_clock_cfg *cfg = backup_clock_sc_cfg; + size_t count = ARRAY_SIZE(backup_clock_sc_cfg); + size_t i = 0; + uintptr_t base = stm32_rcc_base(); + + for (i = 0; i < count; i++) { + io_write32(base + cfg[i].offset, cfg[i].value); + io_write32(base + cfg[i].offset + RCC_MP_ENCLRR_OFFSET, + ~cfg[i].value); + } +} + +static void backup_regular_cfg(void) +{ + struct backup_clock_cfg *cfg = backup_clock_cfg; + size_t count = ARRAY_SIZE(backup_clock_cfg); + size_t i = 0; + uintptr_t base = stm32_rcc_base(); + + for (i = 0; i < count; i++) + cfg[i].value = io_read32(base + cfg[i].offset); +} + +static void restore_regular_cfg(void) +{ + struct backup_clock_cfg *cfg = backup_clock_cfg; + size_t count = ARRAY_SIZE(backup_clock_cfg); + size_t i = 0; + uintptr_t base = stm32_rcc_base(); + + for (i = 0; i < count; i++) + io_write32(base + cfg[i].offset, cfg[i].value); +} + +static void disable_kernel_clocks(void) +{ + const uint32_t ker_mask = RCC_OCENR_HSIKERON | + RCC_OCENR_CSIKERON | + RCC_OCENR_HSEKERON; + + /* Disable all ck_xxx_ker clocks */ + io_write32(stm32_rcc_base() + RCC_OCENCLRR, ker_mask); +} + +static void enable_kernel_clocks(void) +{ + uintptr_t rcc_base = stm32_rcc_base(); + uint32_t reg = 0; + const uint32_t ker_mask = RCC_OCENR_HSIKERON | + RCC_OCENR_CSIKERON | + RCC_OCENR_HSEKERON; + + /* Enable ck_xxx_ker clocks if ck_xxx was on */ + reg = io_read32(rcc_base + RCC_OCENSETR) << 1; + io_write32(rcc_base + RCC_OCENSETR, reg & ker_mask); +} + +static void clear_rcc_reset_status(void) +{ + /* Clear reset status fields */ + io_write32(stm32_rcc_base() + RCC_MP_RSTSCLRR, 0); +} + +void stm32mp1_clk_save_context_for_stop(void) +{ + enable_kernel_clocks(); + save_mcu_subsys_clocks(); + save_pll34_state(); +} + +void stm32mp1_clk_restore_context_for_stop(void) +{ + restore_pll34_state(); + /* Restore MCU clock source after PLL3 is ready */ + restore_mcu_subsys_clocks(); + disable_kernel_clocks(); +} + +void stm32mp1_clk_mcuss_protect(bool enable) +{ + uintptr_t rcc_base = stm32_rcc_base(); + + if (enable) + io_setbits32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); + else + io_clrbits32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); +} + +static void stm32_clock_suspend(void) +{ + backup_regular_cfg(); + backup_sc_cfg(); + backup_mux_cfg(); + save_pll34_state(); + + enable_kernel_clocks(); + clear_rcc_reset_status(); +} + +static void stm32_clock_resume(void) +{ + unsigned int idx = 0; + + restore_pll34_state(); + restore_mux_cfg(); + restore_sc_cfg(); + restore_regular_cfg(); + + /* Sync secure and shared clocks physical state on functional state */ + for (idx = 0; idx < NB_GATES; idx++) { + struct stm32mp1_clk_gate const *gate = gate_ref(idx); + + if (gate_is_non_secure(gate)) + continue; + + if (gate_refcounts[idx]) { + DMSG("Force clock %d enable", gate->clock_id); + __clk_enable(gate); + } else { + DMSG("Force clock %d disable", gate->clock_id); + __clk_disable(gate); + } + } + + disable_kernel_clocks(); +} + +static TEE_Result stm32_clock_pm(enum pm_op op, unsigned int pm_hint __unused, + const struct pm_callback_handle *hdl __unused) +{ + if (op == PM_OP_SUSPEND) + stm32_clock_suspend(); + else + stm32_clock_resume(); + + return TEE_SUCCESS; +} +DECLARE_KEEP_PAGER(stm32_clock_pm); +#else +static TEE_Result stm32_clock_pm(enum pm_op op __unused, + unsigned int pm_hint __unused, + const struct pm_callback_handle *hdl __unused) +{ + return TEE_ERROR_SECURITY; +} +#endif /*CFG_PM*/ + +static void init_non_secure_rcc(void) +{ + uintptr_t rcc_base = stm32_rcc_base(); + + /* Clear all interrupt flags and core stop requests */ + io_write32(rcc_base + RCC_MP_CIFR, 0x110F1F); + io_write32(rcc_base + RCC_MP_SREQCLRR, 0x3); +} + +static TEE_Result stm32_clk_probe(void) +{ + assert(PLLCFG_NB == PLAT_MAX_PLLCFG_NB); + + stm32mp1_clk_early_init(); + enable_static_secure_clocks(); + save_current_opp(); + init_non_secure_rcc(); + register_pm_core_service_cb(stm32_clock_pm, NULL); + + clk_provider_register(&stm32mp_clk_ops); + + return TEE_SUCCESS; +} +/* Setup clock support before driver initialization */ +service_init(stm32_clk_probe); diff --git a/core/drivers/clk/clk.c b/core/drivers/clk/clk.c new file mode 100644 index 000000000..f6e5d8ecf --- /dev/null +++ b/core/drivers/clk/clk.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + * Author(s): Ludovic Barre, for STMicroelectronics. + */ + +#include +#include +#include + +static const struct clk_ops *ops; + +TEE_Result clk_enable(unsigned long id) +{ + assert(ops && ops->enable); + + return ops->enable(id); +} + +void clk_disable(unsigned long id) +{ + assert(ops && ops->disable); + + ops->disable(id); +} + +unsigned long clk_get_rate(unsigned long id) +{ + assert(ops && ops->get_rate); + + return ops->get_rate(id); +} + +unsigned long clk_get_parent(unsigned long id) +{ + assert(ops); + + if (ops->get_parent) + return ops->get_parent(id); + + return CLK_UNKNOWN_ID; +} + +bool clk_is_enabled(unsigned long id) +{ + assert(ops && ops->is_enabled); + + return ops->is_enabled(id); +} + +void clk_provider_register(const struct clk_ops *ops_ptr) +{ + assert(!ops && ops_ptr && ops_ptr->enable && + ops_ptr->disable && ops_ptr->get_rate && + ops_ptr->is_enabled); + + ops = ops_ptr; +} diff --git a/core/drivers/clk/sub.mk b/core/drivers/clk/sub.mk new file mode 100644 index 000000000..4caed574b --- /dev/null +++ b/core/drivers/clk/sub.mk @@ -0,0 +1,2 @@ +srcs-$(CFG_CLK_DRIVER) += clk.c +srcs-$(CFG_STM32MP15_CLK) += clk-stm32mp15.c diff --git a/core/drivers/gic.c b/core/drivers/gic.c index 0bad97486..3f1a606ed 100644 --- a/core/drivers/gic.c +++ b/core/drivers/gic.c @@ -7,12 +7,15 @@ #include #include #include +#include #include #include #include +#include +#include #include -#include #include +#include /* Offsets from gic.gicc_base */ #define GICC_CTLR (0x000) @@ -33,9 +36,11 @@ #define GICD_ICENABLER(n) (0x180 + (n) * 4) #define GICD_ISPENDR(n) (0x200 + (n) * 4) #define GICD_ICPENDR(n) (0x280 + (n) * 4) +#define GICD_ISACTIVER(n) (0x300 + (n) * 4) #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) #define GICD_ITARGETSR(n) (0x800 + (n) * 4) #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) +#define GICD_ICFGR(n) (0xc00 + (n) * 4) #define GICD_SGIR (0xF00) #define GICD_CTLR_ENABLEGRP0 (1 << 0) @@ -76,6 +81,25 @@ static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, static void gic_op_set_affinity(struct itr_chip *chip, size_t it, uint8_t cpu_mask); +#if defined(CFG_ARM_GIC_PM) +static void gic_pm_add_it(struct gic_data *gd, unsigned int it); +static void gic_pm_register(struct gic_data *gd); +#else +static void gic_pm_add_it(struct gic_data *gd __unused, + unsigned int it __unused) +{ +} +static void gic_pm_register(struct gic_data *gd __unused) +{ +} +#endif + +#if !defined(CFG_ARM_GICV3) +static uint8_t gic_op_set_pmr(struct itr_chip *chip, uint8_t mask); +static uint8_t gic_op_set_ipriority(struct itr_chip *chip, size_t it, + uint8_t mask); +#endif + static const struct itr_ops gic_ops = { .add = gic_op_add, .enable = gic_op_enable, @@ -83,6 +107,10 @@ static const struct itr_ops gic_ops = { .raise_pi = gic_op_raise_pi, .raise_sgi = gic_op_raise_sgi, .set_affinity = gic_op_set_affinity, +#if !defined(CFG_ARM_GICV3) + .set_pmr = gic_op_set_pmr, + .set_ipriority = gic_op_set_ipriority, +#endif }; DECLARE_KEEP_PAGER(gic_ops); @@ -148,10 +176,10 @@ void gic_cpu_init(struct gic_data *gd) * allow the Non-secure world to adjust the priority mask itself */ #if defined(CFG_ARM_GICV3) - write_icc_pmr(0x80); + write_icc_pmr(GIC_HIGHEST_NS_PRIORITY); write_icc_igrpen1(1); #else - io_write32(gd->gicc_base + GICC_PMR, 0x80); + io_write32(gd->gicc_base + GICC_PMR, GIC_HIGHEST_NS_PRIORITY); /* Enable GIC */ io_write32(gd->gicc_base + GICC_CTLR, @@ -160,13 +188,10 @@ void gic_cpu_init(struct gic_data *gd) #endif } -void gic_init(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, - vaddr_t gicd_base) +void gic_init_setup(struct gic_data *gd) { size_t n; - gic_init_base_addr(gd, gicc_base, gicd_base); - for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { /* Disable interrupts */ io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); @@ -191,11 +216,11 @@ void gic_init(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, * allow the Non-secure world to adjust the priority mask itself */ #if defined(CFG_ARM_GICV3) - write_icc_pmr(0x80); + write_icc_pmr(GIC_HIGHEST_NS_PRIORITY); write_icc_igrpen1(1); io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); #else - io_write32(gd->gicc_base + GICC_PMR, 0x80); + io_write32(gd->gicc_base + GICC_PMR, GIC_HIGHEST_NS_PRIORITY); /* Enable GIC */ io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | @@ -212,6 +237,14 @@ void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, gd->gicd_base = gicd_base; gd->max_it = probe_max_it(gicc_base, gicd_base); gd->chip.ops = &gic_ops; + + gic_pm_register(gd); +} + +void gic_init(struct gic_data *gd, vaddr_t gicc_base, vaddr_t gicd_base) +{ + gic_init_base_addr(gd, gicc_base, gicd_base); + gic_init_setup(gd); } static void gic_it_add(struct gic_data *gd, size_t it) @@ -236,7 +269,8 @@ static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, { size_t idx __maybe_unused = it / NUM_INTS_PER_REG; uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); - uint32_t target, target_shift; + uint32_t target = 0; + uint32_t target_shift = 0; vaddr_t itargetsr = gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); @@ -258,15 +292,39 @@ static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) size_t idx __maybe_unused = it / NUM_INTS_PER_REG; uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); - /* Assigned to group0 */ - assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); - /* Set prio it to selected CPUs */ DMSG("prio: writing 0x%x to 0x%" PRIxVA, prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); } +static uint8_t gic_op_set_pmr(struct itr_chip *chip, uint8_t mask) +{ + struct gic_data *gd = container_of(chip, struct gic_data, chip); + uint32_t pmr = io_read32(gd->gicc_base + GICC_PMR); + + /* + * Order memory updates w.r.t. PMR write, and ensure they're visible + * before potential out of band interrupt trigger because of PMR update. + */ + dsb_ishst(); + io_write32(gd->gicc_base + GICC_PMR, mask); + dsb_ishst(); + + return (uint8_t)pmr; +} + +static uint8_t gic_op_set_ipriority(struct itr_chip *chip, size_t it, + uint8_t mask) +{ + struct gic_data *gd = container_of(chip, struct gic_data, chip); + uint8_t prio = io_read8(gd->gicd_base + GICD_IPRIORITYR(0) + it); + + gic_it_set_prio(gd, it, mask); + + return prio; +} + static void gic_it_enable(struct gic_data *gd, size_t it) { size_t idx = it / NUM_INTS_PER_REG; @@ -391,8 +449,8 @@ void gic_dump_state(struct gic_data *gd) void gic_it_handle(struct gic_data *gd) { - uint32_t iar; - uint32_t id; + uint32_t iar = 0; + uint32_t id = 0; iar = gic_read_iar(gd); id = iar & GICC_IAR_IT_ID_MASK; @@ -417,6 +475,8 @@ static void gic_op_add(struct itr_chip *chip, size_t it, /* Set the CPU mask to deliver interrupts to any online core */ gic_it_set_cpu_mask(gd, it, 0xff); gic_it_set_prio(gd, it, 0x1); + + gic_pm_add_it(gd, it); } static void gic_op_enable(struct itr_chip *chip, size_t it) @@ -462,6 +522,7 @@ static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, else gic_it_raise_sgi(gd, it, cpu_mask, 0); } + static void gic_op_set_affinity(struct itr_chip *chip, size_t it, uint8_t cpu_mask) { @@ -472,3 +533,137 @@ static void gic_op_set_affinity(struct itr_chip *chip, size_t it, gic_it_set_cpu_mask(gd, it, cpu_mask); } + +#if defined(CFG_ARM_GIC_PM) +/* + * Save/restore interrupts registered from the gic_op_add_it() handler + */ +#define IT_PM_GPOUP1_BIT BIT(0) +#define IT_PM_ENABLE_BIT BIT(1) +#define IT_PM_PENDING_BIT BIT(2) +#define IT_PM_ACTIVE_BIT BIT(3) +#define IT_PM_CONFIG_MASK GENMASK_32(1, 0) + +/* + * @it - interrupt ID/number + * @flags - bitflag IT_PM_*_BIT + * @iprio - 8bit prio from IPRIORITYR + * @itarget - 8bit target from ITARGETR + * @icfg - 2bit configuration from ICFGR and IT_PM_CONFIG_MASK + */ +struct gic_it_pm { + uint16_t it; + uint8_t flags; + uint8_t iprio; + uint8_t itarget; + uint8_t icfg; +}; + +static void gic_pm_add_it(struct gic_data *gd, unsigned int it) +{ + struct gic_pm *pm = &gd->pm; + + pm->count++; + pm->pm_cfg = realloc(pm->pm_cfg, pm->count * sizeof(*pm->pm_cfg)); + if (!pm->pm_cfg) + panic(); + + pm->pm_cfg[pm->count - 1] = (struct gic_it_pm){ .it = it }; +} + +static void gic_save_it(struct gic_data *gd, struct gic_it_pm *pm) +{ + unsigned int it = pm->it; + size_t idx = 0; + uint32_t bit_mask = BIT(it % NUM_INTS_PER_REG); + uint32_t shift2 = it % (NUM_INTS_PER_REG / 2); + uint32_t shift8 = it % (NUM_INTS_PER_REG / 8); + uint32_t data32 = 0; + + pm->flags = 0; + idx = it / NUM_INTS_PER_REG; + + if (io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & bit_mask) + pm->flags |= IT_PM_GPOUP1_BIT; + if (io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & bit_mask) + pm->flags |= IT_PM_ENABLE_BIT; + if (io_read32(gd->gicd_base + GICD_ISPENDR(idx)) & bit_mask) + pm->flags |= IT_PM_PENDING_BIT; + if (io_read32(gd->gicd_base + GICD_ISACTIVER(idx)) & bit_mask) + pm->flags |= IT_PM_ACTIVE_BIT; + + idx = (8 * it) / NUM_INTS_PER_REG; + + data32 = io_read32(gd->gicd_base + GICD_IPRIORITYR(idx)) >> shift8; + pm->iprio = (uint8_t)data32; + + data32 = io_read32(gd->gicd_base + GICD_ITARGETSR(idx)) >> shift8; + pm->itarget = (uint8_t)data32; + + /* Note: ICFGR is RAO for SPIs and PPIs */ + idx = (2 * it) / NUM_INTS_PER_REG; + data32 = io_read32(gd->gicd_base + GICD_ICFGR(idx)) >> shift2; + pm->icfg = (uint8_t)data32 & IT_PM_CONFIG_MASK; +} + +static void gic_restore_it(struct gic_data *gd, struct gic_it_pm *pm) +{ + unsigned int it = pm->it; + size_t idx = it / NUM_INTS_PER_REG; + uint32_t mask = BIT(it % NUM_INTS_PER_REG); + uint32_t shift2 = it % (NUM_INTS_PER_REG / 2); + uint32_t shift8 = it % (NUM_INTS_PER_REG / 8); + + io_mask32(gd->gicd_base + GICD_IGROUPR(idx), + (pm->flags & IT_PM_GPOUP1_BIT) ? mask : 0, mask); + + io_mask32(gd->gicd_base + GICD_ISENABLER(idx), + (pm->flags & IT_PM_ENABLE_BIT) ? mask : 0, mask); + + io_mask32(gd->gicd_base + GICD_ISPENDR(idx), + (pm->flags & IT_PM_PENDING_BIT) ? mask : 0, mask); + + io_mask32(gd->gicd_base + GICD_ISACTIVER(idx), + (pm->flags & IT_PM_ACTIVE_BIT) ? mask : 0, mask); + + idx = (8 * it) / NUM_INTS_PER_REG; + + io_mask32(gd->gicd_base + GICD_IPRIORITYR(idx), + (uint32_t)pm->iprio << shift8, UINT8_MAX << shift8); + + io_mask32(gd->gicd_base + GICD_ITARGETSR(idx), + (uint32_t)pm->itarget << shift8, UINT8_MAX << shift8); + + /* Note: ICFGR is WI for SPIs and PPIs */ + idx = (2 * it) / NUM_INTS_PER_REG; + io_mask32(gd->gicd_base + GICD_ICFGR(idx), + (uint32_t)pm->icfg << shift2, IT_PM_CONFIG_MASK << shift2); +} + +static TEE_Result gic_pm(enum pm_op op, unsigned int pm_hint __unused, + const struct pm_callback_handle *handle) +{ + void (*sequence)(struct gic_data *gd, struct gic_it_pm *pm) = NULL; + struct gic_it_pm *cfg = NULL; + unsigned int n = 0; + struct gic_data *gd = (struct gic_data *)PM_CALLBACK_GET_HANDLE(handle); + struct gic_pm *pm = &gd->pm; + + if (op == PM_OP_SUSPEND) { + sequence = gic_save_it; + } else { + gic_init_setup(gd); + sequence = gic_restore_it; + } + for (n = 0, cfg = pm->pm_cfg; n < pm->count; n++, cfg++) + sequence(gd, cfg); + + return TEE_SUCCESS; +} +DECLARE_KEEP_PAGER(gic_pm); + +static void gic_pm_register(struct gic_data *gd) +{ + register_pm_core_service_cb(gic_pm, gd); +} +#endif /*CFG_ARM_GIC_PM*/ diff --git a/core/drivers/scmi-msg/clock.c b/core/drivers/scmi-msg/clock.c index 6fe62477e..0361f8828 100644 --- a/core/drivers/scmi-msg/clock.c +++ b/core/drivers/scmi-msg/clock.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. * Copyright (c) 2019, Linaro Limited + * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. */ #include #include @@ -357,7 +357,7 @@ static const scmi_msg_handler_t scmi_clock_handler_table[] = { [SCMI_CLOCK_CONFIG_SET] = scmi_clock_config_set, }; -static bool message_id_is_supported(size_t message_id) +static bool message_id_is_supported(unsigned int message_id) { return message_id < ARRAY_SIZE(scmi_clock_handler_table) && scmi_clock_handler_table[message_id]; diff --git a/core/drivers/stm32_bsec.c b/core/drivers/stm32_bsec.c index 2b1584ff5..7d389a061 100644 --- a/core/drivers/stm32_bsec.c +++ b/core/drivers/stm32_bsec.c @@ -91,10 +91,6 @@ #define BSEC_MODE_BIST2_LOCK_MASK BIT(7) /* BSEC_DEBUG */ -#define BSEC_HDPEN BIT(4) -#define BSEC_SPIDEN BIT(5) -#define BSEC_SPINDEN BIT(6) -#define BSEC_DBGSWGEN BIT(10) #define BSEC_DEN_ALL_MSK GENMASK_32(10, 0) /* @@ -546,6 +542,40 @@ bool stm32_bsec_nsec_can_access_otp(uint32_t otp_id) nsec_access_granted(otp_id - otp_upper_base()); } +struct nvmem_layout { + char *name; + uint32_t otp_id; + size_t bit_len; +}; + +static struct nvmem_layout *nvmem_layout; +static size_t nvmem_layout_count; + +TEE_Result stm32_bsec_find_otp_in_nvmem_layout(const char *name, + uint32_t *otp_id, + size_t *otp_bit_len) +{ + size_t i = 0; + + if (!name) + return TEE_ERROR_BAD_PARAMETERS; + + for (i = 0; i < nvmem_layout_count; i++) { + if (!nvmem_layout[i].name || strcmp(name, nvmem_layout[i].name)) + continue; + + if (otp_id) + *otp_id = nvmem_layout[i].otp_id; + + if (otp_bit_len) + *otp_bit_len = nvmem_layout[i].bit_len; + + return TEE_SUCCESS; + } + + return TEE_ERROR_ITEM_NOT_FOUND; +} + #ifdef CFG_DT static void enable_nsec_access(unsigned int otp_id) { @@ -624,6 +654,77 @@ static void bsec_dt_otp_nsec_access(void *fdt, int bsec_node) } } +static void save_dt_nvmem_layout(void *fdt) +{ + const fdt32_t *cells = NULL; + int i = 0; + int cell_nb = 0; + int nvmem_node = 0; + + nvmem_node = fdt_node_offset_by_compatible(fdt, -1, + "st,stm32-nvmem-layout"); + if (nvmem_node < 0) + return; + + cells = fdt_getprop(fdt, nvmem_node, "nvmem-cells", &cell_nb); + if (!cells) + cell_nb = 0; + + cell_nb /= sizeof(uint32_t); + + i = fdt_stringlist_count(fdt, nvmem_node, "nvmem-cell-names"); + if (i < 0) + i = 0; + + if (cell_nb != i) + panic("Inconsistent NVMEM layout"); + + nvmem_layout = calloc(cell_nb, sizeof(*nvmem_layout)); + if (!nvmem_layout) + panic(); + + nvmem_layout_count = (size_t)cell_nb; + + for (i = 0; i < cell_nb; i++) { + const fdt32_t *cuint = NULL; + const char *string = NULL; + int len = 0; + int node = 0; + struct nvmem_layout *layout_cell = &nvmem_layout[i]; + + node = fdt_node_offset_by_phandle(fdt, + fdt32_to_cpu(*(cells + i))); + if (node < 0) { + IMSG("Malformed nvmem_layout node: ignored"); + continue; + } + + cuint = fdt_getprop(fdt, node, "reg", &len); + if (!cuint || (len != (2 * (int)sizeof(uint32_t)))) { + IMSG("Malformed nvmem_layout node: ignored"); + continue; + } + + if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) { + IMSG("Misaligned nvmem_layout element: ignored"); + continue; + } + layout_cell->otp_id = fdt32_to_cpu(*cuint) / sizeof(uint32_t); + layout_cell->bit_len = fdt32_to_cpu(*(cuint + 1)) * CHAR_BIT; + + string = fdt_stringlist_get(fdt, nvmem_node, "nvmem-cell-names", + i, &len); + if (!string || !len) + continue; + + layout_cell->name = calloc(1, len + 1); + if (!layout_cell->name) + panic(); + + memcpy(layout_cell->name, string, len); + } +} + static void initialize_bsec_from_dt(void) { void *fdt = NULL; @@ -642,6 +743,8 @@ static void initialize_bsec_from_dt(void) panic(); bsec_dt_otp_nsec_access(fdt, node); + + save_dt_nvmem_layout(fdt); } #else static void initialize_bsec_from_dt(void) diff --git a/core/drivers/stm32_etzpc.c b/core/drivers/stm32_etzpc.c index 3482f3431..5573503a1 100644 --- a/core/drivers/stm32_etzpc.c +++ b/core/drivers/stm32_etzpc.c @@ -26,10 +26,16 @@ #include #include #include +#include #include /* Devicetree compatibility */ #define ETZPC_COMPAT "st,stm32-etzpc" +#define ETZPC_LOCK_MASK BIT(0) +#define ETZPC_MODE_SHIFT 8 +#define ETZPC_MODE_MASK GENMASK_32(1, 0) +#define ETZPC_ID_SHIFT 16 +#define ETZPC_ID_MASK GENMASK_32(7, 0) /* ID Registers */ #define ETZPC_TZMA0_SIZE 0x000U @@ -316,6 +322,45 @@ void stm32_etzpc_init(paddr_t base) } #ifdef CFG_DT +struct dt_id_attr { + /* The effective size of the array is meaningless here */ + fdt32_t id_attr[1]; +}; + +static void etzpc_dt_conf_decprot(void *fdt, int node) +{ + const struct dt_id_attr *conf_list = NULL; + size_t i = 0; + int len = 0; + + conf_list = (const struct dt_id_attr *)fdt_getprop(fdt, node, + "st,decprot", &len); + if (conf_list == NULL) { + DMSG("No ETZPC DECPROT configuration in DT"); + return; + } + + for (i = 0; i < len / sizeof(uint32_t); i++) { + uint32_t value = fdt32_to_cpu(conf_list->id_attr[i]); + uint32_t id = (value >> ETZPC_ID_SHIFT) & ETZPC_ID_MASK; + uint32_t mode = (value >> ETZPC_MODE_SHIFT) & ETZPC_MODE_MASK; + bool lock = value & ETZPC_LOCK_MASK; + enum etzpc_decprot_attributes attr = ETZPC_DECPROT_MAX; + + if (!valid_decprot_id(id)) { + DMSG("Invalid DECPROT %"PRIu32, id); + panic(); + } + + attr = stm32mp_etzpc_binding2decprot(mode); + stm32mp_register_etzpc_decprot(id, attr); + etzpc_configure_decprot(id, attr); + + if (lock) + etzpc_lock_decprot(id); + } +} + static TEE_Result init_etzpc_from_dt(void) { void *fdt = get_embedded_dt(); @@ -339,6 +384,8 @@ static TEE_Result init_etzpc_from_dt(void) init_device_from_hw_config(&etzpc_dev, pbase); + etzpc_dt_conf_decprot(fdt, node); + return TEE_SUCCESS; } diff --git a/core/drivers/stm32_gpio.c b/core/drivers/stm32_gpio.c index 8f7927d90..83c7b8b4e 100644 --- a/core/drivers/stm32_gpio.c +++ b/core/drivers/stm32_gpio.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) 2017-2019, STMicroelectronics + * Copyright (c) 2017-2020, STMicroelectronics * * STM32 GPIO driver is used as pin controller for stm32mp SoCs. * The driver API is defined in header file stm32_gpio.h. */ #include +#include #include #include #include @@ -54,7 +55,7 @@ static void get_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) vaddr_t base = stm32_get_gpio_bank_base(bank); unsigned int clock = stm32_get_gpio_bank_clock(bank); - stm32_clock_enable(clock); + clk_enable(clock); /* * Save GPIO configuration bits spread over the few bank registers. @@ -84,7 +85,7 @@ static void get_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & GPIO_ALTERNATE_MASK; - stm32_clock_disable(clock); + clk_disable(clock); } /* Apply GPIO (@bank/@pin) configuration described by @cfg */ @@ -94,7 +95,7 @@ static void set_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) unsigned int clock = stm32_get_gpio_bank_clock(bank); uint32_t exceptions = cpu_spin_lock_xsave(&gpio_lock); - stm32_clock_enable(clock); + clk_enable(clock); /* Load GPIO MODE value, 2bit value shifted by twice the pin number */ io_clrsetbits32(base + GPIO_MODER_OFFSET, @@ -129,7 +130,7 @@ static void set_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) /* Load GPIO Output direction confuguration, 1bit */ io_clrsetbits32(base + GPIO_ODR_OFFSET, BIT(pin), cfg->od << pin); - stm32_clock_disable(clock); + clk_disable(clock); cpu_spin_unlock_xrestore(&gpio_lock, exceptions); } @@ -395,12 +396,12 @@ int stm32_gpio_get_input_level(unsigned int bank, unsigned int pin) assert(valid_gpio_config(bank, pin, true)); - stm32_clock_enable(clock); + clk_enable(clock); if (io_read32(base + GPIO_IDR_OFFSET) == BIT(pin)) rc = 1; - stm32_clock_disable(clock); + clk_disable(clock); return rc; } @@ -412,14 +413,14 @@ void stm32_gpio_set_output_level(unsigned int bank, unsigned int pin, int level) assert(valid_gpio_config(bank, pin, false)); - stm32_clock_enable(clock); + clk_enable(clock); if (level) io_write32(base + GPIO_BSRR_OFFSET, BIT(pin)); else io_write32(base + GPIO_BSRR_OFFSET, BIT(pin + 16)); - stm32_clock_disable(clock); + clk_disable(clock); } void stm32_gpio_set_secure_cfg(unsigned int bank, unsigned int pin, bool secure) @@ -428,13 +429,13 @@ void stm32_gpio_set_secure_cfg(unsigned int bank, unsigned int pin, bool secure) unsigned int clock = stm32_get_gpio_bank_clock(bank); uint32_t exceptions = cpu_spin_lock_xsave(&gpio_lock); - stm32_clock_enable(clock); + clk_enable(clock); if (secure) io_setbits32(base + GPIO_SECR_OFFSET, BIT(pin)); else io_clrbits32(base + GPIO_SECR_OFFSET, BIT(pin)); - stm32_clock_disable(clock); + clk_disable(clock); cpu_spin_unlock_xrestore(&gpio_lock, exceptions); } diff --git a/core/drivers/stm32_i2c.c b/core/drivers/stm32_i2c.c index 790a5cab6..2807cc42a 100644 --- a/core/drivers/stm32_i2c.c +++ b/core/drivers/stm32_i2c.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) /* - * Copyright (c) 2017-2019, STMicroelectronics + * Copyright (c) 2017-2020, STMicroelectronics * * The driver API is defined in header file stm32_i2c.h. * @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -313,7 +314,7 @@ static void save_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg) { vaddr_t base = get_base(hi2c); - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); cfg->cr1 = io_read32(base + I2C_CR1); cfg->cr2 = io_read32(base + I2C_CR2); @@ -321,14 +322,14 @@ static void save_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg) cfg->oar2 = io_read32(base + I2C_OAR2); cfg->timingr = io_read32(base + I2C_TIMINGR); - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); } static void restore_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg) { vaddr_t base = get_base(hi2c); - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); io_clrbits32(base + I2C_CR1, I2C_CR1_PE); io_write32(base + I2C_TIMINGR, cfg->timingr & TIMINGR_CLEAR_MASK); @@ -338,7 +339,7 @@ static void restore_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg) io_write32(base + I2C_CR1, cfg->cr1 & ~I2C_CR1_PE); io_setbits32(base + I2C_CR1, cfg->cr1 & I2C_CR1_PE); - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); } static void __maybe_unused dump_cfg(struct i2c_cfg *cfg __maybe_unused) @@ -354,7 +355,7 @@ static void __maybe_unused dump_i2c(struct i2c_handle_s *hi2c) { vaddr_t __maybe_unused base = get_base(hi2c); - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); DMSG("CR1: %#"PRIx32, io_read32(base + I2C_CR1)); DMSG("CR2: %#"PRIx32, io_read32(base + I2C_CR2)); @@ -362,7 +363,7 @@ static void __maybe_unused dump_i2c(struct i2c_handle_s *hi2c) DMSG("OAR2: %#"PRIx32, io_read32(base + I2C_OAR2)); DMSG("TIM: %#"PRIx32, io_read32(base + I2C_TIMINGR)); - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); } /* @@ -597,7 +598,7 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c, assert(i2c_specs_is_consistent()); - clock_src = stm32_clock_get_rate(hi2c->clock); + clock_src = clk_get_rate(hi2c->clock); if (!clock_src) { DMSG("Null I2C clock rate"); return -1; @@ -759,7 +760,7 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c, if (rc) return rc; - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); base = get_base(hi2c); hi2c->i2c_state = I2C_STATE_BUSY; @@ -819,7 +820,7 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c, if (rc) DMSG("I2C analog filter error %d", rc); - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); return rc; } @@ -1074,7 +1075,7 @@ static int i2c_write(struct i2c_handle_s *hi2c, struct i2c_request *request, if (!p_data || !size) return -1; - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000); if (wait_isr_event(hi2c, I2C_ISR_BUSY, 0, timeout_ref)) @@ -1161,7 +1162,7 @@ static int i2c_write(struct i2c_handle_s *hi2c, struct i2c_request *request, rc = 0; bail: - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); return rc; } @@ -1207,7 +1208,7 @@ int stm32_i2c_read_write_membyte(struct i2c_handle_s *hi2c, uint16_t dev_addr, if (hi2c->i2c_state != I2C_STATE_READY || !p_data) return -1; - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_US); if (wait_isr_event(hi2c, I2C_ISR_BUSY, 0, timeout_ref)) @@ -1264,7 +1265,7 @@ int stm32_i2c_read_write_membyte(struct i2c_handle_s *hi2c, uint16_t dev_addr, rc = 0; bail: - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); return rc; } @@ -1297,7 +1298,7 @@ static int i2c_read(struct i2c_handle_s *hi2c, struct i2c_request *request, if (!p_data || !size) return -1; - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000); if (wait_isr_event(hi2c, I2C_ISR_BUSY, 0, timeout_ref)) @@ -1374,7 +1375,7 @@ static int i2c_read(struct i2c_handle_s *hi2c, struct i2c_request *request, rc = 0; bail: - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); return rc; } @@ -1417,7 +1418,7 @@ bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint32_t dev_addr, if (hi2c->i2c_state != I2C_STATE_READY) return rc; - stm32_clock_enable(hi2c->clock); + clk_enable(hi2c->clock); if (io_read32(base + I2C_ISR) & I2C_ISR_BUSY) goto bail; @@ -1489,7 +1490,7 @@ bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint32_t dev_addr, notif_i2c_timeout(hi2c); bail: - stm32_clock_disable(hi2c->clock); + clk_disable(hi2c->clock); return rc; } diff --git a/core/drivers/stm32_iwdg.c b/core/drivers/stm32_iwdg.c new file mode 100644 index 000000000..335d1a2cb --- /dev/null +++ b/core/drivers/stm32_iwdg.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* IWDG Compatibility */ +#define IWDG_COMPAT "st,stm32mp1-iwdg" +#define IWDG_TIMEOUT_US 100000U + +/* IWDG registers offsets */ +#define IWDG_KR_OFFSET 0x00U +#define IWDG_PR_OFFSET 0x04U +#define IWDG_RLR_OFFSET 0x08U +#define IWDG_SR_OFFSET 0x0CU +#define IWDG_EWCR_OFFSET 0x14U + +/* Registers values */ +#define IWDG_KR_ACCESS_KEY 0x5555 +#define IWDG_KR_RELOAD_KEY 0xAAAA +#define IWDG_KR_START_KEY 0xCCCC + +#define IWDG_PR_DIV_4 0x00 +#define IWDG_PR_DIV_256 0x06 + +#define IWDG_RLR_MAX_VAL 0xFFF + +#define IWDG_SR_EWU BIT(3) + +#define IWDG_EWCR_EWIE BIT(15) +#define IWDG_EWCR_EWIC BIT(14) +#define IWDG_EWCR_EWIT_MASK GENMASK_32(11, 0) + +struct stm32_iwdg_instance { + struct io_pa_va base; + unsigned long clock; + uint8_t instance; + uint8_t flags; +}; + +static struct stm32_iwdg_instance *stm32_iwdg; +static size_t stm32_iwdg_count; + +static vaddr_t get_base(struct stm32_iwdg_instance *iwdg) +{ + return io_pa_or_va(&iwdg->base); +} + +static int stm32_iwdg_get_dt_node(void *fdt, struct dt_node_info *info, + int offset) +{ + int node = fdt_node_offset_by_compatible(fdt, offset, IWDG_COMPAT); + + if (node < 0) { + if (offset == -1) + DMSG("No IDWG found"); + + return -FDT_ERR_NOTFOUND; + } + + _fdt_fill_device_info(fdt, info, node); + + return node; +} + +static struct stm32_iwdg_instance *get_iwdg(unsigned int instance) +{ + size_t i = 0; + + assert(instance <= UINT8_MAX); + for (i = 0; i < stm32_iwdg_count; i++) + if (stm32_iwdg[i].instance == instance) + return &stm32_iwdg[i]; + + return NULL; +} + +static enum itr_return stm32_iwdg_it_handler(struct itr_handler *handler) +{ + unsigned int __maybe_unused cpu = get_core_pos(); + unsigned int instance = stm32mp_iwdg_irq2instance(handler->it); + struct stm32_iwdg_instance *iwdg = get_iwdg(instance); + vaddr_t iwdg_base = get_base(iwdg); + + DMSG("CPU %u IT Watchdog %d\n", cpu, instance + 1); + + stm32_iwdg_refresh(instance); + + clk_enable(iwdg->clock); + + io_setbits32(iwdg_base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIC); + + clk_disable(iwdg->clock); + +#ifdef CFG_PM + /* + * Ack interrupt as we do not return from next call. + * And interrupt is no more considered as pending here. + */ + stm32mp_gic_set_end_of_interrupt(handler->it); + + stm32_cores_reset(); +#else + panic("Watchdog"); +#endif + + return ITRR_HANDLED; +} +DECLARE_KEEP_PAGER(stm32_iwdg_it_handler); + +static int stm32_iwdg_get_secure_timeout(void *fdt, int node) +{ + const fdt32_t *cuint = NULL; + + cuint = fdt_getprop(fdt, node, "secure-timeout-sec", NULL); + if (!cuint) + return -1; + + return (int)fdt32_to_cpu(*cuint); +} + +static int fdt_get_clock_id_by_name(void *fdt, int node, const char *name) +{ + const fdt32_t *cuint = NULL; + int index = 0; + int len = 0; + + index = fdt_stringlist_search(fdt, node, "clock-names", name); + if (index < 0) + return index; + + cuint = fdt_getprop(fdt, node, "clocks", &len); + if (!cuint) + return -FDT_ERR_NOTFOUND; + + if ((index * (int)sizeof(uint32_t)) > len) + return -FDT_ERR_BADVALUE; + + cuint += (index << 1) + 1; + return (int)fdt32_to_cpu(*cuint); +} + +static TEE_Result stm32_iwdg_conf_etimeout(void *fdt, int node, + struct stm32_iwdg_instance *iwdg) +{ + int id_lsi = 0; + int dt_secure_timeout = stm32_iwdg_get_secure_timeout(fdt, node); + uint32_t reload = 0; + uint32_t status = 0; + uint64_t timeout_ref = 0; + unsigned long long reload_ll = 0; + vaddr_t iwdg_base = get_base(iwdg); + struct itr_handler *itr = NULL; + + if (dt_secure_timeout < 0) + return TEE_SUCCESS; + + if (dt_secure_timeout == 0) + return TEE_ERROR_GENERIC; + + id_lsi = fdt_get_clock_id_by_name(fdt, node, "lsi"); + if (id_lsi < 0) + return TEE_ERROR_GENERIC; + + /* Prescaler fix to 256 */ + reload_ll = (unsigned long long)dt_secure_timeout * + clk_get_rate(id_lsi); + reload = ((uint32_t)(reload_ll >> 8) - 1) & IWDG_EWCR_EWIT_MASK; + + clk_enable(iwdg->clock); + + io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_START_KEY); + io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY); + io_write32(iwdg_base + IWDG_PR_OFFSET, IWDG_PR_DIV_256); + io_write32(iwdg_base + IWDG_EWCR_OFFSET, reload | IWDG_EWCR_EWIE); + + timeout_ref = timeout_init_us(IWDG_TIMEOUT_US); + while (!timeout_elapsed(timeout_ref)) + if (!(io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_EWU)) + break; + + status = io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_EWU; + clk_disable(iwdg->clock); + if (status) + return TEE_ERROR_GENERIC; + + itr = calloc(1, sizeof(*itr)); + if (!itr) + panic("out of memory"); + + itr->it = stm32mp_iwdg_instance2irq(iwdg->instance); + itr->handler = stm32_iwdg_it_handler; + itr_add(itr); + itr_enable(itr->it); + + return TEE_SUCCESS; +} + +void stm32_iwdg_refresh(unsigned int instance) +{ + struct stm32_iwdg_instance *iwdg = get_iwdg(instance); + + if (!iwdg) + return; + + clk_enable(iwdg->clock); + + io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY); + + clk_disable(iwdg->clock); +} + +static TEE_Result iwdg_init(void) +{ + int node = -1; + TEE_Result res = TEE_ERROR_GENERIC; + struct dt_node_info dt_info = { }; + void *fdt = NULL; + size_t count = 0; + + fdt = get_embedded_dt(); + if (!fdt) + panic(); + + assert(!stm32_iwdg && !stm32_iwdg_count); + + for (node = stm32_iwdg_get_dt_node(fdt, &dt_info, node); + node != -FDT_ERR_NOTFOUND; + node = stm32_iwdg_get_dt_node(fdt, &dt_info, node)) { + struct stm32_iwdg_instance iwdg = { }; + enum teecore_memtypes memtype = MEM_AREA_MAXTYPE; + uint32_t hw_init = 0; + + iwdg.base.pa = dt_info.reg; + iwdg.clock = (unsigned long)dt_info.clock; + iwdg.instance = stm32mp_iwdg_iomem2instance(iwdg.base.pa); + + memtype = ((dt_info.status & DT_STATUS_OK_NSEC) != 0) ? + MEM_AREA_IO_NSEC : MEM_AREA_IO_SEC; + iwdg.base.va = (vaddr_t)phys_to_virt(iwdg.base.pa, memtype); + + /* DT can specify low power cases */ + if (!fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL)) + iwdg.flags |= IWDG_DISABLE_ON_STOP; + + if (!fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL)) + iwdg.flags |= IWDG_DISABLE_ON_STANDBY; + + hw_init = stm32_get_iwdg_otp_config(iwdg.base.pa); + + if (hw_init & IWDG_HW_ENABLED) { + if (dt_info.status == DT_STATUS_DISABLED) + panic("IWDG HW enabled"); + + iwdg.flags |= IWDG_HW_ENABLED; + } + + if (hw_init & IWDG_DISABLE_ON_STOP) + iwdg.flags |= IWDG_DISABLE_ON_STOP; + + if (hw_init & IWDG_DISABLE_ON_STANDBY) + iwdg.flags |= IWDG_DISABLE_ON_STANDBY; + + if (dt_info.status == DT_STATUS_DISABLED) + continue; + + DMSG("IWDG%u found, %ssecure", iwdg.instance + 1, + (dt_info.status & DT_STATUS_OK_NSEC) ? "non-" : ""); + + if (dt_info.status & DT_STATUS_OK_NSEC) + stm32mp_register_non_secure_periph_iomem(iwdg.base.pa); + else + stm32mp_register_secure_periph_iomem(iwdg.base.pa); + + res = stm32_iwdg_conf_etimeout(fdt, node, &iwdg); + if (res) { + EMSG("IWDG%x early timeout config failed (%d)\n", + iwdg.instance + 1, res); + panic(); + } + + stm32_iwdg = realloc(stm32_iwdg, (count + 1) * sizeof(iwdg)); + if (!stm32_iwdg) + panic("out of memory"); + + memcpy(&stm32_iwdg[count], &iwdg, sizeof(iwdg)); + count++; + } + + stm32_iwdg_count = count; + + DMSG("%u IWDG instance%s found", count, count > 1 ? "s" : ""); + + return TEE_SUCCESS; +} +driver_init(iwdg_init); diff --git a/core/drivers/stm32_rng.c b/core/drivers/stm32_rng.c index d55f28f19..e95bde8ad 100644 --- a/core/drivers/stm32_rng.c +++ b/core/drivers/stm32_rng.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause /* - * Copyright (c) 2018-2019, STMicroelectronics + * Copyright (c) 2018-2020, STMicroelectronics */ #include +#include #include #include #include @@ -129,7 +130,7 @@ static void gate_rng(bool enable, struct stm32_rng_instance *dev) if (enable) { /* incr_refcnt return non zero if resource shall be enabled */ if (incr_refcnt(&dev->refcount)) { - stm32_clock_enable(dev->clock); + clk_enable(dev->clock); io_write32(rng_cr, 0); io_write32(rng_cr, RNG_CR_RNGEN | RNG_CR_CED); } @@ -137,7 +138,7 @@ static void gate_rng(bool enable, struct stm32_rng_instance *dev) /* decr_refcnt return non zero if resource shall be disabled */ if (decr_refcnt(&dev->refcount)) { io_write32(rng_cr, 0); - stm32_clock_disable(dev->clock); + clk_disable(dev->clock); } } diff --git a/core/drivers/stm32_rtc.c b/core/drivers/stm32_rtc.c new file mode 100644 index 000000000..79ab627e6 --- /dev/null +++ b/core/drivers/stm32_rtc.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTC_COMPAT "st,stm32mp1-rtc" + +#define RTC_TR 0x00 +#define RTC_DR 0x04 +#define RTC_SSR 0x08 +#define RTC_ICSR 0x0C +#define RTC_PRER 0x10 +#define RTC_WUTR 0x14 +#define RTC_CR 0x18 +#define RTC_SMCR 0x20 +#define RTC_WPR 0x24 +#define RTC_CALR 0x28 +#define RTC_SHIFTR 0x2C +#define RTC_TSTR 0x30 +#define RTC_TSDR 0x34 +#define RTC_TSSSR 0x38 +#define RTC_ALRMAR 0x40 +#define RTC_ALRMASSR 0x44 +#define RTC_ALRMBR 0x48 +#define RTC_ALRMBSSR 0x4C +#define RTC_SR 0x50 +#define RTC_SCR 0x5C +#define RTC_OR 0x60 + +#define RTC_TR_SU_MASK GENMASK_32(3, 0) +#define RTC_TR_ST_MASK GENMASK_32(6, 4) +#define RTC_TR_ST_SHIFT 4 +#define RTC_TR_MNU_MASK GENMASK_32(11, 8) +#define RTC_TR_MNU_SHIFT 8 +#define RTC_TR_MNT_MASK GENMASK_32(14, 12) +#define RTC_TR_MNT_SHIFT 12 +#define RTC_TR_HU_MASK GENMASK_32(19, 16) +#define RTC_TR_HU_SHIFT 16 +#define RTC_TR_HT_MASK GENMASK_32(21, 20) +#define RTC_TR_HT_SHIFT 20 +#define RTC_TR_PM BIT(22) + +#define RTC_DR_DU_MASK GENMASK_32(3, 0) +#define RTC_DR_DT_MASK GENMASK_32(5, 4) +#define RTC_DR_DT_SHIFT 4 +#define RTC_DR_MU_MASK GENMASK_32(11, 8) +#define RTC_DR_MU_SHIFT 8 +#define RTC_DR_MT BIT(12) +#define RTC_DR_MT_SHIFT 12 +#define RTC_DR_WDU_MASK GENMASK_32(15, 13) +#define RTC_DR_WDU_SHIFT 13 +#define RTC_DR_YU_MASK GENMASK_32(19, 16) +#define RTC_DR_YU_SHIFT 16 +#define RTC_DR_YT_MASK GENMASK_32(23, 20) +#define RTC_DR_YT_SHIFT 20 + +#define RTC_SSR_SS_MASK GENMASK_32(15, 0) + +#define RTC_ICSR_RSF BIT(5) + +#define RTC_PRER_PREDIV_S_MASK GENMASK_32(15, 0) + +#define RTC_CR_BYPSHAD BIT(5) +#define RTC_CR_BYPSHAD_SHIFT 5 +#define RTC_CR_TAMPTS BIT(25) + +#define RTC_SMCR_TS_DPROT BIT(3) +#define RTC_SR_TSF BIT(3) +#define RTC_SCR_CTSF BIT(3) +#define RTC_SR_TSOVF BIT(4) +#define RTC_SCR_CTSOVF BIT(4) + +#define RTC_TSDR_MU_MASK GENMASK_32(11, 8) +#define RTC_TSDR_MU_SHIFT 8 +#define RTC_TSDR_DT_MASK GENMASK_32(5, 4) +#define RTC_TSDR_DT_SHIFT 4 +#define RTC_TSDR_DU_MASK GENMASK_32(3, 0) +#define RTC_TSDR_DU_SHIFT 0 + +#define RTC_WPR_KEY1 0xCA +#define RTC_WPR_KEY2 0x53 +#define RTC_WPR_KEY_LOCK 0xFF + +#define RTC_FLAGS_READ_TWICE BIT(0) +#define RTC_FLAGS_SECURE BIT(1) + +struct rtc_device { + struct io_pa_va base; + uint16_t clock; + uint8_t flags; +}; + +/* Expect a single RTC instance */ +struct rtc_device rtc_dev; + +static vaddr_t get_base(void) +{ + assert(rtc_dev.base.pa); + return io_pa_or_va(&rtc_dev.base); +} + +static void stm32_rtc_write_unprotect(void) +{ + vaddr_t rtc_base = get_base(); + + io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY1); + io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY2); +} + +static void stm32_rtc_write_protect(void) +{ + vaddr_t rtc_base = get_base(); + + io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY_LOCK); +} + +static bool stm32_rtc_get_bypshad(void) +{ + return io_read32(get_base() + RTC_CR) & RTC_CR_BYPSHAD; +} + +/* Get calendar data from RTC devicecalendar valueregister values */ +static void stm32_rtc_read_calendar(struct stm32_rtc_calendar *calendar) +{ + vaddr_t rtc_base = get_base(); + bool bypshad = stm32_rtc_get_bypshad(); + + if (!bypshad) { + /* Shadow RTC registers */ + io_clrbits32(rtc_base + RTC_ICSR, RTC_ICSR_RSF); + while (!(io_read32(rtc_base + RTC_ICSR) & RTC_ICSR_RSF)) + ; + } + + calendar->ssr = io_read32(rtc_base + RTC_SSR); + calendar->tr = io_read32(rtc_base + RTC_TR); + calendar->dr = io_read32(rtc_base + RTC_DR); +} + +/* Fill the RTC timestamp structure from a given RTC time-in-day value */ +static void stm32_rtc_get_time(struct stm32_rtc_calendar *cal, + struct stm32_rtc_time *tm) +{ + tm->hour = (((cal->tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10) + + ((cal->tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT); + + if (cal->tr & RTC_TR_PM) + tm->hour += 12; + + tm->min = (((cal->tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10) + + ((cal->tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT); + tm->sec = (((cal->tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10) + + (cal->tr & RTC_TR_SU_MASK); +} + +/* Fill the RTC timestamp structure from a given RTC date value */ +static void stm32_rtc_get_date(struct stm32_rtc_calendar *cal, + struct stm32_rtc_time *tm) +{ + tm->wday = (((cal->dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT)); + + tm->day = (((cal->dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10) + + (cal->dr & RTC_DR_DU_MASK); + + tm->month = (((cal->dr & RTC_DR_MT) >> RTC_DR_MT_SHIFT) * 10) + + ((cal->dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT); + + tm->year = (((cal->dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10) + + ((cal->dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + 2000; +} + +/* Update time value with RTC timestamp */ +static void stm32_rtc_read_timestamp(struct stm32_rtc_time *time) +{ + struct stm32_rtc_calendar cal_tamp = { }; + vaddr_t rtc_base = get_base(); + + cal_tamp.tr = io_read32(rtc_base + RTC_TSTR); + cal_tamp.dr = io_read32(rtc_base + RTC_TSDR); + stm32_rtc_get_time(&cal_tamp, time); + stm32_rtc_get_date(&cal_tamp, time); +} + +void stm32_rtc_get_calendar(struct stm32_rtc_calendar *calendar) +{ + clk_enable(rtc_dev.clock); + + stm32_rtc_read_calendar(calendar); + + /* RTC may need to be read twice, depending of clocks configuration */ + if (rtc_dev.flags & RTC_FLAGS_READ_TWICE) { + uint32_t tr_save = calendar->tr; + + stm32_rtc_read_calendar(calendar); + + if (calendar->tr != tr_save) + stm32_rtc_read_calendar(calendar); + } + + clk_disable(rtc_dev.clock); +} + +/* Return difference in milliseconds on second fraction */ +static uint32_t stm32_rtc_get_second_fraction(struct stm32_rtc_calendar *cal) +{ + uint32_t prediv_s = io_read32(get_base() + RTC_PRER) & + RTC_PRER_PREDIV_S_MASK; + uint32_t ss = cal->ssr & RTC_SSR_SS_MASK; + + return ((prediv_s - ss) * 1000) / (prediv_s + 1); +} + +/* Return absolute difference in milliseconds on second fraction */ +static signed long long stm32_rtc_diff_frac(struct stm32_rtc_calendar *cur, + struct stm32_rtc_calendar *ref) +{ + return (signed long long)stm32_rtc_get_second_fraction(cur) - + (signed long long)stm32_rtc_get_second_fraction(ref); +} + +/* Return absolute difference in milliseconds on seconds-in-day fraction */ +static signed long long stm32_rtc_diff_time(struct stm32_rtc_time *current, + struct stm32_rtc_time *ref) +{ + signed long long curr_s = 0; + signed long long ref_s = 0; + + curr_s = (signed long long)current->sec + + (((signed long long)current->min + + (((signed long long)current->hour * 60))) * 60); + + ref_s = (signed long long)ref->sec + + (((signed long long)ref->min + + (((signed long long)ref->hour * 60))) * 60); + + return (curr_s - ref_s) * 1000U; +} + +static bool stm32_is_a_leap_year(uint32_t year) +{ + return ((year % 4) == 0) && + (((year % 100) != 0) || ((year % 400) == 0)); +} + +/* Return absolute difference in milliseconds on day-in-year fraction */ +static signed long long stm32_rtc_diff_date(struct stm32_rtc_time *current, + struct stm32_rtc_time *ref) +{ + uint32_t diff_in_days = 0; + uint32_t m = 0; + const uint8_t month_len[NB_MONTHS] = { + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 + }; + + /* Get the number of non-entire month days */ + if (current->day >= ref->day) + diff_in_days += current->day - ref->day; + else + diff_in_days += month_len[ref->month - 1] - + ref->day + current->day; + + /* Get the number of entire months, and compute the related days */ + if (current->month > (ref->month + 1)) + for (m = ref->month + 1; m < current->month && m < 12; m++) + diff_in_days += month_len[m - 1]; + + if (current->month < (ref->month - 1)) { + for (m = 1; m < current->month && m < 12; m++) + diff_in_days += month_len[m - 1]; + + for (m = ref->month + 1; m < 12; m++) + diff_in_days += month_len[m - 1]; + } + + /* Get complete years */ + if (current->year > (ref->year + 1)) + diff_in_days += (current->year - ref->year - 1) * 365; + + /* Particular cases: leap years (one day more) */ + if (diff_in_days > 0) { + if (current->year == ref->year) { + if (stm32_is_a_leap_year(current->year) && + ref->month <= 2 && + current->month >= 3 && current->day <= 28) + diff_in_days++; + } else { + uint32_t y = 0; + + /* Ref year is leap */ + if (stm32_is_a_leap_year(ref->year) && + ref->month <= 2 && ref->day <= 28) + diff_in_days++; + + /* Current year is leap */ + if (stm32_is_a_leap_year(current->year) && + current->month >= 3) + diff_in_days++; + + /* Interleaved years are leap */ + for (y = ref->year + 1; y < current->year; y++) + if (stm32_is_a_leap_year(y)) + diff_in_days++; + } + } + + return (24 * 60 * 60 * 1000) * (signed long long)diff_in_days; +} + +unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur, + struct stm32_rtc_calendar *ref) +{ + signed long long diff_in_ms = 0; + struct stm32_rtc_time curr_t = { }; + struct stm32_rtc_time ref_t = { }; + + stm32_rtc_get_date(cur, &curr_t); + stm32_rtc_get_date(ref, &ref_t); + stm32_rtc_get_time(cur, &curr_t); + stm32_rtc_get_time(ref, &ref_t); + + diff_in_ms += stm32_rtc_diff_frac(cur, ref); + diff_in_ms += stm32_rtc_diff_time(&curr_t, &ref_t); + diff_in_ms += stm32_rtc_diff_date(&curr_t, &ref_t); + + return (unsigned long long)diff_in_ms; +} + +void stm32_rtc_get_timestamp(struct stm32_rtc_time *tamp_ts) +{ + vaddr_t rtc_base = get_base(); + + clk_enable(rtc_dev.clock); + + if (io_read32(rtc_base + RTC_SR) & RTC_SR_TSF) { + /* Timestamp for tamper event */ + stm32_rtc_read_timestamp(tamp_ts); + io_setbits32(rtc_base + RTC_SCR, RTC_SCR_CTSF); + + /* Overflow detection */ + if (io_read32(rtc_base + RTC_SR) & RTC_SR_TSOVF) + io_setbits32(rtc_base + RTC_SCR, RTC_SCR_CTSOVF); + } + + clk_disable(rtc_dev.clock); +} + +void stm32_rtc_set_tamper_timestamp(void) +{ + vaddr_t rtc_base = get_base(); + + clk_enable(rtc_dev.clock); + + stm32_rtc_write_unprotect(); + + /* Enable tamper timestamper */ + io_setbits32(rtc_base + RTC_CR, RTC_CR_TAMPTS); + + /* Secure Timestamp bit */ + io_clrbits32(rtc_base + RTC_SMCR, RTC_SMCR_TS_DPROT); + + stm32_rtc_write_protect(); + + clk_disable(rtc_dev.clock); +} + +bool stm32_rtc_is_timestamp_enable(void) +{ + bool ret = false; + + clk_enable(rtc_dev.clock); + + ret = io_read32(get_base() + RTC_CR) & RTC_CR_TAMPTS; + + clk_disable(rtc_dev.clock); + + return ret; +} + +#ifdef CFG_DT +static unsigned int get_second_clock(void *fdt, int offs) +{ + const fdt32_t *cuint = NULL; + int len = 0; + + cuint = fdt_getprop(fdt, offs, "clocks", &len); + if (len == 3) { + EMSG("RTC expects 2 clocks, %d found", len); + return DT_INFO_INVALID_CLOCK; + } + + return fdt32_to_cpu(*(cuint + 3)); +} + +static TEE_Result stm32_rtc_init(void) +{ + int node = 0; + struct dt_node_info dt_info = { }; + void *fdt = get_embedded_dt(); + + if (!fdt) + panic(); + + node = fdt_node_offset_by_compatible(fdt, -1, RTC_COMPAT); + if (node < 0) + return TEE_SUCCESS; + + _fdt_fill_device_info(fdt, &dt_info, node); + + rtc_dev.base.pa = dt_info.reg; + + if (dt_info.status == DT_STATUS_OK_SEC) { + rtc_dev.flags |= RTC_FLAGS_SECURE; + stm32mp_register_secure_periph_iomem(rtc_dev.base.pa); + rtc_dev.base.va = (vaddr_t)phys_to_virt(rtc_dev.base.pa, + MEM_AREA_IO_SEC); + /* Unbalanced clock enable: keep RTC running */ + clk_enable(get_second_clock(fdt, node)); + } else { + stm32mp_register_non_secure_periph_iomem(rtc_dev.base.pa); + rtc_dev.base.va = (vaddr_t)phys_to_virt(rtc_dev.base.pa, + MEM_AREA_IO_NSEC); + } + + rtc_dev.clock = (unsigned long)dt_info.clock; + + if (stm32_rtc_get_read_twice()) + rtc_dev.flags |= RTC_FLAGS_READ_TWICE; + + return 0; +} +driver_init(stm32_rtc_init); +#endif diff --git a/core/drivers/stm32_tim.c b/core/drivers/stm32_tim.c new file mode 100644 index 000000000..635e13824 --- /dev/null +++ b/core/drivers/stm32_tim.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2018-2020, STMicroelectronics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIM_CR1 0x00 /* Control Register 1 */ +#define TIM_CR2 0x04 /* Control Register 2 */ +#define TIM_SMCR 0x08 /* Slave mode control reg */ +#define TIM_DIER 0x0C /* DMA/interrupt register */ +#define TIM_SR 0x10 /* Status register */ +#define TIM_EGR 0x14 /* Event Generation Reg */ +#define TIM_CCMR1 0x18 /* Capt/Comp 1 Mode Reg */ +#define TIM_CCMR2 0x1C /* Capt/Comp 2 Mode Reg */ +#define TIM_CCER 0x20 /* Capt/Comp Enable Reg */ +#define TIM_CNT 0x24 /* Counter */ +#define TIM_PSC 0x28 /* Prescaler */ +#define TIM_ARR 0x2C /* Auto-Reload Register */ +#define TIM_CCR1 0x34 /* Capt/Comp Register 1 */ +#define TIM_CCR2 0x38 /* Capt/Comp Register 2 */ +#define TIM_CCR3 0x3C /* Capt/Comp Register 3 */ +#define TIM_CCR4 0x40 /* Capt/Comp Register 4 */ +#define TIM_BDTR 0x44 /* Break and Dead-Time Reg */ +#define TIM_DCR 0x48 /* DMA control register */ +#define TIM_DMAR 0x4C /* DMA transfer register */ +#define TIM_AF1 0x60 /* Alt Function Reg 1 */ +#define TIM_AF2 0x64 /* Alt Function Reg 2 */ +#define TIM_TISEL 0x68 /* Input Selection */ + +#define TIM_CR1_CEN BIT(0) +#define TIM_SMCR_SMS GENMASK_32(2, 0) /* Slave mode selection */ +#define TIM_SMCR_TS GENMASK_32(6, 4) /* Trigger selection */ +#define TIM_CCMR_CC1S_TI1 BIT(0) /* IC1/IC3 selects TI1/TI3 */ +#define TIM_CCMR_CC1S_TI2 BIT(1) /* IC1/IC3 selects TI2/TI4 */ +#define TIM_CCMR_CC2S_TI2 BIT(8) /* IC2/IC4 selects TI2/TI4 */ +#define TIM_CCMR_CC2S_TI1 BIT(9) /* IC2/IC4 selects TI1/TI3 */ +#define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */ +#define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */ +#define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */ +#define TIM_SR_UIF BIT(0) /* UIF interrupt flag */ +#define TIM_SR_CC1IF BIT(1) /* CC1 interrupt flag */ +#define TIM_TISEL_TI1SEL_MASK GENMASK_32(3, 0) +#define TIM_SMCR_SMS_RESET BIT(2) +#define TIM_SMCR_TS_SHIFT 4 +#define TIM_SMCR_TS_TI1FP1 0x5 + +#define TIM_COMPAT "st,stm32-timers" +#define TIM_TIMEOUT_US 100000 +#define TIM_TIMEOUT_STEP_US 10 +#define TIM_PRESCAL_HSI 10 +#define TIM_PRESCAL_CSI 7 +#define TIM_MIN_FREQ_CALIB 50000000U +#define TIM_THRESHOLD 1U + +struct stm32_tim_instance { + struct io_pa_va base; + unsigned long clk; + unsigned long freq; + uint8_t cal_input; +}; + +static vaddr_t timer_base(struct stm32_tim_instance *timer) +{ + return io_pa_or_va(&timer->base); +} + +/* Currently support HSI and CSI calibratrion */ +#define TIM_MAX_INSTANCE 2 +static struct stm32_tim_instance stm32_tim[TIM_MAX_INSTANCE]; + +static int timer_get_dt_node(void *fdt, struct dt_node_info *info, int offset) +{ + int node = fdt_node_offset_by_compatible(fdt, offset, TIM_COMPAT); + + if (node < 0) + return -FDT_ERR_NOTFOUND; + + _fdt_fill_device_info(fdt, info, node); + + return node; +} + +static int timer_config(struct stm32_tim_instance *timer) +{ + vaddr_t base = timer_base(timer); + + clk_enable(timer->clk); + + timer->freq = clk_get_rate(timer->clk); + if (timer->freq < TIM_MIN_FREQ_CALIB) { + EMSG("Calibration: timer not accurate enough"); + clk_disable(timer->clk); + return -1; + } + + if ((io_read32(base + TIM_TISEL) & TIM_TISEL_TI1SEL_MASK) != + timer->cal_input) { + io_clrsetbits32(base + TIM_CCMR1, + TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC1S_TI2, + TIM_CCMR_CC1S_TI1); + + io_clrbits32(base + TIM_CCER, + TIM_CCER_CC1P | TIM_CCER_CC1NP); + + io_clrsetbits32(base + TIM_SMCR, + TIM_SMCR_TS | TIM_SMCR_SMS, + (TIM_SMCR_TS_TI1FP1 << TIM_SMCR_TS_SHIFT) | + TIM_SMCR_SMS_RESET); + + io_write32(base + TIM_TISEL, timer->cal_input); + io_setbits32(base + TIM_CR1, TIM_CR1_CEN); + io_setbits32(base + TIM_CCER, TIM_CCER_CC1E); + } + + clk_disable(timer->clk); + + return 0; +} + +static uint32_t timer_start_capture(struct stm32_tim_instance *timer) +{ + uint64_t timeout_ref = 0; + uint64_t timeout_conv = 0; + uint32_t counter = 0; + uint32_t old_counter = 0; + vaddr_t base = timer_base(timer); + + if (timer_config(timer)) + return 0; + + clk_enable(timer->clk); + + io_write32(base + TIM_SR, 0); + + timeout_ref = timeout_init_us(TIM_TIMEOUT_US / TIM_TIMEOUT_STEP_US); + + while (!timeout_elapsed(timeout_ref)) + if (io_read32(base + TIM_SR) & TIM_SR_UIF) + break; + if (!(io_read32(base + TIM_SR) & TIM_SR_UIF)) + goto bail; + + io_write32(base + TIM_SR, 0); + + timeout_conv = timeout_init_us(TIM_TIMEOUT_US); + + do { + if (timeout_elapsed(timeout_conv)) { + counter = 0; + goto bail; + } + + timeout_ref = timeout_init_us(TIM_TIMEOUT_US / + TIM_TIMEOUT_STEP_US); + while (!timeout_elapsed(timeout_ref)) + if (io_read32(base + TIM_SR) & TIM_SR_CC1IF) + break; + + if (!(io_read32(base + TIM_SR) & TIM_SR_CC1IF)) { + counter = 0; + goto bail; + } + + old_counter = counter; + counter = io_read32(base + TIM_CCR1); + } while (MAX(counter, old_counter) - MIN(counter, old_counter) > + TIM_THRESHOLD); + +bail: + clk_disable(timer->clk); + + return counter; +} + +unsigned long stm32_tim_hsi_freq(void) +{ + struct stm32_tim_instance *timer = &stm32_tim[HSI_CAL]; + uint32_t counter = 0; + + if (timer->base.pa) + counter = timer_start_capture(timer); + + if (!counter) + return 0; + + return (timer->freq / counter) << TIM_PRESCAL_HSI; +} +DECLARE_KEEP_PAGER(stm32_tim_hsi_freq); + +unsigned long stm32_tim_csi_freq(void) +{ + struct stm32_tim_instance *timer = &stm32_tim[CSI_CAL]; + uint32_t counter = 0; + + if (timer->base.pa) + counter = timer_start_capture(timer); + + if (!counter) + return 0; + + return (timer->freq / counter) << TIM_PRESCAL_CSI; +} +DECLARE_KEEP_PAGER(stm32_tim_csi_freq); + +static void _init_stm32_tim(void) +{ + void *fdt = get_embedded_dt(); + struct dt_node_info dt_timer = { }; + int node = -1; + static bool inited; + + if (inited) + return; + inited = true; + + if (!fdt) + panic(); + + for (node = timer_get_dt_node(fdt, &dt_timer, node); + node != -FDT_ERR_NOTFOUND; + node = timer_get_dt_node(fdt, &dt_timer, node)) { + struct stm32_tim_instance *timer = NULL; + const uint32_t *cuint = NULL; + + if (!(dt_timer.status & DT_STATUS_OK_SEC)) + continue; + + cuint = fdt_getprop(fdt, node, "st,hsi-cal-input", NULL); + if (cuint) { + timer = &stm32_tim[HSI_CAL]; + timer->base.pa = dt_timer.reg; + timer->clk = dt_timer.clock; + timer->freq = clk_get_rate(timer->clk); + timer->cal_input = fdt32_to_cpu(*cuint); + if (timer_config(timer)) { + timer->base.pa = 0; + continue; + } + } + + cuint = fdt_getprop(fdt, node, "st,csi-cal-input", NULL); + if (cuint) { + timer = &stm32_tim[CSI_CAL]; + timer->base.pa = dt_timer.reg; + timer->clk = dt_timer.clock; + timer->freq = clk_get_rate(timer->clk); + timer->cal_input = fdt32_to_cpu(*cuint); + if (timer_config(timer)) { + timer->base.pa = 0; + continue; + } + } + } +} + +void stm32_tim_freq_func(unsigned long (**timer_freq_cb)(void), + enum stm32_tim_cal type) +{ + _init_stm32_tim(); + + *timer_freq_cb = NULL; + + switch (type) { + case HSI_CAL: + if (stm32_tim[HSI_CAL].base.pa) + *timer_freq_cb = stm32_tim_hsi_freq; + break; + + case CSI_CAL: + if (stm32_tim[CSI_CAL].base.pa) + *timer_freq_cb = stm32_tim_csi_freq; + break; + default: + panic(); + } +} + +static TEE_Result init_stm32_tim(void) +{ + _init_stm32_tim(); + + return TEE_SUCCESS; +} +driver_init(init_stm32_tim); diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk index 25d69eea8..0d3b81e21 100644 --- a/core/drivers/sub.mk +++ b/core/drivers/sub.mk @@ -26,13 +26,17 @@ srcs-$(CFG_STM32_BSEC) += stm32_bsec.c srcs-$(CFG_STM32_ETZPC) += stm32_etzpc.c srcs-$(CFG_STM32_GPIO) += stm32_gpio.c srcs-$(CFG_STM32_I2C) += stm32_i2c.c +srcs-$(CFG_STM32_IWDG) += stm32_iwdg.c srcs-$(CFG_STM32_RNG) += stm32_rng.c +srcs-$(CFG_STM32_RTC) += stm32_rtc.c +srcs-$(CFG_STM32_TIM) += stm32_tim.c srcs-$(CFG_STM32_UART) += stm32_uart.c srcs-$(CFG_STPMIC1) += stpmic1.c srcs-$(CFG_BCM_HWRNG) += bcm_hwrng.c srcs-$(CFG_BCM_SOTP) += bcm_sotp.c srcs-$(CFG_BCM_GPIO) += bcm_gpio.c +subdirs-y += clk subdirs-y += crypto subdirs-$(CFG_BNXT_FW) += bnxt subdirs-$(CFG_SCMI_MSG_DRIVERS) += scmi-msg diff --git a/core/include/drivers/clk.h b/core/include/drivers/clk.h new file mode 100644 index 000000000..8c0c44b34 --- /dev/null +++ b/core/include/drivers/clk.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef CLK_H +#define CLK_H + +#include +#include + +#define CLK_UNKNOWN_ID ULONG_MAX + +/* + * Minimal generic clock framework where platform is expected implement a + * single clock provider and each individual clock identified with a unique + * unsigned long identifier. + */ +struct clk_ops { + TEE_Result (*enable)(unsigned long id); + void (*disable)(unsigned long id); + unsigned long (*get_rate)(unsigned long id); + unsigned long (*get_parent)(unsigned long id); + bool (*is_enabled)(unsigned long id); +}; + +TEE_Result clk_enable(unsigned long id); +void clk_disable(unsigned long id); +unsigned long clk_get_rate(unsigned long id); +bool clk_is_enabled(unsigned long id); +unsigned long clk_get_parent(unsigned long id); + +void clk_provider_register(const struct clk_ops *ops); + +#endif /* CLK_H */ diff --git a/core/include/drivers/gic.h b/core/include/drivers/gic.h index f9bb28ec1..c8da6d849 100644 --- a/core/include/drivers/gic.h +++ b/core/include/drivers/gic.h @@ -9,17 +9,38 @@ #include #include +/* Constants to categorize priorities */ +#define GIC_HIGHEST_SEC_PRIORITY 0x0U +#define GIC_LOWEST_SEC_PRIORITY 0x7fU +#define GIC_HIGHEST_NS_PRIORITY 0x80U +#define GIC_LOWEST_NS_PRIORITY 0xfeU +/* 0xff would disable all interrupts */ + #define GIC_DIST_REG_SIZE 0x10000 #define GIC_CPU_REG_SIZE 0x10000 #define GIC_SGI(x) (x) #define GIC_PPI(x) ((x) + 16) #define GIC_SPI(x) ((x) + 32) +/* + * Save and restore some interrupts configuration during low power sequences. + * This is used on platforms using OP-TEE secure monitor. + */ +struct gic_it_pm; + +struct gic_pm { + struct gic_it_pm *pm_cfg; + size_t count; +}; + struct gic_data { vaddr_t gicc_base; vaddr_t gicd_base; size_t max_it; struct itr_chip chip; +#if defined(CFG_ARM_GIC_PM) + struct gic_pm pm; +#endif }; /* @@ -31,6 +52,9 @@ void gic_init(struct gic_data *gd, vaddr_t gicc_base, vaddr_t gicd_base); /* initial base address only */ void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base, vaddr_t gicd_base); +/* Setup GIC default configuration */ +void gic_init_setup(struct gic_data *gd); + /* initial cpu if only, mainly use for secondary cpu setup cpu interface */ void gic_cpu_init(struct gic_data *gd); diff --git a/core/include/drivers/stm32_bsec.h b/core/include/drivers/stm32_bsec.h index b6afbf8c4..9fe85bc98 100644 --- a/core/include/drivers/stm32_bsec.h +++ b/core/include/drivers/stm32_bsec.h @@ -10,6 +10,12 @@ #include #include +/* BSEC_DEBUG */ +#define BSEC_HDPEN BIT(4) +#define BSEC_SPIDEN BIT(5) +#define BSEC_SPINDEN BIT(6) +#define BSEC_DBGSWGEN BIT(10) + /* * Load OTP from SAFMEM and provide its value * @value: Output read value @@ -147,4 +153,14 @@ TEE_Result stm32_bsec_otp_lock(uint32_t service); */ bool stm32_bsec_nsec_can_access_otp(uint32_t otp_id); +/* + * Find and get OTP location from its name. + * @name: sub-node name to look up. + * @otp_id: pointer to read OTP number or NULL. + * @otp_bit_len: pointer to read OTP length in bits or NULL. + * Return a TEE_Result compliant status + */ +TEE_Result stm32_bsec_find_otp_in_nvmem_layout(const char *name, + uint32_t *otp_id, + size_t *otp_bit_len); #endif /*__STM32_BSEC_H*/ diff --git a/core/include/drivers/stm32_iwdg.h b/core/include/drivers/stm32_iwdg.h new file mode 100644 index 000000000..f06325812 --- /dev/null +++ b/core/include/drivers/stm32_iwdg.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + */ + +#ifndef __STM32_IWDG_H__ +#define __STM32_IWDG_H__ + +#include + +#define IWDG_HW_ENABLED BIT(0) +#define IWDG_DISABLE_ON_STOP BIT(1) +#define IWDG_DISABLE_ON_STANDBY BIT(2) + +void stm32_iwdg_refresh(unsigned int instance); + +#endif /*__STM32_IWDG_H__*/ diff --git a/core/include/drivers/stm32_rtc.h b/core/include/drivers/stm32_rtc.h new file mode 100644 index 000000000..b0f4ef858 --- /dev/null +++ b/core/include/drivers/stm32_rtc.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + */ + +#ifndef __PLAT_RTC_H__ +#define __PLAT_RTC_H__ + +#include + +struct stm32_rtc_calendar { + uint32_t ssr; + uint32_t tr; + uint32_t dr; +}; + +enum months { + JANUARY = 1, + FEBRUARY, + MARCH, + APRIL, + MAY, + JUNE, + JULY, + AUGUST, + SEPTEMBER, + OCTOBER, + NOVEMBER, + DECEMBER, + NB_MONTHS = 12 +}; + +struct stm32_rtc_time { + uint32_t hour; + uint32_t min; + uint32_t sec; + uint32_t wday; + uint32_t day; + enum months month; + uint32_t year; +}; + +/* Get calendar formated time from RTC device */ +void stm32_rtc_get_calendar(struct stm32_rtc_calendar *calendar); + +/* Return time diff in milliseconds between current and reference time */ +unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur, + struct stm32_rtc_calendar *ref); + +/* Enable tamper and secure timestamp access in RTC */ +void stm32_rtc_set_tamper_timestamp(void); + +/* Retrun true if and only if RTC timestamp is enable */ +bool stm32_rtc_is_timestamp_enable(void); + +/* Get RTC timestamp for current time */ +void stm32_rtc_get_timestamp(struct stm32_rtc_time *tamp_ts); + +#endif /* __PLAT_RTC_H__ */ diff --git a/core/include/drivers/stm32_tim.h b/core/include/drivers/stm32_tim.h new file mode 100644 index 000000000..2373561a3 --- /dev/null +++ b/core/include/drivers/stm32_tim.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2018-2019, STMicroelectronics + */ + +#ifndef STM32_TIM_H +#define STM32_TIM_H + +enum stm32_tim_cal { + HSI_CAL = 0, + CSI_CAL +}; + +unsigned long stm32_tim_hsi_freq(void); +unsigned long stm32_tim_csi_freq(void); + +/* + * Get the timer frequence callback function for a target clock calibration + * @timer_freq_cb - Output callback function + * @type - Target clock calibration ID + */ +void stm32_tim_freq_func(unsigned long (**timer_freq_cb)(void), + enum stm32_tim_cal type); + +#endif /* STM32_TIM_H */ diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h b/core/include/drivers/stm32mp1_rcc.h similarity index 95% rename from core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h rename to core/include/drivers/stm32mp1_rcc.h index 4dedbad27..6c92257b6 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h +++ b/core/include/drivers/stm32mp1_rcc.h @@ -1,13 +1,11 @@ /* SPDX-License-Identifier: BSD-3-Clause */ /* - * Copyright (c) 2017-2018, STMicroelectronics + * Copyright (c) 2017-2020, STMicroelectronics */ #ifndef __STM32MP1_RCC_H__ #define __STM32MP1_RCC_H__ -#include -#include #include #define RCC_TZCR 0x00 @@ -392,7 +390,8 @@ #define RCC_HSICFGR_HSITRIM_SHIFT 8 #define RCC_HSICFGR_HSITRIM_MASK GENMASK_32(14, 8) #define RCC_HSICFGR_HSICAL_SHIFT 16 -#define RCC_HSICFGR_HSICAL_MASK GENMASK_32(27, 16) +#define RCC_HSICFGR_HSICAL_MASK GENMASK_32(24, 16) +#define RCC_HSICFGR_HSICAL_TEMP_MASK GENMASK_32(27, 25) /* Fields of RCC_CSICFGR register */ #define RCC_CSICFGR_CSITRIM_SHIFT 8 @@ -455,6 +454,9 @@ #define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0) #define RCC_MP_SREQCLRR_STPREQ_P1 BIT(1) +/* Values of RCC_PWRLPDLYCR register */ +#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK GENMASK_32(21, 0) + /* Global Control Register */ #define RCC_MP_GCR_BOOT_MCU BIT(0) @@ -511,6 +513,9 @@ #define RCC_AHB5RSTSETR_RNG1RST BIT(6) #define RCC_AHB5RSTSETR_AXIMCRST BIT(16) +/* RCC_MP_AHB6RST(SET|CLR)R bit fields */ +#define RCC_AHB6RSTSETR_GPURST BIT(5) + /* RCC_MP_AHB5EN(SET|CLR)R bit fields */ #define RCC_MP_AHB5ENSETR_GPIOZEN_POS 0 #define RCC_MP_AHB5ENSETR_CRYP1EN_POS 4 @@ -534,26 +539,43 @@ #define RCC_MP_AHB5LPENSETR_BKPSRAMLPEN BIT(8) /* RCC_MP_TZAHB6EN(SET|CLR)R bit fields */ -#define RCC_MP_TZAHB6ENSETR_MDMA_POS 0 -#define RCC_MP_TZAHB6ENSETR_MDMA BIT(RCC_MP_TZAHB6ENSETR_MDMA_POS) +#define RCC_MP_TZAHB6ENSETR_MDMA_POS 0 +#define RCC_MP_TZAHB6ENSETR_MDMA \ + BIT(RCC_MP_TZAHB6ENSETR_MDMA_POS) /* RCC_MP_IWDGFZ(SET|CLR)R bit fields */ #define RCC_MP_IWDGFZSETR_IWDG1 BIT(0) #define RCC_MP_IWDGFZSETR_IWDG2 BIT(1) #define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" +#define DT_RCC_SEC_CLK_COMPAT "st,stm32mp1-rcc-secure" #ifndef __ASSEMBLER__ +#include +#include +#include + vaddr_t stm32_rcc_base(void); static inline bool stm32_rcc_is_secure(void) { - return io_read32(stm32_rcc_base() + RCC_TZCR) & RCC_TZCR_TZEN; + static int state = -1; + + if (state < 0) + state = io_read32(stm32_rcc_base() + RCC_TZCR) & RCC_TZCR_TZEN; + + return state; } static inline bool stm32_rcc_is_mckprot(void) { - return io_read32(stm32_rcc_base() + RCC_TZCR) & RCC_TZCR_MCKPROT; + const uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT; + static int state = -1; + + if (state < 0) + state = (io_read32(stm32_rcc_base() + RCC_TZCR) & mask) == mask; + + return state; } #endif /*__ASSEMBLER__*/ diff --git a/core/include/dt-bindings/clock/stm32mp1-clksrc.h b/core/include/dt-bindings/clock/stm32mp1-clksrc.h new file mode 100644 index 000000000..de7d1604c --- /dev/null +++ b/core/include/dt-bindings/clock/stm32mp1-clksrc.h @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + */ + +#ifndef _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ +#define _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ + +/* PLL output is enable when x=1, with x=p,q or r */ +#define PQR(p, q, r) (((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2)) + +/* st,clksrc: mandatory clock source */ + +#define CLK_MPU_HSI 0x00000200 +#define CLK_MPU_HSE 0x00000201 +#define CLK_MPU_PLL1P 0x00000202 +#define CLK_MPU_PLL1P_DIV 0x00000203 + +#define CLK_AXI_HSI 0x00000240 +#define CLK_AXI_HSE 0x00000241 +#define CLK_AXI_PLL2P 0x00000242 + +#define CLK_MCU_HSI 0x00000480 +#define CLK_MCU_HSE 0x00000481 +#define CLK_MCU_CSI 0x00000482 +#define CLK_MCU_PLL3P 0x00000483 + +#define CLK_PLL12_HSI 0x00000280 +#define CLK_PLL12_HSE 0x00000281 + +#define CLK_PLL3_HSI 0x00008200 +#define CLK_PLL3_HSE 0x00008201 +#define CLK_PLL3_CSI 0x00008202 + +#define CLK_PLL4_HSI 0x00008240 +#define CLK_PLL4_HSE 0x00008241 +#define CLK_PLL4_CSI 0x00008242 +#define CLK_PLL4_I2SCKIN 0x00008243 + +#define CLK_RTC_DISABLED 0x00001400 +#define CLK_RTC_LSE 0x00001401 +#define CLK_RTC_LSI 0x00001402 +#define CLK_RTC_HSE 0x00001403 + +#define CLK_MCO1_HSI 0x00008000 +#define CLK_MCO1_HSE 0x00008001 +#define CLK_MCO1_CSI 0x00008002 +#define CLK_MCO1_LSI 0x00008003 +#define CLK_MCO1_LSE 0x00008004 +#define CLK_MCO1_DISABLED 0x0000800F + +#define CLK_MCO2_MPU 0x00008040 +#define CLK_MCO2_AXI 0x00008041 +#define CLK_MCO2_MCU 0x00008042 +#define CLK_MCO2_PLL4P 0x00008043 +#define CLK_MCO2_HSE 0x00008044 +#define CLK_MCO2_HSI 0x00008045 +#define CLK_MCO2_DISABLED 0x0000804F + +/* st,pkcs: peripheral kernel clock source */ + +#define CLK_I2C12_PCLK1 0x00008C00 +#define CLK_I2C12_PLL4R 0x00008C01 +#define CLK_I2C12_HSI 0x00008C02 +#define CLK_I2C12_CSI 0x00008C03 +#define CLK_I2C12_DISABLED 0x00008C07 + +#define CLK_I2C35_PCLK1 0x00008C40 +#define CLK_I2C35_PLL4R 0x00008C41 +#define CLK_I2C35_HSI 0x00008C42 +#define CLK_I2C35_CSI 0x00008C43 +#define CLK_I2C35_DISABLED 0x00008C47 + +#define CLK_I2C46_PCLK5 0x00000C00 +#define CLK_I2C46_PLL3Q 0x00000C01 +#define CLK_I2C46_HSI 0x00000C02 +#define CLK_I2C46_CSI 0x00000C03 +#define CLK_I2C46_DISABLED 0x00000C07 + +#define CLK_SAI1_PLL4Q 0x00008C80 +#define CLK_SAI1_PLL3Q 0x00008C81 +#define CLK_SAI1_I2SCKIN 0x00008C82 +#define CLK_SAI1_CKPER 0x00008C83 +#define CLK_SAI1_PLL3R 0x00008C84 +#define CLK_SAI1_DISABLED 0x00008C87 + +#define CLK_SAI2_PLL4Q 0x00008CC0 +#define CLK_SAI2_PLL3Q 0x00008CC1 +#define CLK_SAI2_I2SCKIN 0x00008CC2 +#define CLK_SAI2_CKPER 0x00008CC3 +#define CLK_SAI2_SPDIF 0x00008CC4 +#define CLK_SAI2_PLL3R 0x00008CC5 +#define CLK_SAI2_DISABLED 0x00008CC7 + +#define CLK_SAI3_PLL4Q 0x00008D00 +#define CLK_SAI3_PLL3Q 0x00008D01 +#define CLK_SAI3_I2SCKIN 0x00008D02 +#define CLK_SAI3_CKPER 0x00008D03 +#define CLK_SAI3_PLL3R 0x00008D04 +#define CLK_SAI3_DISABLED 0x00008D07 + +#define CLK_SAI4_PLL4Q 0x00008D40 +#define CLK_SAI4_PLL3Q 0x00008D41 +#define CLK_SAI4_I2SCKIN 0x00008D42 +#define CLK_SAI4_CKPER 0x00008D43 +#define CLK_SAI4_PLL3R 0x00008D44 +#define CLK_SAI4_DISABLED 0x00008D47 + +#define CLK_SPI2S1_PLL4P 0x00008D80 +#define CLK_SPI2S1_PLL3Q 0x00008D81 +#define CLK_SPI2S1_I2SCKIN 0x00008D82 +#define CLK_SPI2S1_CKPER 0x00008D83 +#define CLK_SPI2S1_PLL3R 0x00008D84 +#define CLK_SPI2S1_DISABLED 0x00008D87 + +#define CLK_SPI2S23_PLL4P 0x00008DC0 +#define CLK_SPI2S23_PLL3Q 0x00008DC1 +#define CLK_SPI2S23_I2SCKIN 0x00008DC2 +#define CLK_SPI2S23_CKPER 0x00008DC3 +#define CLK_SPI2S23_PLL3R 0x00008DC4 +#define CLK_SPI2S23_DISABLED 0x00008DC7 + +#define CLK_SPI45_PCLK2 0x00008E00 +#define CLK_SPI45_PLL4Q 0x00008E01 +#define CLK_SPI45_HSI 0x00008E02 +#define CLK_SPI45_CSI 0x00008E03 +#define CLK_SPI45_HSE 0x00008E04 +#define CLK_SPI45_DISABLED 0x00008E07 + +#define CLK_SPI6_PCLK5 0x00000C40 +#define CLK_SPI6_PLL4Q 0x00000C41 +#define CLK_SPI6_HSI 0x00000C42 +#define CLK_SPI6_CSI 0x00000C43 +#define CLK_SPI6_HSE 0x00000C44 +#define CLK_SPI6_PLL3Q 0x00000C45 +#define CLK_SPI6_DISABLED 0x00000C47 + +#define CLK_UART6_PCLK2 0x00008E40 +#define CLK_UART6_PLL4Q 0x00008E41 +#define CLK_UART6_HSI 0x00008E42 +#define CLK_UART6_CSI 0x00008E43 +#define CLK_UART6_HSE 0x00008E44 +#define CLK_UART6_DISABLED 0x00008E47 + +#define CLK_UART24_PCLK1 0x00008E80 +#define CLK_UART24_PLL4Q 0x00008E81 +#define CLK_UART24_HSI 0x00008E82 +#define CLK_UART24_CSI 0x00008E83 +#define CLK_UART24_HSE 0x00008E84 +#define CLK_UART24_DISABLED 0x00008E87 + +#define CLK_UART35_PCLK1 0x00008EC0 +#define CLK_UART35_PLL4Q 0x00008EC1 +#define CLK_UART35_HSI 0x00008EC2 +#define CLK_UART35_CSI 0x00008EC3 +#define CLK_UART35_HSE 0x00008EC4 +#define CLK_UART35_DISABLED 0x00008EC7 + +#define CLK_UART78_PCLK1 0x00008F00 +#define CLK_UART78_PLL4Q 0x00008F01 +#define CLK_UART78_HSI 0x00008F02 +#define CLK_UART78_CSI 0x00008F03 +#define CLK_UART78_HSE 0x00008F04 +#define CLK_UART78_DISABLED 0x00008F07 + +#define CLK_UART1_PCLK5 0x00000C80 +#define CLK_UART1_PLL3Q 0x00000C81 +#define CLK_UART1_HSI 0x00000C82 +#define CLK_UART1_CSI 0x00000C83 +#define CLK_UART1_PLL4Q 0x00000C84 +#define CLK_UART1_HSE 0x00000C85 +#define CLK_UART1_DISABLED 0x00000C87 + +#define CLK_SDMMC12_HCLK6 0x00008F40 +#define CLK_SDMMC12_PLL3R 0x00008F41 +#define CLK_SDMMC12_PLL4P 0x00008F42 +#define CLK_SDMMC12_HSI 0x00008F43 +#define CLK_SDMMC12_DISABLED 0x00008F47 + +#define CLK_SDMMC3_HCLK2 0x00008F80 +#define CLK_SDMMC3_PLL3R 0x00008F81 +#define CLK_SDMMC3_PLL4P 0x00008F82 +#define CLK_SDMMC3_HSI 0x00008F83 +#define CLK_SDMMC3_DISABLED 0x00008F87 + +#define CLK_ETH_PLL4P 0x00008FC0 +#define CLK_ETH_PLL3Q 0x00008FC1 +#define CLK_ETH_DISABLED 0x00008FC3 + +#define CLK_QSPI_ACLK 0x00009000 +#define CLK_QSPI_PLL3R 0x00009001 +#define CLK_QSPI_PLL4P 0x00009002 +#define CLK_QSPI_CKPER 0x00009003 + +#define CLK_FMC_ACLK 0x00009040 +#define CLK_FMC_PLL3R 0x00009041 +#define CLK_FMC_PLL4P 0x00009042 +#define CLK_FMC_CKPER 0x00009043 + +#define CLK_FDCAN_HSE 0x000090C0 +#define CLK_FDCAN_PLL3Q 0x000090C1 +#define CLK_FDCAN_PLL4Q 0x000090C2 +#define CLK_FDCAN_PLL4R 0x000090C3 + +#define CLK_SPDIF_PLL4P 0x00009140 +#define CLK_SPDIF_PLL3Q 0x00009141 +#define CLK_SPDIF_HSI 0x00009142 +#define CLK_SPDIF_DISABLED 0x00009143 + +#define CLK_CEC_LSE 0x00009180 +#define CLK_CEC_LSI 0x00009181 +#define CLK_CEC_CSI_DIV122 0x00009182 +#define CLK_CEC_DISABLED 0x00009183 + +#define CLK_USBPHY_HSE 0x000091C0 +#define CLK_USBPHY_PLL4R 0x000091C1 +#define CLK_USBPHY_HSE_DIV2 0x000091C2 +#define CLK_USBPHY_DISABLED 0x000091C3 + +#define CLK_USBO_PLL4R 0x800091C0 +#define CLK_USBO_USBPHY 0x800091C1 + +#define CLK_RNG1_CSI 0x00000CC0 +#define CLK_RNG1_PLL4R 0x00000CC1 +#define CLK_RNG1_LSE 0x00000CC2 +#define CLK_RNG1_LSI 0x00000CC3 + +#define CLK_RNG2_CSI 0x00009200 +#define CLK_RNG2_PLL4R 0x00009201 +#define CLK_RNG2_LSE 0x00009202 +#define CLK_RNG2_LSI 0x00009203 + +#define CLK_CKPER_HSI 0x00000D00 +#define CLK_CKPER_CSI 0x00000D01 +#define CLK_CKPER_HSE 0x00000D02 +#define CLK_CKPER_DISABLED 0x00000D03 + +#define CLK_STGEN_HSI 0x00000D40 +#define CLK_STGEN_HSE 0x00000D41 +#define CLK_STGEN_DISABLED 0x00000D43 + +#define CLK_DSI_DSIPLL 0x00009240 +#define CLK_DSI_PLL4P 0x00009241 + +#define CLK_ADC_PLL4R 0x00009280 +#define CLK_ADC_CKPER 0x00009281 +#define CLK_ADC_PLL3Q 0x00009282 +#define CLK_ADC_DISABLED 0x00009283 + +#define CLK_LPTIM45_PCLK3 0x000092C0 +#define CLK_LPTIM45_PLL4P 0x000092C1 +#define CLK_LPTIM45_PLL3Q 0x000092C2 +#define CLK_LPTIM45_LSE 0x000092C3 +#define CLK_LPTIM45_LSI 0x000092C4 +#define CLK_LPTIM45_CKPER 0x000092C5 +#define CLK_LPTIM45_DISABLED 0x000092C7 + +#define CLK_LPTIM23_PCLK3 0x00009300 +#define CLK_LPTIM23_PLL4Q 0x00009301 +#define CLK_LPTIM23_CKPER 0x00009302 +#define CLK_LPTIM23_LSE 0x00009303 +#define CLK_LPTIM23_LSI 0x00009304 +#define CLK_LPTIM23_DISABLED 0x00009307 + +#define CLK_LPTIM1_PCLK1 0x00009340 +#define CLK_LPTIM1_PLL4P 0x00009341 +#define CLK_LPTIM1_PLL3Q 0x00009342 +#define CLK_LPTIM1_LSE 0x00009343 +#define CLK_LPTIM1_LSI 0x00009344 +#define CLK_LPTIM1_CKPER 0x00009345 +#define CLK_LPTIM1_DISABLED 0x00009347 + +/* define for st,pll /csg */ +#define SSCG_MODE_CENTER_SPREAD 0 +#define SSCG_MODE_DOWN_SPREAD 1 + +/* define for st,drive */ +#define LSEDRV_LOWEST 0 +#define LSEDRV_MEDIUM_LOW 1 +#define LSEDRV_MEDIUM_HIGH 2 +#define LSEDRV_HIGHEST 3 + +#endif diff --git a/core/include/dt-bindings/power/stm32mp1-power.h b/core/include/dt-bindings/power/stm32mp1-power.h new file mode 100644 index 000000000..bfb7f785e --- /dev/null +++ b/core/include/dt-bindings/power/stm32mp1-power.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Yann Gautier for STMicroelectronics. + */ + +#ifndef DT_BINDINGS_STM32MP1_POWER_H +#define DT_BINDINGS_STM32MP1_POWER_H + +#define STM32_PM_CSLEEP_RUN 0 +#define STM32_PM_CSTOP_ALLOW_STOP 1 +#define STM32_PM_CSTOP_ALLOW_LP_STOP 2 +#define STM32_PM_CSTOP_ALLOW_LPLV_STOP 3 +#define STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR 4 +#define STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF 5 +#define STM32_PM_SHUTDOWN 6 +#define STM32_PM_MAX_SOC_MODE 7 + +#endif /* DT_BINDINGS_STM32MP1_POWER_H */ diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_etzpc.h b/core/include/dt-bindings/soc/st,stm32-etzpc.h similarity index 83% rename from core/arch/arm/plat-stm32mp1/drivers/stm32mp1_etzpc.h rename to core/include/dt-bindings/soc/st,stm32-etzpc.h index 338a39283..6678b8e66 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_etzpc.h +++ b/core/include/dt-bindings/soc/st,stm32-etzpc.h @@ -1,26 +1,35 @@ -/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ /* - * Copyright (C) 2018-2019, STMicroelectronics + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause */ -#ifndef __STM32MP1_ETZPC_H -#define __STM32MP1_ETZPC_H +#ifndef _DT_BINDINGS_STM32_ETZPC_H +#define _DT_BINDINGS_STM32_ETZPC_H -/* Define DECPROT IDs for stm32mp1 familly */ +/* define DECPROT modes */ +#define DECPROT_S_RW 0x0 +#define DECPROT_NS_R_S_W 0x1 +#define DECPROT_MCU_ISOLATION 0x2 +#define DECPROT_NS_RW 0x3 + +/* define DECPROT lock */ +#define DECPROT_UNLOCK 0x0 +#define DECPROT_LOCK 0x1 + +/* define ETZPC ID */ #define STM32MP1_ETZPC_STGENC_ID 0 #define STM32MP1_ETZPC_BKPSRAM_ID 1 #define STM32MP1_ETZPC_IWDG1_ID 2 #define STM32MP1_ETZPC_USART1_ID 3 #define STM32MP1_ETZPC_SPI6_ID 4 #define STM32MP1_ETZPC_I2C4_ID 5 -#define STM32MP1_ETZPC_GPIOZ_ID 6 #define STM32MP1_ETZPC_RNG1_ID 7 #define STM32MP1_ETZPC_HASH1_ID 8 #define STM32MP1_ETZPC_CRYP1_ID 9 #define STM32MP1_ETZPC_DDRCTRL_ID 10 #define STM32MP1_ETZPC_DDRPHYC_ID 11 #define STM32MP1_ETZPC_I2C6_ID 12 -/* 13-15 Reserved */ #define STM32MP1_ETZPC_TIM2_ID 16 #define STM32MP1_ETZPC_TIM3_ID 17 #define STM32MP1_ETZPC_TIM4_ID 18 @@ -47,12 +56,9 @@ #define STM32MP1_ETZPC_DAC_ID 39 #define STM32MP1_ETZPC_UART7_ID 40 #define STM32MP1_ETZPC_UART8_ID 41 -/* 42-43 Reserved */ #define STM32MP1_ETZPC_MDIOS_ID 44 -/* 45-47 Reserved */ #define STM32MP1_ETZPC_TIM1_ID 48 #define STM32MP1_ETZPC_TIM8_ID 49 -/* 50 Reserved */ #define STM32MP1_ETZPC_USART6_ID 51 #define STM32MP1_ETZPC_SPI1_ID 52 #define STM32MP1_ETZPC_SPI4_ID 53 @@ -65,7 +71,6 @@ #define STM32MP1_ETZPC_SAI3_ID 60 #define STM32MP1_ETZPC_DFSDM_ID 61 #define STM32MP1_ETZPC_TT_FDCAN_ID 62 -/* 63 Reserved */ #define STM32MP1_ETZPC_LPTIM2_ID 64 #define STM32MP1_ETZPC_LPTIM3_ID 65 #define STM32MP1_ETZPC_LPTIM4_ID 66 @@ -78,7 +83,6 @@ #define STM32MP1_ETZPC_HASH2_ID 73 #define STM32MP1_ETZPC_RNG2_ID 74 #define STM32MP1_ETZPC_CRYP2_ID 75 -/* 76-79 Reserved */ #define STM32MP1_ETZPC_SRAM1_ID 80 #define STM32MP1_ETZPC_SRAM2_ID 81 #define STM32MP1_ETZPC_SRAM3_ID 82 @@ -94,7 +98,10 @@ #define STM32MP1_ETZPC_QSPI_ID 92 #define STM32MP1_ETZPC_DLYBQ_ID 93 #define STM32MP1_ETZPC_ETH_ID 94 -/* 95 Reserved */ + #define STM32MP1_ETZPC_MAX_ID 96 -#endif /*__STM32MP1_ETZPC_H*/ +#define DECPROT(id, mode, lock) (((id) << 16) | ((mode) << 8) | (lock)) + +#endif /* _DT_BINDINGS_STM32_ETZPC_H */ + diff --git a/core/include/kernel/interrupt.h b/core/include/kernel/interrupt.h index 849e987f9..796eded29 100644 --- a/core/include/kernel/interrupt.h +++ b/core/include/kernel/interrupt.h @@ -25,6 +25,11 @@ struct itr_ops { uint8_t cpu_mask); void (*set_affinity)(struct itr_chip *chip, size_t it, uint8_t cpu_mask); +#if !defined(CFG_ARM_GICV3) + uint8_t (*set_pmr)(struct itr_chip *chip, uint8_t mask); + uint8_t (*set_ipriority)(struct itr_chip *chip, size_t it, + uint8_t mask); +#endif }; enum itr_return { @@ -66,4 +71,14 @@ void itr_set_affinity(size_t it, uint8_t cpu_mask); */ void itr_core_handler(void); +/* + * Set the Priority Mask Regarding and return its previous value + */ +uint8_t itr_set_pmr(uint8_t mask); + +/* + * Set the targe tinterrupt priority mask and return its previous value + */ +uint8_t itr_set_ipriority(size_t it, uint8_t mask); + #endif /*__KERNEL_INTERRUPT_H*/ diff --git a/core/include/kernel/panic.h b/core/include/kernel/panic.h index b9a56dc2c..0f0d0794e 100644 --- a/core/include/kernel/panic.h +++ b/core/include/kernel/panic.h @@ -8,6 +8,12 @@ #include +/* + * Platform can define a panic sequence to trap cpu/reset core or system + * after eventual debug trace. + */ +void plat_panic(void); + /* debug disabled => __FILE__, ... and panic message are not built. */ #if defined(CFG_TEE_CORE_DEBUG) #define __panic(str) __do_panic(__FILE__, __LINE__, __func__, str) diff --git a/core/kernel/interrupt.c b/core/kernel/interrupt.c index 961ce6be3..376012556 100644 --- a/core/kernel/interrupt.c +++ b/core/kernel/interrupt.c @@ -88,3 +88,13 @@ void __weak __noreturn itr_core_handler(void) { panic("Secure interrupt handler not defined"); } + +uint8_t itr_set_pmr(uint8_t mask) +{ + return itr_chip->ops->set_pmr(itr_chip, mask); +} + +uint8_t itr_set_ipriority(size_t it, uint8_t mask) +{ + return itr_chip->ops->set_ipriority(itr_chip, it, mask); +} diff --git a/core/kernel/panic.c b/core/kernel/panic.c index f30c6ffe7..023f4be5d 100644 --- a/core/kernel/panic.c +++ b/core/kernel/panic.c @@ -7,8 +7,21 @@ #include #include #include +#include #include +static void __noreturn stall_cpu(void) +{ + while (true) + ; +} + +void __weak __noreturn plat_panic(void) +{ + /* abort current execution */ + stall_cpu(); +} + void __do_panic(const char *file __maybe_unused, const int line __maybe_unused, const char *func __maybe_unused, @@ -17,8 +30,6 @@ void __do_panic(const char *file __maybe_unused, /* disable prehemption */ (void)thread_mask_exceptions(THREAD_EXCP_ALL); - /* TODO: notify other cores */ - /* trace: Panic ['panic-string-message' ]at FILE:LINE []" */ if (!file && !func && !msg) EMSG_RAW("Panic"); @@ -29,7 +40,9 @@ void __do_panic(const char *file __maybe_unused, func ? "<" : "", func ? func : "", func ? ">" : ""); print_kernel_stack(); - /* abort current execution */ - while (1) - ; + + plat_panic(); + + EMSG("platform failed to abord execution"); + stall_cpu(); } diff --git a/core/mm/vm.c b/core/mm/vm.c index 27ffa18af..95080a700 100644 --- a/core/mm/vm.c +++ b/core/mm/vm.c @@ -162,14 +162,26 @@ static TEE_Result alloc_pgt(struct user_mode_ctx *uctx) return TEE_SUCCESS; } -static void maybe_free_pgt(struct user_mode_ctx *uctx, struct vm_region *r) +static void rem_um_region(struct user_mode_ctx *uctx, struct vm_region *r) { - struct thread_specific_data *tsd = NULL; + struct thread_specific_data *tsd = thread_get_tsd(); struct pgt_cache *pgt_cache = NULL; vaddr_t begin = ROUNDDOWN(r->va, CORE_MMU_PGDIR_SIZE); vaddr_t last = ROUNDUP(r->va + r->size, CORE_MMU_PGDIR_SIZE); struct vm_region *r2 = NULL; + if (uctx->ts_ctx == tsd->ctx) + pgt_cache = &tsd->pgt_cache; + + if (mobj_is_paged(r->mobj)) { + tee_pager_rem_um_region(uctx, r->va, r->size); + } else { + pgt_clear_ctx_range(pgt_cache, uctx->ts_ctx, r->va, + r->va + r->size); + tlbi_mva_range_asid(r->va, r->size, SMALL_PAGE_SIZE, + uctx->vm_info.asid); + } + r2 = TAILQ_NEXT(r, link); if (r2) last = MIN(last, ROUNDDOWN(r2->va, CORE_MMU_PGDIR_SIZE)); @@ -183,10 +195,6 @@ static void maybe_free_pgt(struct user_mode_ctx *uctx, struct vm_region *r) if (begin >= last) return; - tsd = thread_get_tsd(); - if (uctx->ts_ctx == tsd->ctx) - pgt_cache = &tsd->pgt_cache; - pgt_flush_ctx_range(pgt_cache, uctx->ts_ctx, r->va, r->va + r->size); } @@ -539,9 +547,7 @@ TEE_Result vm_remap(struct user_mode_ctx *uctx, vaddr_t *new_va, vaddr_t old_va, if (r->va + r->size > old_va + len) break; r_next = TAILQ_NEXT(r, link); - if (fobj) - tee_pager_rem_um_region(uctx, r->va, r->size); - maybe_free_pgt(uctx, r); + rem_um_region(uctx, r); TAILQ_REMOVE(&uctx->vm_info.regions, r, link); TAILQ_INSERT_TAIL(®s, r, link); } @@ -774,21 +780,13 @@ TEE_Result vm_unmap(struct user_mode_ctx *uctx, vaddr_t va, size_t len) while (true) { r_next = TAILQ_NEXT(r, link); unmap_end_va = r->va + r->size; - if (mobj_is_paged(r->mobj)) - tee_pager_rem_um_region(uctx, r->va, r->size); - maybe_free_pgt(uctx, r); + rem_um_region(uctx, r); umap_remove_region(&uctx->vm_info, r); if (!r_next || unmap_end_va == end_va) break; r = r_next; } - /* - * Synchronize change to translation tables. Even though the pager - * case unmaps immediately we may still free a translation table. - */ - vm_set_ctx(uctx->ts_ctx); - return TEE_SUCCESS; } @@ -843,9 +841,7 @@ void vm_clean_param(struct user_mode_ctx *uctx) TAILQ_FOREACH_SAFE(r, &uctx->vm_info.regions, link, next_r) { if (r->flags & VM_FLAG_EPHEMERAL) { - if (mobj_is_paged(r->mobj)) - tee_pager_rem_um_region(uctx, r->va, r->size); - maybe_free_pgt(uctx, r); + rem_um_region(uctx, r); umap_remove_region(&uctx->vm_info, r); } } @@ -1055,9 +1051,7 @@ void vm_rem_rwmem(struct user_mode_ctx *uctx, struct mobj *mobj, vaddr_t va) TAILQ_FOREACH(r, &uctx->vm_info.regions, link) { if (r->mobj == mobj && r->va == va) { - if (mobj_is_paged(r->mobj)) - tee_pager_rem_um_region(uctx, r->va, r->size); - maybe_free_pgt(uctx, r); + rem_um_region(uctx, r); umap_remove_region(&uctx->vm_info, r); return; } diff --git a/core/sub.mk b/core/sub.mk index 5a17cd923..faaf21c74 100644 --- a/core/sub.mk +++ b/core/sub.mk @@ -20,13 +20,16 @@ recipe-ldelf = $(PYTHON3) scripts/gen_ldelf_hex.py --input $(out-dir)/ldelf/ldel endif ifeq ($(CFG_WITH_USER_TA)-$(CFG_EARLY_TA),y-y) +ifeq ($(CFG_EARLY_TA_COMPRESS),y) +early-ta-compress = --compress +endif define process_early_ta early-ta-$1-uuid := $(firstword $(subst ., ,$(notdir $1))) gensrcs-y += early-ta-$1 produce-early-ta-$1 = early_ta_$$(early-ta-$1-uuid).c depends-early-ta-$1 = $1 scripts/ts_bin_to_c.py -recipe-early-ta-$1 = $(PYTHON3) scripts/ts_bin_to_c.py --compress --ta $1 \ - --out $(sub-dir-out)/early_ta_$$(early-ta-$1-uuid).c +recipe-early-ta-$1 = $(PYTHON3) scripts/ts_bin_to_c.py $(early-ta-compress) \ + --ta $1 --out $(sub-dir-out)/early_ta_$$(early-ta-$1-uuid).c endef $(foreach f, $(EARLY_TA_PATHS), $(eval $(call process_early_ta,$(f)))) $(foreach f, $(CFG_IN_TREE_EARLY_TAS), $(eval $(call \ diff --git a/keys/default_rproc.pem b/keys/default_rproc.pem new file mode 100644 index 000000000..d54476f35 --- /dev/null +++ b/keys/default_rproc.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA1TD3AMwyJhzsliOhEStPrCrgnG9Gy8z+OCtialVngW/rkqQB +cb/oOdiMPjfLoSio8zaUA86mTHo6DINZIopTZvs9pysnpvrOwbjCVRXTcIhgM/YZ +GyN9c+Qo5fCbOlCsxD0PG40hP4O0dktWyzmWQfjy0+9BDAyMoW59lPeYZcJAKSWT +M10V5h3JTabA4dqVroeztuTow3ftNImNuzMFYDqGDUcJy0EdluRsBfhOOKXE7ZaQ +RXnwY9CTCGqgsuNKwE1g8evkseaLcJk4/JpVFOgZp4fUgsxU6EBRD2i+C+Jq9KXg +qBcK0QwXNr2IwG3i76QmLzGGkpW7bKPn/QhGMQIDAQABAoIBAQCHBnAqzSmmAgPG +Q+KroSbhAHcqHUBVrAwHP1Mhzd20mVI2mjFf/g/zMzf/4A7Uj5ASGqs8jhG9tlw1 +uKsnuTyBqPavfiGrHIb/IynSAfTc/UMRJflYuu2mDQfqOq3WDWqfD50V8hjwxVXy +5lyecma8ehQyLwKfwwL+66AWTYr0Rx+OdXkGdGj1SXbJU39nv7UH8ZggpICFhUXO +r7NgJr2UOyhEje4stTGSb86SrvxHRm07JG1WSOJ2GV0EBhWNqbRtsnvH1NKNm03m +yM+zMbqvtdg1Wkfcfxtx6h7MGHhUUIHwotDoKgZ1lz1EdVWk8clmlKCLFEBxcwIp +sdbrodnBAoGBAPFQ1J7B+3eDBJjgrEFu9soygrjulhiA2+3qrra95RyuIE0wE8CO +DPjAGHOnxAoUt8H+TEGF2Wo2HVQauz2ElPOlIxQctr3w2Xpi1DibKEdooQLRlaSS +LHWAxTLZj9EI3NuYhdRvFHUW2ExEqCADOKY4+1xRSXuIbIkaLMaah8R9AoGBAOIq +BEiqoaQM/EA4z+m7RuOjc1PtA0qo9DJIEb4Mj92gEGzSHCdNN+eDCKbqyd8BGo/w +Pf6N8+dotjYvzlz3MqwfV1aczvQqbfkivzahO7GlK2KmwwLG3Vm8dZAZCZKEglOg +ex6h/L8gOgqSP+C4OmdEU4jdA24BSHr+1ZArHPrFAoGBAL27l/DbBCSLVun8fHNW +E6QW4sEUld7eMg12H7h+xc0u+ya1TlJvXbOXFaKZnYFvmKtmjf5WhwMDWTvvaJiN +za9jf5kommXtIJEhc0quc5TxpubYcpfadipM/L9mX7UzCrN90Hueeq81LwuIT8gb +wEaxNrD3GJeQRAXoFpxwk57hAoGAaeqLfwyKDq4WJG120VtnY4xUomVJOVnOow2l +YX+4kG45wvzTOoSrPbzb/G/QgqOdsPMt1VzdcO5VByN0XY1XKcyztlhRg3+raRWg +vxDbR+K2Ysj+YvqHB1N/KzDOjtOHxWpOvpXWLBwHkpPTXoZos5wIEvyOcqIfM5rM +oWvPcpECgYBCtncnPQQJfYcFebw3+rzm9OodF/s6G9afOrzqgEk/0Z6mi20x1c23 +dzcZUpLl9p7fCFg0iz9NwLUYR9tZ/4zy+J4ZET7PduxoLG3m1TVzxSJM+dU+GtQi +fBcdQuC6od9K9MJD2egwmes/I+aWhrIAatrG2iMtrOTG5N0mUMUc+w== +-----END RSA PRIVATE KEY----- diff --git a/lib/libutee/include/remoteproc_pta.h b/lib/libutee/include/remoteproc_pta.h new file mode 100644 index 000000000..cede192eb --- /dev/null +++ b/lib/libutee/include/remoteproc_pta.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef __REMOTEPROC_PTA_H +#define __REMOTEPROC_PTA_H + +#include + +/* + * Interface to the pseudo TA which provides platform implementation + * of the remote processor management + */ + +#define PTA_REMOTEPROC_UUID { 0x54af4a68, 0x19be, 0x40d7, \ + { 0xbb, 0xe6, 0x89, 0x50, 0x35, 0x0a, 0x87, 0x44 } } + +/* Firmware format */ +#define PTA_REMOTEPROC_PROPRIETARY_FMT BIT32(0) +#define PTA_REMOTEPROC_ELF_FMT BIT32(1) + +/* Firmware image protection */ +/* The platorm supports copy of the input firmware image in secure memory */ +#define PTA_REMOTEPROC_FW_SECURE_COPY BIT32(0) +/* The platorm supports load of segment with hash protection */ +#define PTA_REMOTEPROC_FW_WITH_HASH_TABLE BIT32(1) +/* The platorm is able to change access to secure the firmware input image */ +#define PTA_REMOTEPROC_FW_MEMORY_PROTECTION BIT32(2) + +/** + * struct rproc_pta_key_info - public key information + * @algo: Algorithm, defined by public key algorithms TEE_ALG_* + * from TEE Internal API specification + * @info_size: Byte size of the @info + * @info: Append key information data + */ +struct rproc_pta_key_info { + uint32_t algo; + uint32_t info_size; + char info[]; +}; + +static inline size_t + rproc_pta_get_keyinfo_size(struct rproc_pta_key_info *keyinf) +{ + size_t s = 0; + + if (!keyinf || ADD_OVERFLOW(sizeof(*keyinf), keyinf->info_size, &s)) + return 0; + + return s; +} + +#define RPROC_PTA_GET_KEYINFO_SIZE(x) rproc_pta_get_keyinfo_size((x)) + +/* + * Platform capabilities. + * + * Get Platform firmware loader service capabilities. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + * [out] params[1].value.a: Firmware format (PTA_REMOTEPROC_*_FMT) + * [out] params[2].value.a: Image protection method (PTA_REMOTEPROC_FW_*) + */ +#define PTA_REMOTEPROC_HW_CAPABILITIES 1 + +/* + * Firmware loading. + * + * Optional service to implement only in case of proprietary format. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + * [in] params[1].memref: Loadable firmware image + */ +#define PTA_REMOTEPROC_FIRMWARE_LOAD 2 + +/* + * Load a segment with a SHA256 hash. + * + * This command is used when the platform secure memory is too expensive to + * save the whole firmware image in secure memory. Upon segment load, a + * successful completion ensures the loaded image complies with the provided + * hash. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + * [in] params[1].memref: Section data to load + * [in] params[2].value.a: 32bit LSB load device segment address + * [in] params[2].value.b: 32bit MSB load device segment address + * [in] params[3].memref: Expected hash (SHA256) of the payload + */ +#define PTA_REMOTEPROC_LOAD_SEGMENT_SHA256 3 + +/* + * Memory set. + * + * Fill a remote device memory with requested value. this is use for instance + * to clear a memory on the remote firmware load. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + * [in] params[1].value.a: 32bit LSB device memory address + * [in] params[1].value.b: 32bit MSB device memory address + * [in] params[2].value.a: 32bit LSB device memory size + * [in] params[2].value.b: 32bit MSB device memory size + * [in] params[3].value.a: Byte value to be set + */ +#define PTA_REMOTEPROC_SET_MEMORY 4 + +/* + * Firmware start. + * + * Start up a successfully remote processor firmware. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + */ +#define PTA_REMOTEPROC_FIRMWARE_START 5 + +/* + * Firmware stop. + * + * Stop of the remote processor firmware and release/clean resources. + * After the command successful completion, remote processor firmware must be + * reloaded prior being started again. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + */ +#define PTA_REMOTEPROC_FIRMWARE_STOP 6 + +/* + * Firmware device to physical address conversion. + * + * Return the physical address corresponding to an address got from the + * firmware address layout. + * + * [in] params[0].value.a: Unique 32bit firmware identifier + * [in] params[1].value.a: 32bit LSB Device memory address + * [in] params[1].value.b: 32bit MSB Device memory address + * [in] params[2].value.a: 32bit LSB Device memory size + * [in] params[2].value.b: 32bit MSB Device memory size + * [out] params[3].value.a: 32bit LSB converted physical address + * [out] params[3].value.b: 32bit MSB converted physical address + */ +#define PTA_REMOTEPROC_FIRMWARE_DA_TO_PA 7 + +/* + * Verify the firmware digest against a signature + * + * Return TEE_SUCCESS if the signature is verified, else an error + * + * [in] params[0].value.a: Unique 32bit firmware identifier + * [in] params[1].memref: Key information (refer to @rproc_pta_key_info) + * [in] params[2].memref: Digest of the firmware authenticated data + * [in] params[3].memref: Signature of the firmware authenticated data + */ +#define PTA_REMOTEPROC_VERIFY_DIGEST 8 + +#endif /* __REMOTEPROC_PTA_H */ diff --git a/mk/config.mk b/mk/config.mk index 72f13fba4..a14c4f832 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -306,6 +306,9 @@ $(eval $(call cfg-depends-all,CFG_REE_FS_TA_BUFFERED,CFG_REE_FS_TA)) # in-tree TAs. CFG_IN_TREE_EARLY_TAS is formatted as: # / # for instance avb/023f8f1a-292a-432b-8fc4-de8471358067 +# +# By default the early TAs are compressed in the TEE binary, it is possible to +# not compress them with CFG_EARLY_TA_COMPRESS=n ifneq ($(EARLY_TA_PATHS)$(CFG_IN_TREE_EARLY_TAS),) $(call force,CFG_EARLY_TA,y) $(call force,CFG_EMBEDDED_TS,y) @@ -323,6 +326,7 @@ endif ifeq ($(CFG_EMBEDDED_TS),y) $(call force,CFG_ZLIB,y) endif +CFG_EARLY_TA_COMPRESS ?= y # Enable paging, requires SRAM, can't be enabled by default CFG_WITH_PAGER ?= n diff --git a/mk/gcc.mk b/mk/gcc.mk index adc77a24f..81bfa78ad 100644 --- a/mk/gcc.mk +++ b/mk/gcc.mk @@ -13,11 +13,11 @@ nostdinc$(sm) := -nostdinc -isystem $(shell $(CC$(sm)) \ -print-file-name=include 2> /dev/null) # Get location of libgcc from gcc -libgcc$(sm) := $(shell $(CC$(sm)) $(CFLAGS$(arch-bits-$(sm))) \ +libgcc$(sm) := $(shell $(CC$(sm)) $(LIBGCC_LOCATE_CFLAGS) $(CFLAGS$(arch-bits-$(sm))) \ -print-libgcc-file-name 2> /dev/null) -libstdc++$(sm) := $(shell $(CXX$(sm)) $(CXXFLAGS$(arch-bits-$(sm))) $(comp-cxxflags$(sm)) \ +libstdc++$(sm) := $(shell $(CXX$(sm)) $(LIBGCC_LOCATE_CFLAGS) $(CXXFLAGS$(arch-bits-$(sm))) $(comp-cxxflags$(sm)) \ -print-file-name=libstdc++.a 2> /dev/null) -libgcc_eh$(sm) := $(shell $(CXX$(sm)) $(CXXFLAGS$(arch-bits-$(sm))) $(comp-cxxflags$(sm)) \ +libgcc_eh$(sm) := $(shell $(CXX$(sm)) $(LIBGCC_LOCATE_CFLAGS) $(CXXFLAGS$(arch-bits-$(sm))) $(comp-cxxflags$(sm)) \ -print-file-name=libgcc_eh.a 2> /dev/null) # Define these to something to discover accidental use diff --git a/scripts/sign_rproc_fw.py b/scripts/sign_rproc_fw.py new file mode 100755 index 000000000..4248ed280 --- /dev/null +++ b/scripts/sign_rproc_fw.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (C) 2020, STMicroelectronics - All Rights Reserved +# + +try: + from elftools.elf.elffile import ELFFile + from elftools.elf.sections import SymbolTableSection + from elftools.elf.enums import ENUM_P_TYPE_BASE + from elftools.elf.enums import * +except ImportError: + print(""" +*** +ERROR: pyelftools python module is not installed or version < 0.25. +*** +""") + raise + +from Cryptodome.Hash import SHA256 +from Cryptodome.Signature import pkcs1_15 +from Cryptodome.PublicKey import RSA +from Cryptodome.Signature import DSS +from Cryptodome.PublicKey import ECC +import os +import sys +import struct +import logging +import binascii + + +logging.basicConfig(stream=sys.stderr, level=logging.INFO) + +ENUM_HASH_TYPE = dict( + SHA256=1, +) + +ENUM_SIGNATURE_TYPE = dict( + RSA=1, + ECC=2, +) + +ENUM_BINARY_TYPE = dict( + ELF=1, +) + + +def dump_buffer(buf, step=16, name="", logger=logging.info, indent=""): + logger("%s%s:" % (indent, name)) + for i in range(0, len(buf), step): + logger("%s " % (indent) + " ". + join(["%02X" % c for c in buf[i:i+step]])) + logger("\n") + + +class RSA_Signature(object): + + def __init__(self, key): + self._hasher = SHA256.new() + self.signer = pkcs1_15.new(key) + + def hash_compute(self, segment): + self._hasher.update(segment) + + def sign(self): + return self.signer.sign(self._hasher) + + +class ECC_Signature(object): + + def __init__(self, key): + self._hasher = SHA256.new() + self.signer = DSS.new(key, 'fips-186-3') + + def hash_compute(self, segment): + self._hasher.update(segment) + + def sign(self): + return self.signer.sign(self._hasher) + + +Signature = { + 1: RSA_Signature, + 2: ECC_Signature, +} + + +class SegmentHashStruct: + pass + + +class SegmentHash(object): + ''' + Hash table based on Elf program segments + ''' + def __init__(self, img): + self._num_segments = img.num_segments() + self._pack_fmt = '<%dL' % 8 + self.img = img + self.hashProgTable = bytes() + self._offset = 0 + + def get_table(self): + ''' + Create a segment hash table containing for each segment: + - the segments header + - a hash of the segment + ''' + h = SHA256.new() + seg = SegmentHashStruct() + self.size = (h.digest_size + 32) * self._num_segments + logging.debug("hash section size %d" % self.size) + del h + self.buf = bytearray(self.size) + self._bufview_ = memoryview(self.buf) + + for i in range(self._num_segments): + h = SHA256.new() + segment = self.img.get_segment(i) + seg.header = self.img.get_segment(i).header + logging.debug("compute hash for segment offset %s" % seg.header) + h.update(segment.data()) + seg.hash = h.digest() + logging.debug("hash computed: %s" % seg.hash) + del h + struct.pack_into('.sig') + + parsed = parser.parse_args() + + # Set defaults for optional arguments. + + if parsed.outf is None: + parsed.outf = str(parsed.inf)+'.sig' + + return parsed + + +def rsa_key(keyf): + return RSA.importKey(open(keyf).read()) + + +def ecc_key(keyf): + return ECC.import_key(open(keyf).read()) + + +key_type = { + 1: rsa_key, + 2: ecc_key, +} + + +def rsa_sig_size(key): + return key.size_in_bytes() + + +def ecc_sig_size(key): + # to be improve... + # DSA size is N/4 so 64 for DSA (L,N) = (2048, 256) + return 64 + + +sig_size_type = { + 1: rsa_sig_size, + 2: ecc_sig_size, +} + + +def main(): + from Cryptodome.Signature import pss + from Cryptodome.Hash import SHA256 + from Cryptodome.PublicKey import RSA + import base64 + import logging + import struct + + logging.basicConfig() + logger = logging.getLogger(os.path.basename(__file__)) + + args = get_args(logger) + + # Initialise the header */ + s_header = ImageHeader() + + get_key = key_type.get(ENUM_SIGNATURE_TYPE[args.key_type], + lambda: "Invalid sign type") + key = get_key(args.keyf) + + if not key.has_private(): + logger.error('Provided key cannot be used for signing, ' + + 'please use offline-signing mode.') + sys.exit(1) + + # Firmware image + input_file = open(args.inf, 'rb') + img = ELFFile(input_file) + + # need to reopen the file to get the raw data + with open(args.inf, 'rb') as f: + bin_img = f.read() + img_size = len(bin_img) + logging.debug("image size %d" % img_size) + s_header.img_length = img_size + s_header.img_type = ENUM_BINARY_TYPE['ELF'] + + # Hash table chunk + h = SHA256.new() + + # Compute the hash table + hash_table = SegmentHash(img) + hash = hash_table.get_table() + + s_header.hash_offset = s_header.size + s_header.hash_length = hash_table.size + s_header.hash_type = ENUM_HASH_TYPE['SHA256'] + # Get padding to align on 64 bytes + hash_align = s_header.hash_length % 8 + + # Key information chunk + if args.key_infof: + with open(args.key_infof, 'rb') as f: + key_info = f.read() + s_header.key_length = sys.getsizeof(key_info) + s_header.key_offset = s_header.hash_offset + s_header.hash_length + \ + hash_align + # Get padding to align on 64 bytes + key_info_align = s_header.key_length % 8 + else: + key_info_align = 0 + + # Signature chunk + s_header.sign_type = ENUM_SIGNATURE_TYPE[args.key_type] + + sign_size = sig_size_type.get(ENUM_SIGNATURE_TYPE[args.key_type], + lambda: "Invalid sign type")(key) + s_header.sign_length = sign_size + + if args.key_infof: + s_header.sign_offset = s_header.key_offset + s_header.key_length + \ + key_info_align + else: + s_header.sign_offset = s_header.hash_offset + s_header.hash_length + \ + hash_align + + s_header.img_offset = s_header.sign_offset + sign_size + + s_header.length = s_header.size + s_header.hash_length + hash_align + \ + s_header.key_length + key_info_align + s_header.sign_length + + header = s_header.get_packed() + + # Generate signature + signer = Signature.get(ENUM_SIGNATURE_TYPE[args.key_type])(key) + + signer.hash_compute(header) + signer.hash_compute(bytes(hash)) + if args.key_infof: + signer.hash_compute(key_info) + + signature = signer.sign() + if len(signature) != sign_size: + raise Exception(("Actual signature length is not equal to ", + "the computed one: {} != {}". + format(len(signature), sign_size))) + + s_header.dump() + + with open(args.outf, 'wb') as f: + f.write(header) + f.write(hash) + if hash_align: + f.write(bytearray(hash_align)) + if args.key_infof: + if key_info_align: + f.write(key_info) + f.write(bytearray(key_info_align)) + f.write(signature) + f.write(bytearray(sign_size - s_header.sign_length)) + f.write(bin_img) + + +if __name__ == "__main__": + main() diff --git a/ta/remoteproc/Makefile b/ta/remoteproc/Makefile new file mode 100644 index 000000000..0d1a5010c --- /dev/null +++ b/ta/remoteproc/Makefile @@ -0,0 +1,18 @@ +# The UUID for the Trusted Application +BINARY=80a4c275-0a47-4905-8285-1486a9771a08 + +ifdef TA_CROSS_COMPILE +CROSS_COMPILE ?= $(TA_CROSS_COMPILE) +endif +export CROSS_COMPILE + +CFG_TEE_TA_LOG_LEVEL ?= 2 +CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL) + +-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk + +ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) +clean: + @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' + @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' +endif diff --git a/ta/remoteproc/elf_parser.c b/ta/remoteproc/elf_parser.c new file mode 100644 index 000000000..da3e6f4ae --- /dev/null +++ b/ta/remoteproc/elf_parser.c @@ -0,0 +1,186 @@ + // SPDX-License-Identifier: BSD-2-Clause + /* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include + +static bool va_in_fwm_image_range(void *va, uint8_t *fw, size_t fw_size) +{ + uint8_t *vaddr = va; + + assert(fw + fw_size >= fw); + return vaddr >= fw && vaddr < fw + fw_size; +} + +/* + * e32_parse_ehdr() - Check and parse the ELF header + * + * fw: Firmware ELF file image + * size: Byte size of firmware ELF file image + */ +TEE_Result e32_parse_ehdr(uint8_t *fw, size_t size) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw; + + if (!fw || !ALIGNMENT_IS_OK(fw, uint32_t)) { + EMSG("Invalid fw address %p", fw); + return TEE_ERROR_BAD_PARAMETERS; + } + + if (size < sizeof(Elf32_Ehdr) || + size < (ehdr->e_shoff + sizeof(Elf32_Shdr))) + return TEE_ERROR_CORRUPT_OBJECT; + + if (!IS_ELF(*ehdr) || + ehdr->e_ident[EI_VERSION] != EV_CURRENT || + ehdr->e_ident[EI_CLASS] != ELFCLASS32 || + ehdr->e_phentsize != sizeof(Elf32_Phdr) || + ehdr->e_shentsize != sizeof(Elf32_Shdr)) { + EMSG("Invalid header"); + + return TEE_ERROR_BAD_FORMAT; + } + + if (ehdr->e_phnum == 0) { + EMSG("No loadable segment found"); + return TEE_ERROR_BAD_FORMAT; + } + + return TEE_SUCCESS; +} + +/* + * e32_parser_load_elf_image - simple ELF loader + * fw: Firmware ELF file image + * fw_size: Firmware ELF file image byte size + * load_seg: Callback for loading a firmware image segment into device memory + * priv_data: Private data passed to @load_seg callback. + */ +TEE_Result e32_parser_load_elf_image(uint8_t *fw, size_t fw_size, + TEE_Result (*load_seg)(uint8_t *src, + uint32_t size, + uint32_t da, + uint32_t mem_size, + void *priv), + void *priv_data) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw; + Elf32_Phdr *phdr = (void *)((int8_t *)ehdr + ehdr->e_phoff); + TEE_Result res = TEE_SUCCESS; + unsigned int i = 0; + + if (!load_seg) + return TEE_ERROR_BAD_PARAMETERS; + + if (!ALIGNMENT_IS_OK(phdr, uint32_t) || + !va_in_fwm_image_range(phdr, fw, fw_size)) + return TEE_ERROR_CORRUPT_OBJECT; + + for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + uint32_t dst = phdr->p_paddr; + uint8_t *src = NULL; + + if (!va_in_fwm_image_range((void *)((vaddr_t)(phdr + 1) - 1), + fw, fw_size)) + return TEE_ERROR_CORRUPT_OBJECT; + + if (phdr->p_type != PT_LOAD) + continue; + + src = (uint8_t *)fw + phdr->p_offset; + + if (!va_in_fwm_image_range(src, fw, fw_size) || + !va_in_fwm_image_range(src + phdr->p_filesz, fw, fw_size)) + return TEE_ERROR_CORRUPT_OBJECT; + + res = load_seg(src, phdr->p_filesz, dst, phdr->p_memsz, + priv_data); + if (res) + return res; + } + + return TEE_SUCCESS; +} + +/* Helper to find resource table in an ELF image */ +int e32_parser_find_rsc_table(uint8_t *fw, size_t fw_size, + Elf32_Addr *rsc_addr, Elf32_Word *rsc_size) +{ + Elf32_Shdr *shdr = NULL; + int i = 0; + char *name_table = NULL; + struct resource_table *table = NULL; + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw; + uint8_t *elf_data = fw; + + shdr = (void *)(fw + ehdr->e_shoff); + if (!ALIGNMENT_IS_OK(shdr, uint32_t) || + !va_in_fwm_image_range(shdr, fw, fw_size)) + return TEE_ERROR_CORRUPT_OBJECT; + + name_table = (char *)elf_data + shdr[ehdr->e_shstrndx].sh_offset; + if (!va_in_fwm_image_range(name_table, fw, fw_size)) + return TEE_ERROR_CORRUPT_OBJECT; + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + size_t size = shdr->sh_size; + size_t offset = shdr->sh_offset; + + if (!va_in_fwm_image_range(shdr, fw, fw_size)) + return TEE_ERROR_CORRUPT_OBJECT; + + if (strcmp(name_table + shdr->sh_name, ".resource_table")) + continue; + + if (!shdr->sh_size) { + IMSG("Ignore empty resource table section"); + return TEE_ERROR_NO_DATA; + } + + if (offset + size > fw_size || offset + size < size) { + EMSG("Resource table truncated"); + return TEE_ERROR_BAD_FORMAT; + } + + if (sizeof(struct resource_table) > size) { + EMSG("No header found in resource table"); + return TEE_ERROR_BAD_FORMAT; + } + + table = (struct resource_table *)(void *)(elf_data + offset); + if (!ALIGNMENT_IS_OK(table, uint32_t)) + return TEE_ERROR_CORRUPT_OBJECT; + + if (table->ver != 1) { + EMSG("Unsupported fw version %"PRId32, table->ver); + return TEE_ERROR_BAD_FORMAT; + } + + if (table->reserved[0] || table->reserved[1]) { + EMSG("Non zero reserved bytes"); + return TEE_ERROR_BAD_FORMAT; + } + + if (table->num * sizeof(*table->offset) + + sizeof(struct resource_table) > size) { + EMSG("Resource table incomplete"); + return TEE_ERROR_BAD_FORMAT; + } + + DMSG("Resource table address %#"PRIx32", size %"PRIu32, + shdr->sh_addr, shdr->sh_size); + + *rsc_addr = shdr->sh_addr; + *rsc_size = shdr->sh_size; + + return TEE_SUCCESS; + } + + return TEE_ERROR_NO_DATA; +} diff --git a/ta/remoteproc/include/elf32.h b/ta/remoteproc/include/elf32.h new file mode 100644 index 000000000..2806c615d --- /dev/null +++ b/ta/remoteproc/include/elf32.h @@ -0,0 +1,243 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*- + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_ELF32_H_ +#define _SYS_ELF32_H_ 1 + +#include +#include + +/* + * ELF definitions common to all 32-bit architectures. + */ + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; +typedef uint64_t Elf32_Lword; + +typedef Elf32_Word Elf32_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf32_Word Elf32_Size; +typedef Elf32_Sword Elf32_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf32_Half e_type; /* File type. */ + Elf32_Half e_machine; /* Machine architecture. */ + Elf32_Word e_version; /* ELF format version. */ + Elf32_Addr e_entry; /* Entry point. */ + Elf32_Off e_phoff; /* Program header file offset. */ + Elf32_Off e_shoff; /* Section header file offset. */ + Elf32_Word e_flags; /* Architecture-specific flags. */ + Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf32_Half e_phentsize; /* Size of program header entry. */ + Elf32_Half e_phnum; /* Number of program header entries. */ + Elf32_Half e_shentsize; /* Size of section header entry. */ + Elf32_Half e_shnum; /* Number of section header entries. */ + Elf32_Half e_shstrndx; /* Section name strings section. */ +} Elf32_Ehdr; + +/* + * Section header. + */ + +typedef struct { + Elf32_Word sh_name; /* Section name (index into the + section header string table). */ + Elf32_Word sh_type; /* Section type. */ + Elf32_Word sh_flags; /* Section flags. */ + Elf32_Addr sh_addr; /* Address in memory image. */ + Elf32_Off sh_offset; /* Offset in file. */ + Elf32_Word sh_size; /* Size in bytes. */ + Elf32_Word sh_link; /* Index of a related section. */ + Elf32_Word sh_info; /* Depends on section type. */ + Elf32_Word sh_addralign; /* Alignment in bytes. */ + Elf32_Word sh_entsize; /* Size of each entry in section. */ +} Elf32_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf32_Word p_type; /* Entry type. */ + Elf32_Off p_offset; /* File offset of contents. */ + Elf32_Addr p_vaddr; /* Virtual address in memory image. */ + Elf32_Addr p_paddr; /* Physical address (not used). */ + Elf32_Word p_filesz; /* Size of contents in file. */ + Elf32_Word p_memsz; /* Size of contents in memory. */ + Elf32_Word p_flags; /* Access permission flags. */ + Elf32_Word p_align; /* Alignment in memory and file. */ +} Elf32_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf32_Sword d_tag; /* Entry type. */ + union { + Elf32_Word d_val; /* Integer value. */ + Elf32_Addr d_ptr; /* Address value. */ + } d_un; +} Elf32_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ +} Elf32_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf32_Addr r_offset; /* Location to be relocated. */ + Elf32_Word r_info; /* Relocation type and symbol index. */ + Elf32_Sword r_addend; /* Addend. */ +} Elf32_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +/* Macro for constructing r_info from field values. */ +#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) + +/* + * Note entry header + */ +typedef Elf_Note Elf32_Nhdr; + +/* + * Move entry + */ +typedef struct { + Elf32_Lword m_value; /* symbol value */ + Elf32_Word m_info; /* size + index */ + Elf32_Word m_poffset; /* symbol offset */ + Elf32_Half m_repeat; /* repeat count */ + Elf32_Half m_stride; /* stride info */ +} Elf32_Move; + +/* + * The macros compose and decompose values for Move.r_info + * + * sym = ELF32_M_SYM(M.m_info) + * size = ELF32_M_SIZE(M.m_info) + * M.m_info = ELF32_M_INFO(sym, size) + */ +#define ELF32_M_SYM(info) ((info)>>8) +#define ELF32_M_SIZE(info) ((unsigned char)(info)) +#define ELF32_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size)) + +/* + * Hardware/Software capabilities entry + */ +typedef struct { + Elf32_Word c_tag; /* how to interpret value */ + union { + Elf32_Word c_val; + Elf32_Addr c_ptr; + } c_un; +} Elf32_Cap; + +/* + * Symbol table entries. + */ + +typedef struct { + Elf32_Word st_name; /* String table index of name. */ + Elf32_Addr st_value; /* Symbol value. */ + Elf32_Word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf32_Half st_shndx; /* Section index of symbol. */ +} Elf32_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF32_ST_BIND(info) ((info) >> 4) +#define ELF32_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* Structures used by Sun & GNU symbol versioning. */ +typedef struct { + Elf32_Half vd_version; + Elf32_Half vd_flags; + Elf32_Half vd_ndx; + Elf32_Half vd_cnt; + Elf32_Word vd_hash; + Elf32_Word vd_aux; + Elf32_Word vd_next; +} Elf32_Verdef; + +typedef struct { + Elf32_Word vda_name; + Elf32_Word vda_next; +} Elf32_Verdaux; + +typedef struct { + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct { + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef Elf32_Half Elf32_Versym; + +typedef struct { + Elf32_Half si_boundto; /* direct bindings - symbol bound to */ + Elf32_Half si_flags; /* per symbol flags */ +} Elf32_Syminfo; + +#endif /* !_SYS_ELF32_H_ */ diff --git a/ta/remoteproc/include/elf_common.h b/ta/remoteproc/include/elf_common.h new file mode 100644 index 000000000..a1da0ef80 --- /dev/null +++ b/ta/remoteproc/include/elf_common.h @@ -0,0 +1,1014 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*- + * Copyright (c) 2000, 2001, 2008, 2011, David E. O'Brien + * Copyright (c) 1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_ELF_COMMON_H_ +#define _SYS_ELF_COMMON_H_ 1 + +#include + +/* + * ELF definitions that are independent of architecture or word size. + */ + +#ifndef __ASSEMBLER__ +/* + * Note header. The ".note" section contains an array of notes. Each + * begins with this header, aligned to a word boundary. Immediately + * following the note header is n_namesz bytes of name, padded to the + * next word boundary. Then comes n_descsz bytes of descriptor, again + * padded to a word boundary. The values of n_namesz and n_descsz do + * not include the padding. + */ + +typedef struct { + uint32_t n_namesz; /* Length of name. */ + uint32_t n_descsz; /* Length of descriptor. */ + uint32_t n_type; /* Type of this note. */ +} Elf_Note; + +/* + * The header for GNU-style hash sections. + */ + +typedef struct { + uint32_t gh_nbuckets; /* Number of hash buckets. */ + uint32_t gh_symndx; /* First visible symbol in .dynsym. */ + uint32_t gh_maskwords; /* #maskwords used in bloom filter. */ + uint32_t gh_shift2; /* Bloom filter shift count. */ +} Elf_GNU_Hash_Header; +#endif /*__ASSEMBLER__*/ + +/* Indexes into the e_ident array. Keep synced with + http://www.sco.com/developers/gabi/latest/ch4.eheader.html */ +#define EI_MAG0 0 /* Magic number, byte 0. */ +#define EI_MAG1 1 /* Magic number, byte 1. */ +#define EI_MAG2 2 /* Magic number, byte 2. */ +#define EI_MAG3 3 /* Magic number, byte 3. */ +#define EI_CLASS 4 /* Class of machine. */ +#define EI_DATA 5 /* Data format. */ +#define EI_VERSION 6 /* ELF format version. */ +#define EI_OSABI 7 /* Operating system / ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#define OLD_EI_BRAND 8 /* Start of architecture identification. */ +#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ +#define EI_NIDENT 16 /* Size of e_ident array. */ + +/* Values for the magic number bytes. */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" /* magic string */ +#define SELFMAG 4 /* magic string size */ + +/* Values for e_ident[EI_VERSION] and e_version. */ +#define EV_NONE 0 +#define EV_CURRENT 1 + +/* Values for e_ident[EI_CLASS]. */ +#define ELFCLASSNONE 0 /* Unknown class. */ +#define ELFCLASS32 1 /* 32-bit architecture. */ +#define ELFCLASS64 2 /* 64-bit architecture. */ + +/* Values for e_ident[EI_DATA]. */ +#define ELFDATANONE 0 /* Unknown data format. */ +#define ELFDATA2LSB 1 /* 2's complement little-endian. */ +#define ELFDATA2MSB 2 /* 2's complement big-endian. */ + +/* Values for e_ident[EI_OSABI]. */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* Open VMS */ +#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_AROS 15 /* Amiga Research OS */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ +#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ +#define ET_LOOS 0xfe00 /* First operating system specific. */ +#define ET_HIOS 0xfeff /* Last operating system-specific. */ +#define ET_LOPROC 0xff00 /* First processor-specific. */ +#define ET_HIPROC 0xffff /* Last processor-specific. */ + +/* Values for e_machine. */ +#define EM_NONE 0 /* Unknown machine. */ +#define EM_M32 1 /* AT&T WE32100. */ +#define EM_SPARC 2 /* Sun SPARC. */ +#define EM_386 3 /* Intel i386. */ +#define EM_68K 4 /* Motorola 68000. */ +#define EM_88K 5 /* Motorola 88000. */ +#define EM_860 7 /* Intel i860. */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ +#define EM_S370 9 /* IBM System/370. */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ +#define EM_PARISC 15 /* HP PA-RISC. */ +#define EM_VPP500 17 /* Fujitsu VPP500. */ +#define EM_SPARC32PLUS 18 /* SPARC v8plus. */ +#define EM_960 19 /* Intel 80960. */ +#define EM_PPC 20 /* PowerPC 32-bit. */ +#define EM_PPC64 21 /* PowerPC 64-bit. */ +#define EM_S390 22 /* IBM System/390. */ +#define EM_V800 36 /* NEC V800. */ +#define EM_FR20 37 /* Fujitsu FR20. */ +#define EM_RH32 38 /* TRW RH-32. */ +#define EM_RCE 39 /* Motorola RCE. */ +#define EM_ARM 40 /* ARM. */ +#define EM_SH 42 /* Hitachi SH. */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit. */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ +#define EM_ARC 45 /* Argonaut RISC Core. */ +#define EM_H8_300 46 /* Hitachi H8/300. */ +#define EM_H8_300H 47 /* Hitachi H8/300H. */ +#define EM_H8S 48 /* Hitachi H8S. */ +#define EM_H8_500 49 /* Hitachi H8/500. */ +#define EM_IA_64 50 /* Intel IA-64 Processor. */ +#define EM_MIPS_X 51 /* Stanford MIPS-X. */ +#define EM_COLDFIRE 52 /* Motorola ColdFire. */ +#define EM_68HC12 53 /* Motorola M68HC12. */ +#define EM_MMA 54 /* Fujitsu MMA. */ +#define EM_PCP 55 /* Siemens PCP. */ +#define EM_NCPU 56 /* Sony nCPU. */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor. */ +#define EM_STARCORE 58 /* Motorola Star*Core processor. */ +#define EM_ME16 59 /* Toyota ME16 processor. */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor. */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ +#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ +#define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ +#define EM_PDSP 63 /* Sony DSP Processor. */ +#define EM_FX66 66 /* Siemens FX66 microcontroller. */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 + microcontroller. */ +#define EM_ST7 68 /* STmicroelectronics ST7 8-bit + microcontroller. */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller. */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller. */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller. */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller. */ +#define EM_SVX 73 /* Silicon Graphics SVx. */ +#define EM_ST19 74 /* STMicroelectronics ST19 8-bit mc. */ +#define EM_VAX 75 /* Digital VAX. */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded + processor. */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded + processor. */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor. */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor. */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc. */ +#define EM_HUANY 81 /* Harvard University machine-independent + object files. */ +#define EM_PRISM 82 /* SiTera Prism. */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller. */ +#define EM_FR30 84 /* Fujitsu FR30. */ +#define EM_D10V 85 /* Mitsubishi D10V. */ +#define EM_D30V 86 /* Mitsubishi D30V. */ +#define EM_V850 87 /* NEC v850. */ +#define EM_M32R 88 /* Mitsubishi M32R. */ +#define EM_MN10300 89 /* Matsushita MN10300. */ +#define EM_MN10200 90 /* Matsushita MN10200. */ +#define EM_PJ 91 /* picoJava. */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor. */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5. */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture. */ +#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor. */ +#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose + Processor. */ +#define EM_NS32K 97 /* National Semiconductor 32000 series. */ +#define EM_TPC 98 /* Tenor Network TPC processor. */ +#define EM_SNP1K 99 /* Trebia SNP 1000 processor. */ +#define EM_ST200 100 /* STMicroelectronics ST200 microcontroller. */ +#define EM_IP2K 101 /* Ubicom IP2xxx microcontroller family. */ +#define EM_MAX 102 /* MAX Processor. */ +#define EM_CR 103 /* National Semiconductor CompactRISC + microprocessor. */ +#define EM_F2MC16 104 /* Fujitsu F2MC16. */ +#define EM_MSP430 105 /* Texas Instruments embedded microcontroller + msp430. */ +#define EM_BLACKFIN 106 /* Analog Devices Blackfin (DSP) processor. */ +#define EM_SE_C33 107 /* S1C33 Family of Seiko Epson processors. */ +#define EM_SEP 108 /* Sharp embedded microprocessor. */ +#define EM_ARCA 109 /* Arca RISC Microprocessor. */ +#define EM_UNICORE 110 /* Microprocessor series from PKU-Unity Ltd. + and MPRC of Peking University */ +#define EM_AARCH64 183 /* AArch64 (64-bit ARM) */ + +/* Non-standard or deprecated. */ +#define EM_486 6 /* Intel i486. */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ +#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ + +/* e_flags for EM_ARM */ +#define EF_ARM_ABI_VERSION 0x05000000 /* ABI version 5 */ +#define EF_ARM_ABIMASK 0xFF000000 +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_ABI_FLOAT_HARD 0x00000400 /* ABI version 5 and later */ +#define EF_ARM_ABI_FLOAT_SOFT 0x00000200 /* ABI version 5 and later */ + +/* Special section indexes. */ +#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ +#define SHN_LORESERVE 0xff00 /* First of reserved range. */ +#define SHN_LOPROC 0xff00 /* First processor-specific. */ +#define SHN_HIPROC 0xff1f /* Last processor-specific. */ +#define SHN_LOOS 0xff20 /* First operating system-specific. */ +#define SHN_HIOS 0xff3f /* Last operating system-specific. */ +#define SHN_ABS 0xfff1 /* Absolute values. */ +#define SHN_COMMON 0xfff2 /* Common data. */ +#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ +#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends */ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relocation section - no addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ +#define SHT_FINI_ARRAY 15 /* Termination function pointers. */ +#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ +#define SHT_GROUP 17 /* Section group. */ +#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_LOSUNW 0x6ffffff4 +#define SHT_SUNW_dof 0x6ffffff4 +#define SHT_SUNW_cap 0x6ffffff5 +#define SHT_SUNW_SIGNATURE 0x6ffffff6 +#define SHT_GNU_HASH 0x6ffffff6 +#define SHT_GNU_LIBLIST 0x6ffffff7 +#define SHT_SUNW_ANNOTATE 0x6ffffff7 +#define SHT_SUNW_DEBUGSTR 0x6ffffff8 +#define SHT_SUNW_DEBUG 0x6ffffff9 +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_SUNW_verdef 0x6ffffffd +#define SHT_GNU_verdef 0x6ffffffd /* Symbol versions provided */ +#define SHT_SUNW_verneed 0x6ffffffe +#define SHT_GNU_verneed 0x6ffffffe /* Symbol versions required */ +#define SHT_SUNW_versym 0x6fffffff +#define SHT_GNU_versym 0x6fffffff /* Symbol version table */ +#define SHT_HISUNW 0x6fffffff +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_AMD64_UNWIND 0x70000001 /* unwind information */ +#define SHT_ARM_EXIDX 0x70000001 /* Exception index table. */ +#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking + pre-emption map. */ +#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility + attributes. */ +#define SHT_ARM_DEBUGOVERLAY 0x70000004 /* See DBGOVL for details. */ +#define SHT_ARM_OVERLAYSECTION 0x70000005 /* See DBGOVL for details. */ +#define SHT_MIPS_REGINFO 0x70000006 +#define SHT_MIPS_OPTIONS 0x7000000d +#define SHT_MIPS_DWARF 0x7000001e /* MIPS gcc uses MIPS_DWARF */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Flags for sh_flags. */ +#define SHF_WRITE 0x1 /* Section contains writable data. */ +#define SHF_ALLOC 0x2 /* Section occupies memory. */ +#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ +#define SHF_MERGE 0x10 /* Section may be merged. */ +#define SHF_STRINGS 0x20 /* Section contains strings. */ +#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ +#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ +#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ +#define SHF_GROUP 0x200 /* Member of section group. */ +#define SHF_TLS 0x400 /* Section contains TLS data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ + +/* Values for p_type. */ +#define PT_NULL 0 /* Unused entry. */ +#define PT_LOAD 1 /* Loadable segment. */ +#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ +#define PT_INTERP 3 /* Pathname of interpreter. */ +#define PT_NOTE 4 /* Auxiliary information. */ +#define PT_SHLIB 5 /* Reserved (not used). */ +#define PT_PHDR 6 /* Location of program header itself. */ +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* First OS-specific. */ +#define PT_SUNW_UNWIND 0x6464e550 /* amd64 UNWIND program header */ +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_STACK 0x6474e551 +#define PT_GNU_RELRO 0x6474e552 +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* describes the stack segment */ +#define PT_SUNWDTRACE 0x6ffffffc /* private */ +#define PT_SUNWCAP 0x6ffffffd /* hard/soft capabilities segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* Last OS-specific. */ +#define PT_LOPROC 0x70000000 /* First processor-specific type. */ +#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ +#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for p_flags. */ +#define PF_X 0x1 /* Executable. */ +#define PF_W 0x2 /* Writable. */ +#define PF_R 0x4 /* Readable. */ +#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific. */ + +/* Extended program header index. */ +#define PN_XNUM 0xffff + +/* Values for d_tag. */ +#define DT_NULL 0 /* Terminating entry. */ +#define DT_NEEDED 1 /* String table offset of a needed shared + library. */ +#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ +#define DT_PLTGOT 3 /* Processor-dependent address. */ +#define DT_HASH 4 /* Address of symbol hash table. */ +#define DT_STRTAB 5 /* Address of string table. */ +#define DT_SYMTAB 6 /* Address of symbol table. */ +#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ +#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ +#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ +#define DT_STRSZ 10 /* Size of string table. */ +#define DT_SYMENT 11 /* Size of each symbol table entry. */ +#define DT_INIT 12 /* Address of initialization function. */ +#define DT_FINI 13 /* Address of finalization function. */ +#define DT_SONAME 14 /* String table offset of shared object + name. */ +#define DT_RPATH 15 /* String table offset of library path. [sup] */ +#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ +#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ +#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ +#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ +#define DT_PLTREL 20 /* Type of relocation used for PLT. */ +#define DT_DEBUG 21 /* Reserved (not used). */ +#define DT_TEXTREL 22 /* Indicates there may be relocations in + non-writable segments. [sup] */ +#define DT_JMPREL 23 /* Address of PLT relocations. */ +#define DT_BIND_NOW 24 /* [sup] */ +#define DT_INIT_ARRAY 25 /* Address of the array of pointers to + initialization functions */ +#define DT_FINI_ARRAY 26 /* Address of the array of pointers to + termination functions */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of + initialization functions. */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of + termination functions. */ +#define DT_RUNPATH 29 /* String table offset of a null-terminated + library search path string. */ +#define DT_FLAGS 30 /* Object specific flag values. */ +#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', odd == 'd_val' + or none */ +#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to + pre-initialization functions. */ +#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of + pre-initialization functions. */ +#define DT_MAXPOSTAGS 34 /* number of positive tags */ +#define DT_LOOS 0x6000000d /* First OS-specific */ +#define DT_SUNW_AUXILIARY 0x6000000d /* symbol auxiliary name */ +#define DT_SUNW_RTLDINF 0x6000000e /* ld.so.1 info (private) */ +#define DT_SUNW_FILTER 0x6000000f /* symbol filter name */ +#define DT_SUNW_CAP 0x60000010 /* hardware/software */ +#define DT_HIOS 0x6ffff000 /* Last OS-specific */ + +/* + * DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + * Dyn.d_un.d_val field of the Elf*_Dyn structure. + */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_CHECKSUM 0x6ffffdf8 /* elf checksum */ +#define DT_PLTPADSZ 0x6ffffdf9 /* pltpadding size */ +#define DT_MOVEENT 0x6ffffdfa /* move table entry size */ +#define DT_MOVESZ 0x6ffffdfb /* move table size */ +#define DT_FEATURE_1 0x6ffffdfc /* feature holder */ +#define DT_POSFLAG_1 0x6ffffdfd /* flags for DT_* entries, effecting */ + /* the following DT_* entry. */ + /* See DF_P1_* definitions */ +#define DT_SYMINSZ 0x6ffffdfe /* syminfo table size (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* syminfo entry size (in bytes) */ +#define DT_VALRNGHI 0x6ffffdff + +/* + * DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + * Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + * + * If any adjustment is made to the ELF object after it has been + * built, these entries will need to be adjusted. + */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table */ +#define DT_CONFIG 0x6ffffefa /* configuration information */ +#define DT_DEPAUDIT 0x6ffffefb /* dependency auditing */ +#define DT_AUDIT 0x6ffffefc /* object auditing */ +#define DT_PLTPAD 0x6ffffefd /* pltpadding (sparcv9) */ +#define DT_MOVETAB 0x6ffffefe /* move table */ +#define DT_SYMINFO 0x6ffffeff /* syminfo table */ +#define DT_ADDRRNGHI 0x6ffffeff + +#define DT_VERSYM 0x6ffffff0 /* Address of versym section. */ +#define DT_RELACOUNT 0x6ffffff9 /* number of RELATIVE relocations */ +#define DT_RELCOUNT 0x6ffffffa /* number of RELATIVE relocations */ +#define DT_FLAGS_1 0x6ffffffb /* state flags - see DF_1_* defs */ +#define DT_VERDEF 0x6ffffffc /* Address of verdef section. */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of elems in verdef section */ +#define DT_VERNEED 0x6ffffffe /* Address of verneed section. */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of elems in verneed section */ + +#define DT_LOPROC 0x70000000 /* First processor-specific type. */ +#define DT_DEPRECATED_SPARC_REGISTER 0x7000001 +#define DT_AUXILIARY 0x7ffffffd /* shared library auxiliary name */ +#define DT_USED 0x7ffffffe /* ignored - same as needed */ +#define DT_FILTER 0x7fffffff /* shared library filter name */ +#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ + +/* Values for DT_FLAGS */ +#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may + make reference to the $ORIGIN substitution + string */ +#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ +#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in + non-writable segments. */ +#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ +#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ + +/* Values for DT_FLAGS_1 */ +#define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */ +#define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */ +#define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */ +#define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filtees */ +#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ +#define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */ +#define DF_1_INTERPOSE 0x00000400 /* Interpose all objects but main */ +#define DF_1_NODEFLIB 0x00000800 /* Do not search default paths */ + +/* Values for n_type. Used in core files. */ +#define NT_PRSTATUS 1 /* Process status. */ +#define NT_FPREGSET 2 /* Floating point registers. */ +#define NT_PRPSINFO 3 /* Process state info. */ +#define NT_THRMISC 7 /* Thread miscellaneous info. */ +#define NT_PROCSTAT_PROC 8 /* Procstat proc data. */ +#define NT_PROCSTAT_FILES 9 /* Procstat files data. */ +#define NT_PROCSTAT_VMMAP 10 /* Procstat vmmap data. */ +#define NT_PROCSTAT_GROUPS 11 /* Procstat groups data. */ +#define NT_PROCSTAT_UMASK 12 /* Procstat umask data. */ +#define NT_PROCSTAT_RLIMIT 13 /* Procstat rlimit data. */ +#define NT_PROCSTAT_OSREL 14 /* Procstat osreldate data. */ +#define NT_PROCSTAT_PSSTRINGS 15 /* Procstat ps_strings data. */ +#define NT_PROCSTAT_AUXV 16 /* Procstat auxv data. */ + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_LOOS 10 /* Reserved range for operating system */ +#define STB_HIOS 12 /* specific semantics. */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific semantics. */ + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* Unspecified type. */ +#define STT_OBJECT 1 /* Data object. */ +#define STT_FUNC 2 /* Function. */ +#define STT_SECTION 3 /* Section. */ +#define STT_FILE 4 /* Source file. */ +#define STT_COMMON 5 /* Uninitialized common block. */ +#define STT_TLS 6 /* TLS object. */ +#define STT_NUM 7 +#define STT_LOOS 10 /* Reserved range for operating system */ +#define STT_GNU_IFUNC 10 +#define STT_HIOS 12 /* specific semantics. */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific semantics. */ + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0x0 /* Default visibility (see binding). */ +#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ +#define STV_HIDDEN 0x2 /* Not visible. */ +#define STV_PROTECTED 0x3 /* Visible but not preemptible. */ +#define STV_EXPORTED 0x4 +#define STV_SINGLETON 0x5 +#define STV_ELIMINATE 0x6 + +/* Special symbol table indexes. */ +#define STN_UNDEF 0 /* Undefined symbol index. */ + +/* Symbol versioning flags. */ +#define VER_DEF_CURRENT 1 +#define VER_DEF_IDX(x) VER_NDX(x) + +#define VER_FLG_BASE 0x01 +#define VER_FLG_WEAK 0x02 + +#define VER_NEED_CURRENT 1 +#define VER_NEED_WEAK (1u << 15) +#define VER_NEED_HIDDEN VER_NDX_HIDDEN +#define VER_NEED_IDX(x) VER_NDX(x) + +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 +#define VER_NDX_GIVEN 2 + +#define VER_NDX_HIDDEN (1u << 15) +#define VER_NDX(x) ((x) & ~(1u << 15)) + +#define CA_SUNW_NULL 0 +#define CA_SUNW_HW_1 1 /* first hardware capabilities entry */ +#define CA_SUNW_SF_1 2 /* first software capabilities entry */ + +/* + * Syminfo flag values + */ +#define SYMINFO_FLG_DIRECT 0x0001 /* symbol ref has direct association */ + /* to object containing defn. */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* ignored - see SYMINFO_FLG_FILTER */ +#define SYMINFO_FLG_COPY 0x0004 /* symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* object containing defn should be */ + /* lazily-loaded */ +#define SYMINFO_FLG_DIRECTBIND 0x0010 /* ref should be bound directly to */ + /* object containing defn. */ +#define SYMINFO_FLG_NOEXTDIRECT 0x0020 /* don't let an external reference */ + /* directly bind to this symbol */ +#define SYMINFO_FLG_FILTER 0x0002 /* symbol ref is associated to a */ +#define SYMINFO_FLG_AUXILIARY 0x0040 /* standard or auxiliary filter */ + +/* + * Syminfo.si_boundto values. + */ +#define SYMINFO_BT_SELF 0xffff /* symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* symbol bound to parent */ +#define SYMINFO_BT_NONE 0xfffd /* no special symbol binding */ +#define SYMINFO_BT_EXTERN 0xfffc /* symbol defined as external */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* beginning of reserved entries */ + +/* + * Syminfo version values. + */ +#define SYMINFO_NONE 0 /* Syminfo version */ +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* + * Relocation types. + * + * All machine architectures are defined here to allow tools on one to + * handle others. + */ + +#define R_386_NONE 0 /* No relocation. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_PC32 2 /* Add PC-relative symbol value. */ +#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ +#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ +#define R_386_COPY 5 /* Copy data from shared object. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ +#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ +#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ +#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ +#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ +#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ +#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ +#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ +#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ +#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ +#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ +#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ +#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ +#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ +#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ +#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ +#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ +#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ +#define R_386_IRELATIVE 42 /* PLT entry resolved indirectly at runtime */ + +#define R_AARCH64_ABS64 257 +#define R_AARCH64_GLOB_DAT 1025 /* Set GOT entry to data address. */ +#define R_AARCH64_JUMP_SLOT 1026 /* Set GOT entry to code address. */ +#define R_AARCH64_RELATIVE 1027 + +#define R_ARM_NONE 0 /* No relocation. */ +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +/* TLS relocations */ +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy data from shared object. */ +#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ +#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ +#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ +#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ +#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ +#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ +#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS32 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +/* Name Value Field Calculation */ +#define R_IA_64_NONE 0 /* None */ +#define R_IA_64_IMM14 0x21 /* immediate14 S + A */ +#define R_IA_64_IMM22 0x22 /* immediate22 S + A */ +#define R_IA_64_IMM64 0x23 /* immediate64 S + A */ +#define R_IA_64_DIR32MSB 0x24 /* word32 MSB S + A */ +#define R_IA_64_DIR32LSB 0x25 /* word32 LSB S + A */ +#define R_IA_64_DIR64MSB 0x26 /* word64 MSB S + A */ +#define R_IA_64_DIR64LSB 0x27 /* word64 LSB S + A */ +#define R_IA_64_GPREL22 0x2a /* immediate22 @gprel(S + A) */ +#define R_IA_64_GPREL64I 0x2b /* immediate64 @gprel(S + A) */ +#define R_IA_64_GPREL32MSB 0x2c /* word32 MSB @gprel(S + A) */ +#define R_IA_64_GPREL32LSB 0x2d /* word32 LSB @gprel(S + A) */ +#define R_IA_64_GPREL64MSB 0x2e /* word64 MSB @gprel(S + A) */ +#define R_IA_64_GPREL64LSB 0x2f /* word64 LSB @gprel(S + A) */ +#define R_IA_64_LTOFF22 0x32 /* immediate22 @ltoff(S + A) */ +#define R_IA_64_LTOFF64I 0x33 /* immediate64 @ltoff(S + A) */ +#define R_IA_64_PLTOFF22 0x3a /* immediate22 @pltoff(S + A) */ +#define R_IA_64_PLTOFF64I 0x3b /* immediate64 @pltoff(S + A) */ +#define R_IA_64_PLTOFF64MSB 0x3e /* word64 MSB @pltoff(S + A) */ +#define R_IA_64_PLTOFF64LSB 0x3f /* word64 LSB @pltoff(S + A) */ +#define R_IA_64_FPTR64I 0x43 /* immediate64 @fptr(S + A) */ +#define R_IA_64_FPTR32MSB 0x44 /* word32 MSB @fptr(S + A) */ +#define R_IA_64_FPTR32LSB 0x45 /* word32 LSB @fptr(S + A) */ +#define R_IA_64_FPTR64MSB 0x46 /* word64 MSB @fptr(S + A) */ +#define R_IA_64_FPTR64LSB 0x47 /* word64 LSB @fptr(S + A) */ +#define R_IA_64_PCREL60B 0x48 /* immediate60 form1 S + A - P */ +#define R_IA_64_PCREL21B 0x49 /* immediate21 form1 S + A - P */ +#define R_IA_64_PCREL21M 0x4a /* immediate21 form2 S + A - P */ +#define R_IA_64_PCREL21F 0x4b /* immediate21 form3 S + A - P */ +#define R_IA_64_PCREL32MSB 0x4c /* word32 MSB S + A - P */ +#define R_IA_64_PCREL32LSB 0x4d /* word32 LSB S + A - P */ +#define R_IA_64_PCREL64MSB 0x4e /* word64 MSB S + A - P */ +#define R_IA_64_PCREL64LSB 0x4f /* word64 LSB S + A - P */ +#define R_IA_64_LTOFF_FPTR22 0x52 /* immediate22 @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR64I 0x53 /* immediate64 @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR32MSB 0x54 /* word32 MSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR32LSB 0x55 /* word32 LSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR64MSB 0x56 /* word64 MSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_LTOFF_FPTR64LSB 0x57 /* word64 LSB @ltoff(@fptr(S + A)) */ +#define R_IA_64_SEGREL32MSB 0x5c /* word32 MSB @segrel(S + A) */ +#define R_IA_64_SEGREL32LSB 0x5d /* word32 LSB @segrel(S + A) */ +#define R_IA_64_SEGREL64MSB 0x5e /* word64 MSB @segrel(S + A) */ +#define R_IA_64_SEGREL64LSB 0x5f /* word64 LSB @segrel(S + A) */ +#define R_IA_64_SECREL32MSB 0x64 /* word32 MSB @secrel(S + A) */ +#define R_IA_64_SECREL32LSB 0x65 /* word32 LSB @secrel(S + A) */ +#define R_IA_64_SECREL64MSB 0x66 /* word64 MSB @secrel(S + A) */ +#define R_IA_64_SECREL64LSB 0x67 /* word64 LSB @secrel(S + A) */ +#define R_IA_64_REL32MSB 0x6c /* word32 MSB BD + A */ +#define R_IA_64_REL32LSB 0x6d /* word32 LSB BD + A */ +#define R_IA_64_REL64MSB 0x6e /* word64 MSB BD + A */ +#define R_IA_64_REL64LSB 0x6f /* word64 LSB BD + A */ +#define R_IA_64_LTV32MSB 0x74 /* word32 MSB S + A */ +#define R_IA_64_LTV32LSB 0x75 /* word32 LSB S + A */ +#define R_IA_64_LTV64MSB 0x76 /* word64 MSB S + A */ +#define R_IA_64_LTV64LSB 0x77 /* word64 LSB S + A */ +#define R_IA_64_PCREL21BI 0x79 /* immediate21 form1 S + A - P */ +#define R_IA_64_PCREL22 0x7a /* immediate22 S + A - P */ +#define R_IA_64_PCREL64I 0x7b /* immediate64 S + A - P */ +#define R_IA_64_IPLTMSB 0x80 /* function descriptor MSB special */ +#define R_IA_64_IPLTLSB 0x81 /* function descriptor LSB speciaal */ +#define R_IA_64_SUB 0x85 /* immediate64 A - S */ +#define R_IA_64_LTOFF22X 0x86 /* immediate22 special */ +#define R_IA_64_LDXMOV 0x87 /* immediate22 special */ +#define R_IA_64_TPREL14 0x91 /* imm14 @tprel(S + A) */ +#define R_IA_64_TPREL22 0x92 /* imm22 @tprel(S + A) */ +#define R_IA_64_TPREL64I 0x93 /* imm64 @tprel(S + A) */ +#define R_IA_64_TPREL64MSB 0x96 /* word64 MSB @tprel(S + A) */ +#define R_IA_64_TPREL64LSB 0x97 /* word64 LSB @tprel(S + A) */ +#define R_IA_64_LTOFF_TPREL22 0x9a /* imm22 @ltoff(@tprel(S+A)) */ +#define R_IA_64_DTPMOD64MSB 0xa6 /* word64 MSB @dtpmod(S + A) */ +#define R_IA_64_DTPMOD64LSB 0xa7 /* word64 LSB @dtpmod(S + A) */ +#define R_IA_64_LTOFF_DTPMOD22 0xaa /* imm22 @ltoff(@dtpmod(S+A)) */ +#define R_IA_64_DTPREL14 0xb1 /* imm14 @dtprel(S + A) */ +#define R_IA_64_DTPREL22 0xb2 /* imm22 @dtprel(S + A) */ +#define R_IA_64_DTPREL64I 0xb3 /* imm64 @dtprel(S + A) */ +#define R_IA_64_DTPREL32MSB 0xb4 /* word32 MSB @dtprel(S + A) */ +#define R_IA_64_DTPREL32LSB 0xb5 /* word32 LSB @dtprel(S + A) */ +#define R_IA_64_DTPREL64MSB 0xb6 /* word64 MSB @dtprel(S + A) */ +#define R_IA_64_DTPREL64LSB 0xb7 /* word64 LSB @dtprel(S + A) */ +#define R_IA_64_LTOFF_DTPREL22 0xba /* imm22 @ltoff(@dtprel(S+A)) */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ +#define R_MIPS_64 18 /* Direct 64 bit */ +#define R_MIPS_GOTHI16 21 /* GOT HI 16 bit */ +#define R_MIPS_GOTLO16 22 /* GOT LO 16 bit */ +#define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ +#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ + +#define R_PPC_NONE 0 /* No relocation. */ +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* + * 64-bit relocations + */ +#define R_PPC64_ADDR64 38 +#define R_PPC64_ADDR16_HIGHER 39 +#define R_PPC64_ADDR16_HIGHERA 40 +#define R_PPC64_ADDR16_HIGHEST 41 +#define R_PPC64_ADDR16_HIGHESTA 42 +#define R_PPC64_UADDR64 43 +#define R_PPC64_REL64 44 +#define R_PPC64_PLT64 45 +#define R_PPC64_PLTREL64 46 +#define R_PPC64_TOC16 47 +#define R_PPC64_TOC16_LO 48 +#define R_PPC64_TOC16_HI 49 +#define R_PPC64_TOC16_HA 50 +#define R_PPC64_TOC 51 +#define R_PPC64_DTPMOD64 68 +#define R_PPC64_TPREL64 73 +#define R_PPC64_DTPREL64 78 + +/* + * TLS relocations + */ +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 + +/* + * The remaining relocs are from the Embedded ELF ABI, and are not in the + * SVR4 ELF ABI. + */ + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 + +#define R_X86_64_NONE 0 /* No relocation. */ +#define R_X86_64_64 1 /* Add 64 bit symbol value. */ +#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ +#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ +#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ +#define R_X86_64_COPY 5 /* Copy data from shared object. */ +#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ +#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ +#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ +#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ +#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ +#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ +#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ +#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ +#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ +#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ +#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ +#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ +#define R_X86_64_IRELATIVE 37 + +#endif /* !_SYS_ELF_COMMON_H_ */ diff --git a/ta/remoteproc/include/elf_parser.h b/ta/remoteproc/include/elf_parser.h new file mode 100644 index 000000000..5950db971 --- /dev/null +++ b/ta/remoteproc/include/elf_parser.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef ELF_PARSER +#define ELF_PARSER + +#include +#include +#include + +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote processor. It may also include configuration entries. + * If needed, the remote processor firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * This structure shall be consistent with the Linux kernel structure + * definition from include/linux/remoteproc.h. + */ +struct resource_table { + uint32_t ver; + uint32_t num; + uint32_t reserved[2]; + uint32_t offset[]; +} __packed; + +struct fw_elf32 { + uintptr_t e_entry; + uintptr_t e_phoff; + uintptr_t e_shoff; + uint32_t e_phnum; + uint32_t e_shnum; + uint32_t e_phentsize; + uint32_t e_shentsize; + + Elf32_Phdr *phdr; + Elf32_Shdr *shdr; +}; + +TEE_Result e32_parse_ehdr(uint8_t *fw, size_t size); +TEE_Result e32_parser_load_elf_image(uint8_t *fw, size_t fw_size, + TEE_Result (*load_seg)(uint8_t *src, + uint32_t size, + uint32_t da, + uint32_t mem_size, + void *priv), + void *priv_data); +int e32_parser_find_rsc_table(uint8_t *fw, size_t fw_size, Elf32_Addr *rsc_addr, + Elf32_Word *rsc_size); + +#endif /*ELF_PARSER*/ diff --git a/ta/remoteproc/include/ta_remoteproc.h b/ta/remoteproc/include/ta_remoteproc.h new file mode 100644 index 000000000..a51ba5f70 --- /dev/null +++ b/ta/remoteproc/include/ta_remoteproc.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef TA_RPROC_FW_H +#define TA_RPROC_FW_H + +/* + * This UUID is generated with uuidgen + * the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html + */ +#define TA_REMOTEPROC_UUID \ + { 0x80a4c275, 0x0a47, 0x4905, \ + { 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08} } + +/* The function IDs implemented in this TA */ + +/* + * Authentication of the firmware and load in the remote processor memory. + * + * [in] params[0].value.a: unique 32bit identifier of the firmware + * [in] params[1].memref: buffer containing the image of the firmware + */ +#define TA_RPROC_FW_CMD_LOAD_FW 1 + +/* + * Start the remote processor. + * + * [in] params[0].value.a: unique 32bit identifier of the firmware + */ +#define TA_RPROC_FW_CMD_START_FW 2 + +/* + * Stop the remote processor. + * + * [in] params[0].value.a: unique 32bit identifier of the firmware + */ +#define TA_RPROC_FW_CMD_STOP_FW 3 + +/* + * Return the physical address of the resource table, or 0 if not found + * No check is done to verify that the address returned is accessible by the + * non secure world. If the resource table is loaded in a protected memory, + * then accesses from non-secure world will likely fail. + * + * [in] params[0].value.a: unique 32bit identifier of the firmware + * [out] params[1].value.a: 32bit LSB resource table memory address + * [out] params[1].value.b: 32bit MSB resource table memory address + * [out] params[2].value.a: 32bit LSB resource table memory size + * [out] params[2].value.b: 32bit MSB resource table memory size + */ +#define TA_RPROC_FW_CMD_GET_RSC_TABLE 4 + +/* + * Get remote processor firmware core dump. If found, return either + * TEE_SUCCESS on successful completion or TEE_ERROR_SHORT_BUFFER if output + * buffer is too short to store the core dump. + * + * [in] params[0].value.a: unique 32bit identifier of the firmware + * [out] params[1].memref: Core dump, if found + */ +#define TA_RPROC_FW_CMD_GET_COREDUMP 5 + +#endif /*TA_RPROC_FW_H*/ diff --git a/ta/remoteproc/include/user_ta_header_defines.h b/ta/remoteproc/include/user_ta_header_defines.h new file mode 100644 index 000000000..c2ef1b21b --- /dev/null +++ b/ta/remoteproc/include/user_ta_header_defines.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved + */ + +#ifndef USER_TA_HEADER_DEFINES_H +#define USER_TA_HEADER_DEFINES_H + +#include + +#define TA_UUID TA_REMOTEPROC_UUID + +#define TA_FLAGS (TA_FLAG_DEVICE_ENUM | \ + TA_FLAG_SINGLE_INSTANCE | \ + TA_FLAG_INSTANCE_KEEP_ALIVE) + +/* Provisioned stack size */ +#define TA_STACK_SIZE (4 * 1024) + +/* Provisioned heap size for TEE_Malloc() and friends */ +#define TA_DATA_SIZE (4 * 1024) + +/* The gpd.ta.version property */ +#define TA_VERSION "1.0" + +/* The gpd.ta.description property */ +#define TA_DESCRIPTION "remote processor firmware management" + +#endif /* USER_TA_HEADER_DEFINES_H */ diff --git a/ta/remoteproc/remoteproc_core.c b/ta/remoteproc/remoteproc_core.c new file mode 100644 index 000000000..454edf2fb --- /dev/null +++ b/ta/remoteproc/remoteproc_core.c @@ -0,0 +1,781 @@ + // SPDX-License-Identifier: BSD-2-Clause + /* + * Copyright (C) 2020-2021, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Firmware state */ +enum remoteproc_state { + REMOTEPROC_OFF, + REMOTEPROC_LOADED, + REMOTEPROC_STARTED, +}; + +#define RPROC_HDR_MAGIC 0x3543A468 /*random value */ +#define HEADER_VERSION 1 + +/* Supported signature algorithm */ +enum remoteproc_sign_type { + RPROC_RSASSA_PKCS1_v1_5_SHA256 = 1, + RPROC_ECDSA_SHA256 = 2, +}; + +/* + * struct remoteproc_segment - program header with hash structure + * @phdr: program header + * @hash: hash associated to the program segment. + */ +struct remoteproc_segment { + Elf32_Phdr phdr; + unsigned char hash[TEE_SHA256_HASH_SIZE]; +}; + +/* + * struct remoteproc_fw_hdr - firmware header + * @magic: Magic number, must be equal to RPROC_HDR_MAGIC + * @version: Version of the header (must be 1) + * @hdr_length: Total header byte length including chunks + * @sign_length: Signature chunk byte length + * @sign_offset: Signature chunk byte offset from header start + * @sign_type: Signature type + * @phhdr_length: Program header with hashes byte size, possibly 0 + * @phhdr_offset: Program header with hashes byte offset, 0 if not used + * @phhdr_type: Program header with hash type or 0 if not used + * @key_length: Authentication key info byte length, possibly 0 + * @key_offset: Authentication key info byte offset, 0 if not used + * @img_length: Firmware image chunk byte length + * @img_offset: Firmware image chunk byte offset + * @img_type: Firmware image type + */ +struct remoteproc_fw_hdr { + uint32_t magic; + uint32_t version; + uint32_t hdr_length; + uint32_t sign_length; + uint32_t sign_offset; + uint32_t sign_type; + uint32_t phhdr_length; + uint32_t phhdr_offset; + uint32_t phhdr_type; + uint32_t key_length; + uint32_t key_offset; + uint32_t img_length; + uint32_t img_offset; + uint32_t img_type; +}; + +/* + * struct remoteproc_sig_algo - signature algorithm information + * @sign_type: Header signature type + * @id: Signature algorigthm identifier TEE_ALG_* + * @hash_len: Signature hash length + */ +struct remoteproc_sig_algo { + enum remoteproc_sign_type sign_type; + uint32_t id; + size_t hash_len; +}; + +/* + * struct remoteproc_context - firmware context + * @fw_id: Unique Id of the firmware + * @hdr: Location of a secure copy of the firmware header + * @fw_img: Firmware image + * @fw_img_size: Byte size of the firmware image + * @rsc_pa: Physical address of the firmware resource table + * @rsc_size: Byte size of the firmware resource table + * @state: Remote-processor state + * @hw_fmt: Image format capabilities of the remoteproc PTA + * @hw_img_prot: Image protection capabilities of the remoteproc PTA + * @link: Linked list element + */ +struct remoteproc_context { + uint32_t fw_id; + struct remoteproc_fw_hdr *hdr; + uint8_t *fw_img; + size_t fw_img_size; + paddr_t rsc_pa; + uint32_t rsc_size; + enum remoteproc_state state; + uint32_t hw_fmt; + uint32_t hw_img_prot; + TAILQ_ENTRY(remoteproc_context) link; +}; + +TAILQ_HEAD(remoteproc_firmware_head, remoteproc_context); + +static struct remoteproc_firmware_head firmware_head = + TAILQ_HEAD_INITIALIZER(firmware_head); + +static const struct remoteproc_sig_algo rproc_ta_sign_algo[] = { + { + .sign_type = RPROC_RSASSA_PKCS1_v1_5_SHA256, + .id = TEE_ALG_RSASSA_PKCS1_V1_5_SHA256, + .hash_len = TEE_SHA256_HASH_SIZE, + }, + { + .sign_type = RPROC_ECDSA_SHA256, + .id = TEE_ALG_ECDSA_P256, + .hash_len = TEE_SHA256_HASH_SIZE, + }, +}; + +static size_t session_refcount; +static TEE_TASessionHandle pta_session; + +static void remoteproc_header_dump(struct remoteproc_fw_hdr __maybe_unused *hdr) +{ + DMSG("magic :\t%#"PRIx32, hdr->magic); + DMSG("version :\t%#"PRIx32, hdr->version); + DMSG("hdr_length :\t%#"PRIx32, hdr->hdr_length); + DMSG("sign_length :\t%#"PRIx32, hdr->sign_length); + DMSG("sign_offset :\t%#"PRIx32, hdr->sign_offset); + DMSG("sign_type :\t%#"PRIx32, hdr->sign_type); + DMSG("phhdr_length :\t%#"PRIx32, hdr->phhdr_length); + DMSG("phhdr_offset :\t%#"PRIx32, hdr->phhdr_offset); + DMSG("phhdr_type :\t%#"PRIx32, hdr->phhdr_type); + DMSG("key_length :\t%#"PRIx32, hdr->key_length); + DMSG("key_offset :\t%#"PRIx32, hdr->key_offset); + DMSG("img_length :\t%#"PRIx32, hdr->img_length); + DMSG("img_offset :\t%#"PRIx32, hdr->img_offset); + DMSG("img_type :\t%#"PRIx32, hdr->img_type); +} + +static struct remoteproc_context *remoteproc_find_firmware(uint32_t fw_id) +{ + struct remoteproc_context *ctx = NULL; + + TAILQ_FOREACH(ctx, &firmware_head, link) { + if (ctx->fw_id == fw_id) + return ctx; + } + + return NULL; +} + +static struct remoteproc_context *remoteproc_add_firmware(uint32_t fw_id) +{ + struct remoteproc_context *ctx = NULL; + + ctx = TEE_Malloc(sizeof(*ctx), TEE_MALLOC_FILL_ZERO); + if (!ctx) + return NULL; + + ctx->fw_id = fw_id; + + TAILQ_INSERT_TAIL(&firmware_head, ctx, link); + + return ctx; +} + +static const struct remoteproc_sig_algo *remoteproc_get_algo(uint32_t sign_type) +{ + unsigned int i = 0; + + for (i = 0; i < ARRAY_SIZE(rproc_ta_sign_algo); i++) + if (sign_type == rproc_ta_sign_algo[i].sign_type) + return &rproc_ta_sign_algo[i]; + + return NULL; +} + +static TEE_Result remoteproc_pta_verify(struct remoteproc_context *ctx, + const struct remoteproc_sig_algo *algo, + char *hash, uint32_t hash_len) +{ + TEE_Result res = TEE_ERROR_GENERIC; + struct remoteproc_fw_hdr *hdr = ctx->hdr; + struct rproc_pta_key_info *keyinfo = NULL; + uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT); + TEE_Param params[TEE_NUM_PARAMS] = { }; + + keyinfo = TEE_Malloc(sizeof(*keyinfo) + hdr->key_length, 0); + if (!keyinfo) + return TEE_ERROR_OUT_OF_MEMORY; + + keyinfo->algo = algo->id; + keyinfo->info_size = hdr->key_length; + memcpy(keyinfo->info, (uint8_t *)hdr + hdr->key_offset, + hdr->key_length); + + params[0].value.a = ctx->fw_id; + params[1].memref.buffer = keyinfo; + params[1].memref.size = RPROC_PTA_GET_KEYINFO_SIZE(keyinfo); + params[2].memref.buffer = hash; + params[2].memref.size = hash_len; + params[3].memref.buffer = (uint8_t *)hdr + hdr->sign_offset; + params[3].memref.size = hdr->sign_length; + + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_VERIFY_DIGEST, + param_types, params, NULL); + if (res != TEE_SUCCESS) + EMSG("Failed to verify signature, res = %#"PRIx32, res); + + TEE_Free(keyinfo); + + return res; +} + +static TEE_Result remoteproc_save_fw_header(struct remoteproc_context *ctx, + void *fw_orig, + uint32_t fw_orig_size) +{ + struct remoteproc_fw_hdr *hdr = fw_orig; + + remoteproc_header_dump(hdr); + + if (fw_orig_size <= sizeof(*hdr) || fw_orig_size <= hdr->hdr_length) + return TEE_ERROR_CORRUPT_OBJECT; + + ctx->hdr = TEE_Malloc(hdr->hdr_length, TEE_MALLOC_FILL_ZERO); + if (!ctx->hdr) + return TEE_ERROR_OUT_OF_MEMORY; + + memcpy(ctx->hdr, fw_orig, hdr->hdr_length); + + return TEE_SUCCESS; +} + +static TEE_Result remoteproc_verify_signature(struct remoteproc_context *ctx) +{ + TEE_OperationHandle op = TEE_HANDLE_NULL; + struct remoteproc_fw_hdr *hdr = ctx->hdr; + const struct remoteproc_sig_algo *algo = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + char *hash = NULL; + uint32_t hash_len = 0; + + algo = remoteproc_get_algo(hdr->sign_type); + if (!algo) { + EMSG("Unsupported signature type %d", hdr->sign_type); + return TEE_ERROR_NOT_SUPPORTED; + } + + /* Compute the header hash */ + hash_len = algo->hash_len; + hash = TEE_Malloc(hash_len, 0); + if (!hash) + return TEE_ERROR_OUT_OF_MEMORY; + + res = TEE_AllocateOperation(&op, TEE_ALG_SHA256, TEE_MODE_DIGEST, 0); + if (res != TEE_SUCCESS) + goto free_hash; + + res = TEE_DigestDoFinal(op, hdr, hdr->sign_offset, hash, &hash_len); + if (res != TEE_SUCCESS) + goto out; + + /* + * TODO: + * Provide alternative to verify the signature in the TA. This could + * be done for instance by getting the key object from secure storage. + */ + + /* By default ask the pta to verify the signature. */ + res = remoteproc_pta_verify(ctx, algo, hash, hash_len); + +out: + TEE_FreeOperation(op); +free_hash: + TEE_Free(hash); + + return res; +} + +static TEE_Result remoteproc_verify_header(struct remoteproc_context *ctx) +{ + struct remoteproc_fw_hdr *hdr = ctx->hdr; + uint32_t hdr_size = 0; + uint32_t chunk_size = 0; + uint32_t alignment = 0; + + if (hdr->magic != RPROC_HDR_MAGIC) + return TEE_ERROR_CORRUPT_OBJECT; + + if (hdr->version != HEADER_VERSION) + return TEE_ERROR_CORRUPT_OBJECT; + + /* + * The offsets are aligned to 64 bits format. The hdr_length takes into + * account these alignments while the length of each chunks are the + * effective length,excluding the alignment padding bytes. + */ + alignment = hdr->sign_length % sizeof(uint64_t) + + hdr->phhdr_length % sizeof(uint64_t) + + hdr->key_length % sizeof(uint64_t); + + if (ADD_OVERFLOW(sizeof(*hdr), hdr->sign_length, &hdr_size) || + ADD_OVERFLOW(hdr_size, hdr->phhdr_length, &hdr_size) || + ADD_OVERFLOW(hdr_size, hdr->key_length, &hdr_size) || + ADD_OVERFLOW(hdr_size, alignment, &hdr_size) || + hdr->hdr_length != hdr_size) + return TEE_ERROR_CORRUPT_OBJECT; + + if (ADD_OVERFLOW(hdr->sign_offset, hdr->sign_length, &chunk_size) || + chunk_size > hdr_size || + ADD_OVERFLOW(hdr->key_offset, hdr->key_length, &chunk_size) || + chunk_size > hdr_size || + ADD_OVERFLOW(hdr->phhdr_offset, hdr->phhdr_length, &chunk_size) || + chunk_size > hdr_size) + return TEE_ERROR_CORRUPT_OBJECT; + + if (hdr->phhdr_length % sizeof(struct remoteproc_segment)) + return TEE_ERROR_CORRUPT_OBJECT; + + return remoteproc_verify_signature(ctx); +} + +static TEE_Result get_rproc_pta_capabilities(struct remoteproc_context *ctx) +{ + uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_NONE); + TEE_Param params[TEE_NUM_PARAMS] = { }; + TEE_Result res = TEE_ERROR_GENERIC; + + params[0].value.a = ctx->fw_id; + + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_HW_CAPABILITIES, + param_types, params, NULL); + if (res) + return res; + + ctx->hw_fmt = params[1].value.a; + ctx->hw_img_prot = params[2].value.a; + + return TEE_SUCCESS; +} + +static TEE_Result remoteproc_verify_firmware(struct remoteproc_context *ctx, + uint8_t *fw_orig, + uint32_t fw_orig_size) +{ + struct remoteproc_fw_hdr *hdr = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + + res = get_rproc_pta_capabilities(ctx); + if (res) + return res; + + /* Secure the firmware image depending on strategy */ + if (!(ctx->hw_img_prot & PTA_REMOTEPROC_FW_WITH_HASH_TABLE) || + ctx->hw_fmt != PTA_REMOTEPROC_ELF_FMT) { + /* + * Only hash table for ELF format support implemented + * in a first step. + */ + return TEE_ERROR_NOT_IMPLEMENTED; + } + + res = remoteproc_save_fw_header(ctx, fw_orig, fw_orig_size); + if (res) + return res; + + res = remoteproc_verify_header(ctx); + if (res) + goto free_hdr; + + /* Store location of the loadable binary in non-secure memory */ + hdr = ctx->hdr; + ctx->fw_img_size = hdr->img_length; + ctx->fw_img = fw_orig + hdr->img_offset; + + DMSG("Firmware image addr: %p size: %zu", ctx->fw_img, + ctx->fw_img_size); + +free_hdr: + TEE_Free(ctx->hdr); + + return res; +} + +static paddr_t remoteproc_da_to_pa(uint32_t da, uint32_t size, void *priv) +{ + struct remoteproc_context *ctx = priv; + uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT); + TEE_Param params[TEE_NUM_PARAMS] = { }; + TEE_Result res = TEE_ERROR_GENERIC; + + params[0].value.a = ctx->fw_id; + params[1].value.a = da; + params[2].value.a = size; + + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_FIRMWARE_DA_TO_PA, + param_types, params, NULL); + if (res != TEE_SUCCESS) { + EMSG("Failed to translate device address %#"PRIx32, da); + return 0; + } + + return (paddr_t)reg_pair_to_64(params[3].value.b, params[3].value.a); +} + +static TEE_Result remoteproc_parse_rsc_table(struct remoteproc_context *ctx) +{ + uint32_t da = 0; + TEE_Result res = TEE_ERROR_GENERIC; + + res = e32_parser_find_rsc_table(ctx->fw_img, ctx->fw_img_size, + &da, &ctx->rsc_size); + if (res == TEE_ERROR_NO_DATA) { + /* Firmware without resource table */ + ctx->rsc_size = 0; + ctx->rsc_pa = 0; + return TEE_SUCCESS; + } + if (res) + return res; + + if (da) { + DMSG("Resource table device address %#"PRIx32" size %zu", + da, ctx->rsc_size); + + ctx->rsc_pa = remoteproc_da_to_pa(da, ctx->rsc_size, ctx); + if (!ctx->rsc_pa) + return TEE_ERROR_ACCESS_DENIED; + } + + return TEE_SUCCESS; +} + +static TEE_Result get_segment_hash(struct remoteproc_context *ctx, uint8_t *src, + uint32_t size, uint32_t da, + uint32_t mem_size, unsigned char **hash) +{ + struct remoteproc_fw_hdr *hdr = ctx->hdr; + struct remoteproc_segment *peh = NULL; + unsigned int i = 0; + unsigned int nb_entry = hdr->phhdr_length / sizeof(*peh); + + peh = (void *)((uint8_t *)hdr + hdr->phhdr_offset); + + for (i = 0; i < nb_entry; peh++, i++) { + if (peh->phdr.p_paddr != da) + continue; + + /* + * Segment is read from a non secure memory. Crosscheck it using + * the hash table to verify that the segment has not been + * corrupted. + */ + if (peh->phdr.p_type != PT_LOAD) + return TEE_ERROR_CORRUPT_OBJECT; + + if (peh->phdr.p_filesz != size || peh->phdr.p_memsz != mem_size) + return TEE_ERROR_CORRUPT_OBJECT; + + if ((Elf32_Off)(src - ctx->fw_img) != peh->phdr.p_offset) + return TEE_ERROR_CORRUPT_OBJECT; + + *hash = peh->hash; + + return TEE_SUCCESS; + } + + return TEE_ERROR_NO_DATA; +} + +static TEE_Result remoteproc_load_segment(uint8_t *src, uint32_t size, + uint32_t da, uint32_t mem_size, + void *priv) +{ + struct remoteproc_context *ctx = priv; + uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT); + TEE_Param params[TEE_NUM_PARAMS] = { }; + TEE_Result res = TEE_ERROR_GENERIC; + unsigned char *hash = NULL; + + /* + * Invoke platform remoteproc PTA to load the segment in remote + * processor memory which is not mapped in the TA space. + */ + + DMSG("Load segment %#"PRIx32" size %"PRIu32" (%"PRIu32")", da, size, + mem_size); + + res = get_segment_hash(ctx, src, size, da, mem_size, &hash); + if (res) + return res; + + params[0].value.a = ctx->fw_id; + params[1].memref.buffer = src; + params[1].memref.size = size; + params[2].value.a = da; + params[3].memref.buffer = hash; + params[3].memref.size = TEE_SHA256_HASH_SIZE; + + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_LOAD_SEGMENT_SHA256, + param_types, params, NULL); + if (res != TEE_SUCCESS) { + EMSG("Fails to load segment, res = 0x%x", res); + return res; + } + + /* Fill the rest of the memory with 0 */ + if (size < mem_size) { + param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_INPUT); + params[1].value.a = da + size; + params[2].value.a = mem_size - size; + params[3].value.a = 0; + + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_SET_MEMORY, + param_types, params, NULL); + if (res != TEE_SUCCESS) + EMSG("Fails to clear segment, res = 0x%x", res); + } + + return res; +} + +static TEE_Result remoteproc_load_elf(struct remoteproc_context *ctx) +{ + TEE_Result res = TEE_ERROR_GENERIC; + + res = e32_parse_ehdr(ctx->fw_img, ctx->fw_img_size); + if (res) { + EMSG("Failed to parse firmware, res = %#"PRIx32, res); + return res; + } + + return e32_parser_load_elf_image(ctx->fw_img, ctx->fw_img_size, + remoteproc_load_segment, ctx); +} + +static TEE_Result remoteproc_load_fw(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + struct remoteproc_context *ctx = NULL; + uint32_t fw_id = params[0].value.a; + TEE_Result res = TEE_ERROR_GENERIC; + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ctx = remoteproc_find_firmware(fw_id); + if (!ctx) + ctx = remoteproc_add_firmware(fw_id); + if (!ctx) + return TEE_ERROR_OUT_OF_MEMORY; + + if (ctx->state != REMOTEPROC_OFF) + return TEE_ERROR_BAD_STATE; + + if (!params[1].memref.buffer || !params[1].memref.size) + return TEE_ERROR_BAD_PARAMETERS; + + DMSG("Got base addr: %p size %zu", params[1].memref.buffer, + params[1].memref.size); + + res = remoteproc_verify_firmware(ctx, params[1].memref.buffer, + params[1].memref.size); + if (res) { + EMSG("Can't Authenticate the firmware, res = %#"PRIx32, res); + goto out; + } + + res = remoteproc_load_elf(ctx); + if (res) + goto out; + + /* Take opportunity to get the resource table address */ + res = remoteproc_parse_rsc_table(ctx); + if (res == TEE_SUCCESS) + ctx->state = REMOTEPROC_LOADED; + +out: + /* Clear reference to firmware image from shared memory */ + ctx->fw_img = NULL; + ctx->fw_img_size = 0; + + return res; +} + +static TEE_Result remoteproc_start_fw(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + struct remoteproc_context *ctx = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ctx = remoteproc_find_firmware(params[0].value.a); + if (!ctx) + return TEE_ERROR_BAD_PARAMETERS; + + switch (ctx->state) { + case REMOTEPROC_OFF: + res = TEE_ERROR_BAD_STATE; + break; + case REMOTEPROC_STARTED: + res = TEE_SUCCESS; + break; + case REMOTEPROC_LOADED: + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_FIRMWARE_START, + pt, params, NULL); + if (res == TEE_SUCCESS) + ctx->state = REMOTEPROC_STARTED; + break; + default: + res = TEE_ERROR_BAD_STATE; + } + + return res; +} + +static TEE_Result remoteproc_stop_fw(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + struct remoteproc_context *ctx = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ctx = remoteproc_find_firmware(params[0].value.a); + if (!ctx) + return TEE_ERROR_BAD_PARAMETERS; + + switch (ctx->state) { + case REMOTEPROC_LOADED: + res = TEE_ERROR_BAD_STATE; + break; + case REMOTEPROC_OFF: + res = TEE_SUCCESS; + break; + case REMOTEPROC_STARTED: + res = TEE_InvokeTACommand(pta_session, TEE_TIMEOUT_INFINITE, + PTA_REMOTEPROC_FIRMWARE_STOP, + pt, params, NULL); + if (res == TEE_SUCCESS) + ctx->state = REMOTEPROC_OFF; + break; + default: + res = TEE_ERROR_BAD_STATE; + } + + return res; +} + +static TEE_Result remoteproc_get_rsc_table(uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_NONE); + struct remoteproc_context *ctx = NULL; + + if (pt != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + ctx = remoteproc_find_firmware(params[0].value.a); + if (!ctx) + return TEE_ERROR_BAD_PARAMETERS; + + if (ctx->state == REMOTEPROC_OFF) + return TEE_ERROR_BAD_STATE; + + reg_pair_from_64((uint64_t)ctx->rsc_pa, + ¶ms[1].value.b, ¶ms[1].value.a); + reg_pair_from_64((uint64_t)ctx->rsc_size, + ¶ms[2].value.b, ¶ms[2].value.a); + + return TEE_SUCCESS; +} + +TEE_Result TA_CreateEntryPoint(void) +{ + return TEE_SUCCESS; +} + +void TA_DestroyEntryPoint(void) +{ +} + +TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused, + TEE_Param params[TEE_NUM_PARAMS] __unused, + void **sess __unused) +{ + static const TEE_UUID uuid = PTA_REMOTEPROC_UUID; + TEE_Result res = TEE_ERROR_GENERIC; + + if (!session_refcount) { + res = TEE_OpenTASession(&uuid, TEE_TIMEOUT_INFINITE, 0, NULL, + &pta_session, NULL); + if (res) + return res; + } + + session_refcount++; + + return TEE_SUCCESS; +} + +void TA_CloseSessionEntryPoint(void *sess __unused) +{ + session_refcount--; + + if (!session_refcount) + TEE_CloseTASession(pta_session); +} + +TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd_id, + uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + switch (cmd_id) { + case TA_RPROC_FW_CMD_LOAD_FW: + return remoteproc_load_fw(pt, params); + case TA_RPROC_FW_CMD_START_FW: + return remoteproc_start_fw(pt, params); + case TA_RPROC_FW_CMD_STOP_FW: + return remoteproc_stop_fw(pt, params); + case TA_RPROC_FW_CMD_GET_RSC_TABLE: + return remoteproc_get_rsc_table(pt, params); + case TA_RPROC_FW_CMD_GET_COREDUMP: + return TEE_ERROR_NOT_IMPLEMENTED; + default: + return TEE_ERROR_BAD_PARAMETERS; + } +} diff --git a/ta/remoteproc/sub.mk b/ta/remoteproc/sub.mk new file mode 100644 index 000000000..caca5901a --- /dev/null +++ b/ta/remoteproc/sub.mk @@ -0,0 +1,3 @@ +global-incdirs-y += include +srcs-y += remoteproc_core.c +srcs-y += elf_parser.c diff --git a/ta/remoteproc/user_ta.mk b/ta/remoteproc/user_ta.mk new file mode 100644 index 000000000..6db23f705 --- /dev/null +++ b/ta/remoteproc/user_ta.mk @@ -0,0 +1 @@ +user-ta-uuid := 80a4c275-0a47-4905-8285-1486a9771a08 \ No newline at end of file -- 2.17.1