aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/allwinner/axp/axp803.c3
-rw-r--r--drivers/allwinner/axp/axp805.c2
-rw-r--r--drivers/allwinner/axp/common.c15
-rw-r--r--drivers/amlogic/console/aarch64/meson_console.S2
-rw-r--r--drivers/amlogic/crypto/sha_dma.c1
-rw-r--r--drivers/arm/css/mhu/css_mhu_doorbell.c3
-rw-r--r--drivers/arm/css/scmi/scmi_common.c17
-rw-r--r--drivers/arm/css/scmi/scmi_private.h2
-rw-r--r--drivers/arm/css/scmi/vendor/scmi_sq.c2
-rw-r--r--drivers/arm/css/scp/css_pm_scmi.c35
-rw-r--r--drivers/arm/css/scp/css_sds.c16
-rw-r--r--drivers/arm/css/sds/sds.c85
-rw-r--r--drivers/arm/dcc/dcc_console.c21
-rw-r--r--drivers/arm/ethosn/ethosn_big_fw.c57
-rw-r--r--drivers/arm/ethosn/ethosn_big_fw.h36
-rw-r--r--drivers/arm/ethosn/ethosn_npu.mk49
-rw-r--r--drivers/arm/ethosn/ethosn_smc.c543
-rw-r--r--drivers/arm/fvp/fvp_pwrc.c44
-rw-r--r--drivers/arm/gic/v2/gicv2_main.c13
-rw-r--r--drivers/arm/gic/v3/gic-x00.c72
-rw-r--r--drivers/arm/gic/v3/gic600_multichip.c191
-rw-r--r--drivers/arm/gic/v3/gic600_multichip_private.h44
-rw-r--r--drivers/arm/gic/v3/gic600ae_fmu.c384
-rw-r--r--drivers/arm/gic/v3/gic600ae_fmu_helpers.c304
-rw-r--r--drivers/arm/gic/v3/gicv3.mk22
-rw-r--r--drivers/arm/gic/v3/gicv3_helpers.c157
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c286
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h5
-rw-r--r--drivers/arm/mhu/mhu_v2_x.c379
-rw-r--r--drivers/arm/mhu/mhu_v2_x.h210
-rw-r--r--drivers/arm/mhu/mhu_v3_x.c475
-rw-r--r--drivers/arm/mhu/mhu_v3_x.h226
-rw-r--r--drivers/arm/mhu/mhu_v3_x_private.h222
-rw-r--r--drivers/arm/mhu/mhu_wrapper_v2_x.c317
-rw-r--r--drivers/arm/mhu/mhu_wrapper_v3_x.c462
-rw-r--r--drivers/arm/pl011/aarch32/pl011_console.S2
-rw-r--r--drivers/arm/pl011/aarch64/pl011_console.S2
-rw-r--r--drivers/arm/rss/rss_comms.c180
-rw-r--r--drivers/arm/rss/rss_comms.mk34
-rw-r--r--drivers/arm/rss/rss_comms_protocol.c75
-rw-r--r--drivers/arm/rss/rss_comms_protocol.h67
-rw-r--r--drivers/arm/rss/rss_comms_protocol_common.h35
-rw-r--r--drivers/arm/rss/rss_comms_protocol_embed.c86
-rw-r--r--drivers/arm/rss/rss_comms_protocol_embed.h47
-rw-r--r--drivers/arm/rss/rss_comms_protocol_pointer_access.c63
-rw-r--r--drivers/arm/rss/rss_comms_protocol_pointer_access.h42
-rw-r--r--drivers/arm/sbsa/sbsa.c8
-rw-r--r--drivers/arm/smmu/smmu_v3.c119
-rw-r--r--drivers/arm/tzc/tzc400.c34
-rw-r--r--drivers/arm/tzc/tzc_common_private.h23
-rw-r--r--drivers/auth/auth_mod.c273
-rw-r--r--drivers/auth/cca/cot.c679
-rw-r--r--drivers/auth/crypto_mod.c41
-rw-r--r--drivers/auth/cryptocell/712/cryptocell_crypto.c306
-rw-r--r--drivers/auth/cryptocell/712/cryptocell_plat_helpers.c113
-rw-r--r--drivers/auth/cryptocell/713/cryptocell_crypto.c273
-rw-r--r--drivers/auth/cryptocell/713/cryptocell_plat_helpers.c109
-rw-r--r--drivers/auth/cryptocell/cryptocell_crypto.mk40
-rw-r--r--drivers/auth/dualroot/cot.c9
-rw-r--r--drivers/auth/mbedtls/mbedtls_common.c5
-rw-r--r--drivers/auth/mbedtls/mbedtls_common.mk106
-rw-r--r--drivers/auth/mbedtls/mbedtls_crypto.c107
-rw-r--r--drivers/auth/mbedtls/mbedtls_crypto.mk13
-rw-r--r--drivers/auth/mbedtls/mbedtls_psa_crypto.c696
-rw-r--r--drivers/auth/mbedtls/mbedtls_x509_parser.c298
-rw-r--r--drivers/auth/tbbr/tbbr_cot_bl1.c8
-rw-r--r--drivers/auth/tbbr/tbbr_cot_bl1_r64.c178
-rw-r--r--drivers/auth/tbbr/tbbr_cot_bl2.c8
-rw-r--r--drivers/auth/tbbr/tbbr_cot_common.c7
-rw-r--r--drivers/brcm/emmc/emmc_chal_sd.c4
-rw-r--r--drivers/brcm/emmc/emmc_csl_sdcard.c17
-rw-r--r--drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c40
-rw-r--r--drivers/brcm/i2c/i2c.c4
-rw-r--r--drivers/brcm/sotp.c4
-rw-r--r--drivers/cadence/combo_phy/cdns_combo_phy.c83
-rw-r--r--drivers/cadence/emmc/cdns_sdmmc.c824
-rw-r--r--drivers/cadence/nand/cdns_nand.c458
-rw-r--r--drivers/cadence/uart/aarch64/cdns_console.S11
-rw-r--r--drivers/clk/clk.c65
-rw-r--r--drivers/console/aarch32/skeleton_console.S2
-rw-r--r--drivers/console/aarch64/skeleton_console.S2
-rw-r--r--drivers/console/multi_console.c17
-rw-r--r--drivers/fwu/fwu.c295
-rw-r--r--drivers/fwu/fwu.mk11
-rw-r--r--drivers/imx/usdhc/imx_usdhc.c6
-rw-r--r--drivers/io/io_block.c8
-rw-r--r--drivers/io/io_dummy.c155
-rw-r--r--drivers/io/io_mtd.c74
-rw-r--r--drivers/marvell/amb_adec.c13
-rw-r--r--drivers/marvell/ccu.c9
-rw-r--r--drivers/marvell/comphy/comphy-cp110.h2
-rw-r--r--drivers/marvell/comphy/phy-comphy-3700.c307
-rw-r--r--drivers/marvell/comphy/phy-comphy-3700.h176
-rw-r--r--drivers/marvell/comphy/phy-comphy-common.h8
-rw-r--r--drivers/marvell/comphy/phy-comphy-cp110.c34
-rw-r--r--drivers/marvell/gwin.c11
-rw-r--r--drivers/marvell/io_win.c9
-rw-r--r--drivers/marvell/iob.c9
-rw-r--r--drivers/marvell/mc_trustzone/mc_trustzone.c7
-rw-r--r--drivers/marvell/mg_conf_cm3/mg_conf_cm3.c2
-rw-r--r--drivers/marvell/uart/a3700_console.S58
-rw-r--r--drivers/measured_boot/event_log.c410
-rw-r--r--drivers/measured_boot/event_log/event_log.c315
-rw-r--r--drivers/measured_boot/event_log/event_log.mk41
-rw-r--r--drivers/measured_boot/event_log/event_print.c (renamed from drivers/measured_boot/event_print.c)2
-rw-r--r--drivers/measured_boot/measured_boot.c39
-rw-r--r--drivers/measured_boot/measured_boot.mk52
-rw-r--r--drivers/measured_boot/rss/dice_prot_env.c193
-rw-r--r--drivers/measured_boot/rss/dice_prot_env.mk29
-rw-r--r--drivers/measured_boot/rss/qcbor.mk23
-rw-r--r--drivers/measured_boot/rss/rss_measured_boot.c159
-rw-r--r--drivers/measured_boot/rss/rss_measured_boot.mk32
-rw-r--r--drivers/mmc/mmc.c164
-rw-r--r--drivers/mtd/nand/core.c68
-rw-r--r--drivers/mtd/nand/raw_nand.c45
-rw-r--r--drivers/mtd/nand/spi_nand.c21
-rw-r--r--drivers/mtd/nor/spi_nor.c26
-rw-r--r--drivers/mtd/spi-mem/spi_mem.c13
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/csf_hdr.h155
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk4
-rw-r--r--drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c2
-rw-r--r--drivers/nxp/auth/tbbr/tbbr_cot.c3
-rw-r--r--drivers/nxp/console/16550_console.S2
-rw-r--r--drivers/nxp/console/console.mk2
-rw-r--r--drivers/nxp/console/plat_console.h38
-rw-r--r--drivers/nxp/crypto/caam/caam.mk7
-rw-r--r--drivers/nxp/crypto/caam/include/caam.h53
-rw-r--r--drivers/nxp/crypto/caam/include/caam_io.h56
-rw-r--r--drivers/nxp/crypto/caam/include/hash.h85
-rw-r--r--drivers/nxp/crypto/caam/include/jobdesc.h56
-rw-r--r--drivers/nxp/crypto/caam/include/jr_driver_config.h205
-rw-r--r--drivers/nxp/crypto/caam/include/rsa.h40
-rw-r--r--drivers/nxp/crypto/caam/include/sec_hw_specific.h506
-rw-r--r--drivers/nxp/crypto/caam/include/sec_jr_driver.h178
-rw-r--r--drivers/nxp/crypto/caam/src/auth/hash.c2
-rw-r--r--drivers/nxp/crypto/caam/src/auth/nxp_crypto.c2
-rw-r--r--drivers/nxp/crypto/caam/src/hw_key_blob.c2
-rw-r--r--drivers/nxp/crypto/caam/src/jobdesc.c13
-rw-r--r--drivers/nxp/crypto/caam/src/rng.c4
-rw-r--r--drivers/nxp/csu/csu.h40
-rw-r--r--drivers/nxp/csu/csu.mk8
-rw-r--r--drivers/nxp/dcfg/dcfg.c21
-rw-r--r--drivers/nxp/dcfg/dcfg.h85
-rw-r--r--drivers/nxp/dcfg/dcfg.mk8
-rw-r--r--drivers/nxp/dcfg/dcfg_lsch2.h79
-rw-r--r--drivers/nxp/dcfg/dcfg_lsch3.h77
-rw-r--r--drivers/nxp/dcfg/scfg.h59
-rw-r--r--drivers/nxp/ddr/fsl-mmdc/ddr.mk12
-rw-r--r--drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h173
-rw-r--r--drivers/nxp/ddr/include/ddr.h151
-rw-r--r--drivers/nxp/ddr/include/ddr_io.h38
-rw-r--r--drivers/nxp/ddr/include/dimm.h330
-rw-r--r--drivers/nxp/ddr/include/immap.h125
-rw-r--r--drivers/nxp/ddr/include/opts.h119
-rw-r--r--drivers/nxp/ddr/include/regs.h109
-rw-r--r--drivers/nxp/ddr/include/utility.h24
-rw-r--r--drivers/nxp/ddr/nxp-ddr/ddr.c15
-rw-r--r--drivers/nxp/ddr/nxp-ddr/ddr.mk23
-rw-r--r--drivers/nxp/ddr/nxp-ddr/ddrc.c2
-rw-r--r--drivers/nxp/ddr/nxp-ddr/dimm.c6
-rw-r--r--drivers/nxp/ddr/nxp-ddr/regs.c2
-rw-r--r--drivers/nxp/ddr/nxp-ddr/utility.c25
-rw-r--r--drivers/nxp/ddr/phy-gen2/messages.h20
-rw-r--r--drivers/nxp/ddr/phy-gen2/phy.c124
-rw-r--r--drivers/nxp/ddr/phy-gen2/phy.h26
-rw-r--r--drivers/nxp/drivers.mk13
-rw-r--r--drivers/nxp/flexspi/nor/fspi.c3
-rw-r--r--drivers/nxp/gic/gic.mk4
-rw-r--r--drivers/nxp/gic/include/gicv2/plat_gic.h72
-rw-r--r--drivers/nxp/gic/include/gicv3/plat_gic.h114
-rw-r--r--drivers/nxp/gpio/gpio.mk6
-rw-r--r--drivers/nxp/gpio/nxp_gpio.h53
-rw-r--r--drivers/nxp/i2c/i2c.h52
-rw-r--r--drivers/nxp/i2c/i2c.mk8
-rw-r--r--drivers/nxp/ifc/nand/ifc.h329
-rw-r--r--drivers/nxp/ifc/nand/ifc_nand.c658
-rw-r--r--drivers/nxp/ifc/nand/ifc_nand.mk29
-rw-r--r--drivers/nxp/ifc/nor/ifc_nor.c18
-rw-r--r--drivers/nxp/ifc/nor/ifc_nor.mk28
-rw-r--r--drivers/nxp/interconnect/interconnect.mk4
-rw-r--r--drivers/nxp/interconnect/ls_interconnect.h19
-rw-r--r--drivers/nxp/pmu/pmu.h75
-rw-r--r--drivers/nxp/pmu/pmu.mk6
-rw-r--r--drivers/nxp/qspi/qspi.h30
-rw-r--r--drivers/nxp/qspi/qspi.mk8
-rw-r--r--drivers/nxp/sd/sd_mmc.c8
-rw-r--r--drivers/nxp/sd/sd_mmc.h337
-rw-r--r--drivers/nxp/sd/sd_mmc.mk8
-rw-r--r--drivers/nxp/sec_mon/sec_mon.mk6
-rw-r--r--drivers/nxp/sec_mon/snvs.h86
-rw-r--r--drivers/nxp/sfp/fuse_prov.c2
-rw-r--r--drivers/nxp/sfp/fuse_prov.h83
-rw-r--r--drivers/nxp/sfp/sfp.h100
-rw-r--r--drivers/nxp/sfp/sfp.mk10
-rw-r--r--drivers/nxp/sfp/sfp_error_codes.h40
-rw-r--r--drivers/nxp/timer/nxp_timer.c2
-rw-r--r--drivers/nxp/timer/nxp_timer.h35
-rw-r--r--drivers/nxp/timer/timer.mk6
-rw-r--r--drivers/nxp/trdc/imx_trdc.c365
-rw-r--r--drivers/nxp/tzc/plat_tzc380.c169
-rw-r--r--drivers/nxp/tzc/plat_tzc400.h55
-rw-r--r--drivers/nxp/tzc/tzc.mk15
-rw-r--r--drivers/partition/gpt.c12
-rw-r--r--drivers/partition/partition.c340
-rw-r--r--drivers/renesas/common/common.c5
-rw-r--r--drivers/renesas/common/console/rcar_console.S4
-rw-r--r--drivers/renesas/common/console/rcar_printf.c2
-rw-r--r--drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c74
-rw-r--r--drivers/renesas/common/ddr/ddr_b/boot_init_dram.c25
-rw-r--r--drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c45
-rw-r--r--drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h4
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h12
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h6
-rw-r--r--drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h12
-rw-r--r--drivers/renesas/common/emmc/emmc_cmd.c5
-rw-r--r--drivers/renesas/common/emmc/emmc_hal.h2
-rw-r--r--drivers/renesas/common/emmc/emmc_init.c9
-rw-r--r--drivers/renesas/common/emmc/emmc_registers.h15
-rw-r--r--drivers/renesas/common/iic_dvfs/iic_dvfs.c4
-rw-r--r--drivers/renesas/common/io/io_rcar.c141
-rw-r--r--drivers/renesas/common/pfc_regs.h4
-rw-r--r--drivers/renesas/common/pwrc/pwrc.c86
-rw-r--r--drivers/renesas/common/pwrc/pwrc.h21
-rw-r--r--drivers/renesas/common/rom/rom_api.c4
-rw-r--r--drivers/renesas/common/rom/rom_api.h2
-rw-r--r--drivers/renesas/common/scif/scif.S26
-rw-r--r--drivers/renesas/common/watchdog/swdt.c6
-rw-r--r--drivers/renesas/rcar/board/board.c6
-rw-r--r--drivers/renesas/rcar/board/board.h10
-rw-r--r--drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c2
-rw-r--r--drivers/rpi3/gpio/rpi3_gpio.c1
-rw-r--r--drivers/rpi3/rng/rpi3_rng.c15
-rw-r--r--drivers/rpi3/sdhost/rpi3_sdhost.c5
-rw-r--r--drivers/scmi-msg/base.c18
-rw-r--r--drivers/scmi-msg/clock.c12
-rw-r--r--drivers/scmi-msg/common.h18
-rw-r--r--drivers/scmi-msg/entry.c41
-rw-r--r--drivers/scmi-msg/power_domain.c239
-rw-r--r--drivers/scmi-msg/power_domain.h72
-rw-r--r--drivers/scmi-msg/sensor.c277
-rw-r--r--drivers/scmi-msg/sensor.h125
-rw-r--r--drivers/scmi-msg/smt.c8
-rw-r--r--drivers/st/bsec/bsec.c891
-rw-r--r--drivers/st/bsec/bsec2.c839
-rw-r--r--drivers/st/bsec/bsec3.c533
-rw-r--r--drivers/st/clk/clk-stm32-core.c1088
-rw-r--r--drivers/st/clk/clk-stm32-core.h393
-rw-r--r--drivers/st/clk/clk-stm32mp13.c2332
-rw-r--r--drivers/st/clk/stm32mp1_clk.c576
-rw-r--r--drivers/st/clk/stm32mp_clkfunc.c165
-rw-r--r--drivers/st/crypto/stm32_hash.c73
-rw-r--r--drivers/st/crypto/stm32_pka.c702
-rw-r--r--drivers/st/crypto/stm32_rng.c273
-rw-r--r--drivers/st/crypto/stm32_saes.c903
-rw-r--r--drivers/st/ddr/stm32mp1_ddr.c324
-rw-r--r--drivers/st/ddr/stm32mp1_ddr_helpers.c8
-rw-r--r--drivers/st/ddr/stm32mp1_ram.c223
-rw-r--r--drivers/st/ddr/stm32mp_ddr.c106
-rw-r--r--drivers/st/ddr/stm32mp_ddr_test.c140
-rw-r--r--drivers/st/ddr/stm32mp_ram.c60
-rw-r--r--drivers/st/etzpc/etzpc.c16
-rw-r--r--drivers/st/fmc/stm32_fmc2_nand.c16
-rw-r--r--drivers/st/gpio/stm32_gpio.c116
-rw-r--r--drivers/st/i2c/stm32_i2c.c86
-rw-r--r--drivers/st/io/io_mmc.c143
-rw-r--r--drivers/st/io/io_stm32image.c378
-rw-r--r--drivers/st/iwdg/stm32_iwdg.c7
-rw-r--r--drivers/st/mmc/stm32_sdmmc2.c171
-rw-r--r--drivers/st/pmic/stm32mp_pmic.c483
-rw-r--r--drivers/st/pmic/stpmic1.c208
-rw-r--r--drivers/st/regulator/regulator_core.c562
-rw-r--r--drivers/st/regulator/regulator_fixed.c87
-rw-r--r--drivers/st/spi/stm32_qspi.c29
-rw-r--r--drivers/st/uart/aarch32/stm32_console.S39
-rw-r--r--drivers/st/uart/aarch64/stm32_console.S255
-rw-r--r--drivers/st/uart/stm32_uart.c439
-rw-r--r--drivers/st/usb/stm32mp1_usb.c1088
-rw-r--r--drivers/ti/uart/aarch32/16550_console.S2
-rw-r--r--drivers/ti/uart/aarch64/16550_console.S2
-rw-r--r--drivers/ufs/ufs.c630
-rw-r--r--drivers/usb/usb_device.c845
281 files changed, 26423 insertions, 9640 deletions
diff --git a/drivers/allwinner/axp/axp803.c b/drivers/allwinner/axp/axp803.c
index 53b11c11ac..19a9549ed7 100644
--- a/drivers/allwinner/axp/axp803.c
+++ b/drivers/allwinner/axp/axp803.c
@@ -9,7 +9,9 @@
const uint8_t axp_chip_id = AXP803_CHIP_ID;
const char *const axp_compatible = "x-powers,axp803";
+#if SUNXI_SETUP_REGULATORS == 1
const struct axp_regulator axp_regulators[] = {
+ {"aldo1", 700, 3300, 100, NA, 0x28, 0x13, 5},
{"dcdc1", 1600, 3400, 100, NA, 0x20, 0x10, 0},
{"dcdc5", 800, 1840, 10, 32, 0x24, 0x10, 4},
{"dcdc6", 600, 1520, 10, 50, 0x25, 0x10, 5},
@@ -20,3 +22,4 @@ const struct axp_regulator axp_regulators[] = {
{"fldo1", 700, 1450, 50, NA, 0x1c, 0x13, 2},
{}
};
+#endif
diff --git a/drivers/allwinner/axp/axp805.c b/drivers/allwinner/axp/axp805.c
index 8d029c0bdf..3a03fec650 100644
--- a/drivers/allwinner/axp/axp805.c
+++ b/drivers/allwinner/axp/axp805.c
@@ -9,6 +9,7 @@
const uint8_t axp_chip_id = AXP805_CHIP_ID;
const char *const axp_compatible = "x-powers,axp805";
+#if SUNXI_SETUP_REGULATORS == 1
/*
* The "dcdcd" split changes the step size by a factor of 5, not 2;
* disallow values above the split to maintain accuracy.
@@ -31,3 +32,4 @@ const struct axp_regulator axp_regulators[] = {
{"cldo3", 700, 3300, 100, NA, 0x26, 0x11, 6},
{}
};
+#endif
diff --git a/drivers/allwinner/axp/common.c b/drivers/allwinner/axp/common.c
index 143fb0f2d2..79f9089344 100644
--- a/drivers/allwinner/axp/common.c
+++ b/drivers/allwinner/axp/common.c
@@ -9,6 +9,7 @@
#include <libfdt.h>
#include <common/debug.h>
+#include <common/fdt_wrappers.h>
#include <drivers/allwinner/axp.h>
int axp_check_id(void)
@@ -48,6 +49,7 @@ void axp_power_off(void)
axp_setbits(0x32, BIT(7));
}
+#if SUNXI_SETUP_REGULATORS == 1
/*
* Retrieve the voltage from a given regulator DTB node.
* Both the regulator-{min,max}-microvolt properties must be present and
@@ -96,19 +98,9 @@ static int setup_regulator(const void *fdt, int node,
return 0;
}
-static bool is_node_disabled(const void *fdt, int node)
-{
- const char *cell;
- cell = fdt_getprop(fdt, node, "status", NULL);
- if (cell == NULL) {
- return false;
- }
- return strcmp(cell, "okay") != 0;
-}
-
static bool should_enable_regulator(const void *fdt, int node)
{
- if (is_node_disabled(fdt, node)) {
+ if (!fdt_node_is_enabled(fdt, node)) {
return false;
}
if (fdt_getprop(fdt, node, "phandle", NULL) != NULL) {
@@ -208,3 +200,4 @@ void axp_setup_regulators(const void *fdt)
axp_setbits(0x11, BIT(7));
}
}
+#endif /* SUNXI_SETUP_REGULATORS */
diff --git a/drivers/amlogic/console/aarch64/meson_console.S b/drivers/amlogic/console/aarch64/meson_console.S
index 6d0a2d62e7..d955d83c5d 100644
--- a/drivers/amlogic/console/aarch64/meson_console.S
+++ b/drivers/amlogic/console/aarch64/meson_console.S
@@ -69,7 +69,7 @@ func console_meson_register
mov x0, x6
mov x30, x7
- finish_console_register meson putc=1, getc=1, flush=1
+ finish_console_register meson putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
ret x7
diff --git a/drivers/amlogic/crypto/sha_dma.c b/drivers/amlogic/crypto/sha_dma.c
index fceb1c0d3e..5c16d49c7d 100644
--- a/drivers/amlogic/crypto/sha_dma.c
+++ b/drivers/amlogic/crypto/sha_dma.c
@@ -8,6 +8,7 @@
#include <assert.h>
#include <crypto/sha_dma.h>
#include <lib/mmio.h>
+#include <platform_def.h>
#include "aml_private.h"
diff --git a/drivers/arm/css/mhu/css_mhu_doorbell.c b/drivers/arm/css/mhu/css_mhu_doorbell.c
index c51f3b1d78..479bb21b3c 100644
--- a/drivers/arm/css/mhu/css_mhu_doorbell.c
+++ b/drivers/arm/css/mhu/css_mhu_doorbell.c
@@ -15,7 +15,6 @@ void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info)
MHU_RING_DOORBELL(plat_info->db_reg_addr,
plat_info->db_modify_mask,
plat_info->db_preserve_mask);
- return;
}
void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info)
@@ -35,6 +34,4 @@ void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info)
/* clear the access request for the receiver */
MHU_V2_CLEAR_REQUEST(mhuv2_base);
-
- return;
}
diff --git a/drivers/arm/css/scmi/scmi_common.c b/drivers/arm/css/scmi/scmi_common.c
index 5b3724ace6..ca855fe711 100644
--- a/drivers/arm/css/scmi/scmi_common.c
+++ b/drivers/arm/css/scmi/scmi_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,7 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/css/scmi.h>
+#include <drivers/delay_timer.h>
#include "scmi_private.h"
@@ -60,8 +61,10 @@ void scmi_send_sync_command(scmi_channel_t *ch)
dmbsy();
/* Wait for channel to be free */
- while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status))
- ;
+ while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status)) {
+ if (ch->info->delay != 0)
+ udelay(ch->info->delay);
+ }
/*
* Ensure that any read to the SCMI payload area is done after reading
@@ -173,12 +176,12 @@ void *scmi_init(scmi_channel_t *ch)
ret = scmi_proto_version(ch, SCMI_PWR_DMN_PROTO_ID, &version);
if (ret != SCMI_E_SUCCESS) {
- WARN("SCMI power domain protocol version message failed");
+ WARN("SCMI power domain protocol version message failed\n");
goto error;
}
if (!is_scmi_version_compatible(SCMI_PWR_DMN_PROTO_VER, version)) {
- WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x",
+ WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x\n",
version, SCMI_PWR_DMN_PROTO_VER);
goto error;
}
@@ -187,12 +190,12 @@ void *scmi_init(scmi_channel_t *ch)
ret = scmi_proto_version(ch, SCMI_SYS_PWR_PROTO_ID, &version);
if ((ret != SCMI_E_SUCCESS)) {
- WARN("SCMI system power protocol version message failed");
+ WARN("SCMI system power protocol version message failed\n");
goto error;
}
if (!is_scmi_version_compatible(SCMI_SYS_PWR_PROTO_VER, version)) {
- WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x",
+ WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x\n",
version, SCMI_SYS_PWR_PROTO_VER);
goto error;
}
diff --git a/drivers/arm/css/scmi/scmi_private.h b/drivers/arm/css/scmi/scmi_private.h
index 61437f6d7a..a684ca5d07 100644
--- a/drivers/arm/css/scmi/scmi_private.h
+++ b/drivers/arm/css/scmi/scmi_private.h
@@ -136,7 +136,7 @@ typedef struct mailbox_mem {
uint64_t res_b; /* Reserved */
uint32_t flags;
volatile uint32_t len;
- uint32_t msg_header;
+ volatile uint32_t msg_header;
uint32_t payload[];
} mailbox_mem_t;
diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.c b/drivers/arm/css/scmi/vendor/scmi_sq.c
index f18542487e..1037633607 100644
--- a/drivers/arm/css/scmi/vendor/scmi_sq.c
+++ b/drivers/arm/css/scmi/vendor/scmi_sq.c
@@ -15,7 +15,7 @@
#include <sq_common.h>
-/* SCMI messge ID to get the available DRAM region */
+/* SCMI message ID to get the available DRAM region */
#define SCMI_VENDOR_EXT_MEMINFO_GET_MSG 0x3
#define SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN 4
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
index aeb7eda305..9fe8b3759d 100644
--- a/drivers/arm/css/scp/css_pm_scmi.c
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,6 +11,7 @@
#include <common/debug.h>
#include <drivers/arm/css/css_scp.h>
#include <drivers/arm/css/scmi.h>
+#include <lib/mmio.h>
#include <plat/arm/common/plat_arm.h>
#include <plat/arm/css/common/css_pm.h>
#include <plat/common/platform.h>
@@ -286,15 +287,42 @@ int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
return HW_OFF;
}
+/*
+ * Callback function to raise a SGI designated to trigger the CPU power down
+ * sequence on all the online secondary cores.
+ */
+static void css_raise_pwr_down_interrupt(u_register_t mpidr)
+{
+#if CSS_SYSTEM_GRACEFUL_RESET
+ plat_ic_raise_el3_sgi(CSS_CPU_PWR_DOWN_REQ_INTR, mpidr);
+#endif
+}
+
void __dead2 css_scp_system_off(int state)
{
int ret;
/*
+ * Before issuing the system power down command, set the trusted mailbox
+ * to 0. This will ensure that in the case of a warm/cold reset, the
+ * primary CPU executes from the cold boot sequence.
+ */
+ mmio_write_64(PLAT_ARM_TRUSTED_MAILBOX_BASE, 0U);
+
+ /*
+ * Send powerdown request to online secondary core(s)
+ */
+ ret = psci_stop_other_cores(0, css_raise_pwr_down_interrupt);
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("Failed to powerdown secondary core(s)\n");
+ }
+
+ /*
* Disable GIC CPU interface to prevent pending interrupt from waking
* up the AP from WFI.
*/
plat_arm_gic_cpuif_disable();
+ plat_arm_gic_redistif_off();
/*
* Issue SCMI command. First issue a graceful
@@ -309,6 +337,9 @@ void __dead2 css_scp_system_off(int state)
state, ret);
panic();
}
+
+ /* Powerdown of primary core */
+ psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
wfi();
ERROR("CSS set power state: operation not handled.\n");
panic();
@@ -357,7 +388,7 @@ void __init plat_arm_pwrc_setup(void)
unsigned int composite_id, idx;
for (idx = 0; idx < PLAT_ARM_SCMI_CHANNEL_COUNT; idx++) {
- INFO("Initializing driver on Channel %d\n", idx);
+ INFO("Initializing SCMI driver on channel %d\n", idx);
scmi_channels[idx].info = plat_css_get_scmi_info(idx);
scmi_channels[idx].lock = ARM_SCMI_LOCK_GET_INSTANCE;
diff --git a/drivers/arm/css/scp/css_sds.c b/drivers/arm/css/scp/css_sds.c
index e42ee10d75..d9965c671e 100644
--- a/drivers/arm/css/scp/css_sds.c
+++ b/drivers/arm/css/scp/css_sds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,7 +20,7 @@ int css_scp_boot_image_xfer(void *image, unsigned int image_size)
int ret;
unsigned int image_offset, image_flags;
- ret = sds_init();
+ ret = sds_init(SDS_SCP_AP_REGION_ID);
if (ret != SDS_OK) {
ERROR("SCP SDS initialization failed\n");
panic();
@@ -28,13 +28,15 @@ int css_scp_boot_image_xfer(void *image, unsigned int image_size)
VERBOSE("Writing SCP image metadata\n");
image_offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE;
- ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_ADDR_OFFSET,
+ ret = sds_struct_write(SDS_SCP_AP_REGION_ID,
+ SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_ADDR_OFFSET,
&image_offset, SDS_SCP_IMG_ADDR_SIZE,
SDS_ACCESS_MODE_NON_CACHED);
if (ret != SDS_OK)
goto sds_fail;
- ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_SIZE_OFFSET,
+ ret = sds_struct_write(SDS_SCP_AP_REGION_ID,
+ SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_SIZE_OFFSET,
&image_size, SDS_SCP_IMG_SIZE_SIZE,
SDS_ACCESS_MODE_NON_CACHED);
if (ret != SDS_OK)
@@ -42,7 +44,8 @@ int css_scp_boot_image_xfer(void *image, unsigned int image_size)
VERBOSE("Marking SCP image metadata as valid\n");
image_flags = SDS_SCP_IMG_VALID_FLAG_BIT;
- ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_FLAG_OFFSET,
+ ret = sds_struct_write(SDS_SCP_AP_REGION_ID,
+ SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_FLAG_OFFSET,
&image_flags, SDS_SCP_IMG_FLAG_SIZE,
SDS_ACCESS_MODE_NON_CACHED);
if (ret != SDS_OK)
@@ -68,7 +71,8 @@ int css_scp_boot_ready(void)
/* Wait for the SCP RAM Firmware to complete its initialization process */
while (retry > 0) {
- ret = sds_struct_read(SDS_FEATURE_AVAIL_STRUCT_ID, 0,
+ ret = sds_struct_read(SDS_SCP_AP_REGION_ID,
+ SDS_FEATURE_AVAIL_STRUCT_ID, 0,
&scp_feature_availability_flags,
SDS_FEATURE_AVAIL_SIZE,
SDS_ACCESS_MODE_NON_CACHED);
diff --git a/drivers/arm/css/sds/sds.c b/drivers/arm/css/sds/sds.c
index 1fb196c708..91f0a27a41 100644
--- a/drivers/arm/css/sds/sds.c
+++ b/drivers/arm/css/sds/sds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,40 +15,39 @@
#include "sds_private.h"
-/*
- * Variables used to track and maintain the state of the memory region reserved
- * for usage by the SDS framework.
- */
+/* Array of SDS memory region descriptions */
+static sds_region_desc_t *sds_regions;
-/* Pointer to the base of the SDS memory region */
-static uintptr_t sds_mem_base;
-
-/* Size of the SDS memory region in bytes */
-static size_t sds_mem_size;
+/* Total count of SDS memory regions */
+static unsigned int sds_region_cnt;
/*
* Perform some non-exhaustive tests to determine whether any of the fields
* within a Structure Header contain obviously invalid data.
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
*/
-static int sds_struct_is_valid(uintptr_t header)
+static int sds_struct_is_valid(unsigned int region_id, uintptr_t header)
{
size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header);
/* Zero is not a valid identifier */
- if (GET_SDS_HEADER_ID(header) == 0)
+ if (GET_SDS_HEADER_ID(header) == 0) {
return SDS_ERR_FAIL;
+ }
/* Check SDS Schema version */
- if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION)
+ if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION) {
return SDS_ERR_FAIL;
+ }
/* The SDS Structure sizes have to be multiple of 8 */
- if ((struct_size == 0) || ((struct_size % 8) != 0))
+ if ((struct_size == 0) || ((struct_size % 8) != 0)) {
return SDS_ERR_FAIL;
+ }
- if (struct_size > sds_mem_size)
+ if (struct_size > sds_regions[region_id].size) {
return SDS_ERR_FAIL;
+ }
return SDS_OK;
}
@@ -57,10 +56,11 @@ static int sds_struct_is_valid(uintptr_t header)
* Validate the SDS structure headers.
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
*/
-static int validate_sds_struct_headers(void)
+static int validate_sds_struct_headers(unsigned int region_id)
{
unsigned int i, structure_count;
uintptr_t header;
+ uintptr_t sds_mem_base = sds_regions[region_id].base;
structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
@@ -71,7 +71,7 @@ static int validate_sds_struct_headers(void)
/* Iterate over structure headers and validate each one */
for (i = 0; i < structure_count; i++) {
- if (sds_struct_is_valid(header) != SDS_OK) {
+ if (sds_struct_is_valid(region_id, header) != SDS_OK) {
WARN("SDS: Invalid structure header detected\n");
return SDS_ERR_FAIL;
}
@@ -84,10 +84,12 @@ static int validate_sds_struct_headers(void)
* Get the structure header pointer corresponding to the structure ID.
* Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
*/
-static int get_struct_header(uint32_t structure_id, struct_header_t **header)
+static int get_struct_header(unsigned int region_id, uint32_t structure_id,
+ struct_header_t **header)
{
unsigned int i, structure_count;
uintptr_t current_header;
+ uintptr_t sds_mem_base = sds_regions[region_id].base;
assert(header);
@@ -116,12 +118,14 @@ static int get_struct_header(uint32_t structure_id, struct_header_t **header)
* Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
* if not found.
*/
-int sds_struct_exists(unsigned int structure_id)
+int sds_struct_exists(unsigned int region_id, unsigned int structure_id)
{
struct_header_t *header = NULL;
int ret;
- ret = get_struct_header(structure_id, &header);
+ assert(region_id < sds_region_cnt);
+
+ ret = get_struct_header(region_id, structure_id, &header);
if (ret == SDS_OK) {
assert(header);
}
@@ -136,18 +140,21 @@ int sds_struct_exists(unsigned int structure_id)
* The `data` is the pointer to store the read data of size specified by `size`.
* Returns SDS_OK on success or corresponding error codes on failure.
*/
-int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
- void *data, size_t size, sds_access_mode_t mode)
+int sds_struct_read(unsigned int region_id, uint32_t structure_id,
+ unsigned int fld_off, void *data, size_t size,
+ sds_access_mode_t mode)
{
int status;
uintptr_t field_base;
struct_header_t *header = NULL;
+ assert(region_id < sds_region_cnt);
+
if (!data)
return SDS_ERR_INVALID_PARAMS;
/* Check if a structure with this ID exists */
- status = get_struct_header(structure_id, &header);
+ status = get_struct_header(region_id, structure_id, &header);
if (status != SDS_OK)
return status;
@@ -182,18 +189,21 @@ int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
* The `data` is the pointer to data of size specified by `size`.
* Returns SDS_OK on success or corresponding error codes on failure.
*/
-int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
- void *data, size_t size, sds_access_mode_t mode)
+int sds_struct_write(unsigned int region_id, uint32_t structure_id,
+ unsigned int fld_off, void *data, size_t size,
+ sds_access_mode_t mode)
{
int status;
uintptr_t field_base;
struct_header_t *header = NULL;
+ assert(region_id < sds_region_cnt);
+
if (!data)
return SDS_ERR_INVALID_PARAMS;
/* Check if a structure with this ID exists */
- status = get_struct_header(structure_id, &header);
+ status = get_struct_header(region_id, structure_id, &header);
if (status != SDS_OK)
return status;
@@ -226,15 +236,21 @@ int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
/*
* Initialize the SDS driver. Also verifies the SDS version and sanity of
- * the SDS structure headers.
+ * the SDS structure headers in the given SDS region.
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
*/
-int sds_init(void)
+int sds_init(unsigned int region_id)
{
- sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE;
+ if (sds_regions == NULL) {
+ sds_regions = plat_sds_get_regions(&sds_region_cnt);
+ }
+
+ assert(region_id < sds_region_cnt);
+
+ uintptr_t sds_mem_base = sds_regions[region_id].base;
if (!IS_SDS_REGION_VALID(sds_mem_base)) {
- WARN("SDS: No valid SDS Memory Region found\n");
+ VERBOSE("SDS: No valid SDS Memory Region found\n");
return SDS_ERR_FAIL;
}
@@ -244,15 +260,16 @@ int sds_init(void)
return SDS_ERR_FAIL;
}
- sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base);
- if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
+ sds_regions[region_id].size = GET_SDS_REGION_SIZE(sds_mem_base);
+ if (sds_regions[region_id].size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
WARN("SDS: SDS Memory Region exceeds size limit\n");
return SDS_ERR_FAIL;
}
- INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size);
+ INFO("SDS: Detected SDS Memory Region (%zu bytes)\n",
+ sds_regions[region_id].size);
- if (validate_sds_struct_headers() != SDS_OK)
+ if (validate_sds_struct_headers(region_id) != SDS_OK)
return SDS_ERR_FAIL;
return SDS_OK;
diff --git a/drivers/arm/dcc/dcc_console.c b/drivers/arm/dcc/dcc_console.c
index 0b7e541f06..19c3450b39 100644
--- a/drivers/arm/dcc/dcc_console.c
+++ b/drivers/arm/dcc/dcc_console.c
@@ -53,6 +53,7 @@ static inline uint32_t __dcc_getstatus(void)
return read_mdccsr_el0();
}
+#if ENABLE_CONSOLE_GETC
static inline char __dcc_getchar(void)
{
char c;
@@ -61,6 +62,7 @@ static inline char __dcc_getchar(void)
return c;
}
+#endif
static inline void __dcc_putchar(char c)
{
@@ -102,6 +104,7 @@ static int32_t dcc_console_putc(int32_t ch, struct console *console)
return ch;
}
+#if ENABLE_CONSOLE_GETC
static int32_t dcc_console_getc(struct console *console)
{
unsigned int status;
@@ -113,12 +116,7 @@ static int32_t dcc_console_getc(struct console *console)
return __dcc_getchar();
}
-
-int32_t dcc_console_init(unsigned long base_addr, uint32_t uart_clk,
- uint32_t baud_rate)
-{
- return 0; /* No init needed */
-}
+#endif
/**
* dcc_console_flush() - Function to force a write of all buffered data
@@ -139,9 +137,12 @@ static void dcc_console_flush(struct console *console)
static struct dcc_console dcc_console = {
.console = {
.flags = CONSOLE_FLAG_BOOT |
- CONSOLE_FLAG_RUNTIME,
+ CONSOLE_FLAG_RUNTIME |
+ CONSOLE_FLAG_CRASH,
.putc = dcc_console_putc,
+#if ENABLE_CONSOLE_GETC
.getc = dcc_console_getc,
+#endif
.flush = dcc_console_flush,
},
};
@@ -150,3 +151,9 @@ int console_dcc_register(void)
{
return console_register(&dcc_console.console);
}
+
+void console_dcc_unregister(void)
+{
+ dcc_console_flush(&dcc_console.console);
+ (void)console_unregister(&dcc_console.console);
+}
diff --git a/drivers/arm/ethosn/ethosn_big_fw.c b/drivers/arm/ethosn/ethosn_big_fw.c
new file mode 100644
index 0000000000..2aad5da354
--- /dev/null
+++ b/drivers/arm/ethosn/ethosn_big_fw.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include "ethosn_big_fw.h"
+
+/* Magic (FourCC) number to identify the big firmware binary */
+#define ETHOSN_BIG_FW_MAGIC ('E' | ('N' << 8) | ('F' << 16) | ('W' << 24))
+
+/* Supported big firmware version */
+#define ETHOSN_BIG_FW_VERSION_MAJOR 15
+
+#define ETHOSN_ARCH_VER_MAJOR_MASK U(0xF000)
+#define ETHOSN_ARCH_VER_MAJOR_SHIFT U(0xC)
+#define ETHOSN_ARCH_VER_MINOR_MASK U(0xF00)
+#define ETHOSN_ARCH_VER_MINOR_SHIFT U(0x8)
+#define ETHOSN_ARCH_VER_REV_MASK U(0xFF)
+
+/* Convert Arm(R) Ethos(TM)-N NPU architecture version to big firmware format */
+#define ETHOSN_BIG_FW_FORMAT_ARCH_VER(arch_ver) \
+ (arch_ver & ETHOSN_ARCH_VER_MAJOR_MASK) << ETHOSN_ARCH_VER_MAJOR_SHIFT | \
+ (arch_ver & ETHOSN_ARCH_VER_MINOR_MASK) << ETHOSN_ARCH_VER_MINOR_SHIFT | \
+ (arch_ver & ETHOSN_ARCH_VER_REV_MASK)
+
+
+bool ethosn_big_fw_verify_header(const struct ethosn_big_fw *big_fw,
+ uint32_t npu_arch_ver)
+{
+ const uint32_t arch_ver = ETHOSN_BIG_FW_FORMAT_ARCH_VER(npu_arch_ver);
+
+ if (big_fw->fw_magic != ETHOSN_BIG_FW_MAGIC) {
+ ERROR("ETHOSN: Unable to find firmware. Invalid magic value: 0x%02x\n",
+ big_fw->fw_magic);
+
+ return false;
+ }
+
+ if (big_fw->fw_ver_major != ETHOSN_BIG_FW_VERSION_MAJOR) {
+ ERROR("ETHOSN: Unsupported firmware version: %u.%u.%u. Expected Version %u.x.x.\n",
+ big_fw->fw_ver_major, big_fw->fw_ver_minor,
+ big_fw->fw_ver_patch, ETHOSN_BIG_FW_VERSION_MAJOR);
+
+ return false;
+ }
+
+ if (big_fw->arch_min > arch_ver || arch_ver > big_fw->arch_max) {
+ ERROR("ETHOSN: Firmware is not compatbile with architecture version: 0x%02x\n",
+ npu_arch_ver);
+ return false;
+ }
+
+ return true;
+}
diff --git a/drivers/arm/ethosn/ethosn_big_fw.h b/drivers/arm/ethosn/ethosn_big_fw.h
new file mode 100644
index 0000000000..a3213229f1
--- /dev/null
+++ b/drivers/arm/ethosn/ethosn_big_fw.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * Big FW binary structure.
+ * Must be kept in sync with the Arm(R) Ethos(TM)-N NPU firmware binary layout.
+ */
+struct ethosn_big_fw {
+ uint32_t fw_magic;
+ uint32_t fw_ver_major;
+ uint32_t fw_ver_minor;
+ uint32_t fw_ver_patch;
+ uint32_t arch_min;
+ uint32_t arch_max;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t code_offset;
+ uint32_t code_size;
+ uint32_t ple_offset;
+ uint32_t ple_size;
+ uint32_t vector_table_offset;
+ uint32_t vector_table_size;
+ uint32_t unpriv_stack_offset;
+ uint32_t unpriv_stack_size;
+ uint32_t priv_stack_offset;
+ uint32_t priv_stack_size;
+} __packed;
+
+bool ethosn_big_fw_verify_header(const struct ethosn_big_fw *big_fw,
+ uint32_t npu_arch_ver);
diff --git a/drivers/arm/ethosn/ethosn_npu.mk b/drivers/arm/ethosn/ethosn_npu.mk
new file mode 100644
index 0000000000..4a31b597d0
--- /dev/null
+++ b/drivers/arm/ethosn/ethosn_npu.mk
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Arm(R) Ethos(TM)-N NPU SiP service
+ETHOSN_NPU_DRIVER := 0
+
+$(eval $(call assert_boolean,ETHOSN_NPU_DRIVER))
+$(eval $(call add_define,ETHOSN_NPU_DRIVER))
+
+#Ethos-N NPU TZMP1
+ETHOSN_NPU_TZMP1 := 0
+$(eval $(call assert_boolean,ETHOSN_NPU_TZMP1))
+$(eval $(call add_define,ETHOSN_NPU_TZMP1))
+ifeq (${ETHOSN_NPU_TZMP1},1)
+ ifeq (${ETHOSN_NPU_DRIVER},0)
+ $(error "ETHOSN_NPU_TZMP1 is only available if ETHOSN_NPU_DRIVER=1)
+ endif
+ ifeq (${PLAT},juno)
+ $(eval $(call add_define,JUNO_ETHOSN_TZMP1))
+ else
+ $(error "ETHOSN_NPU_TZMP1 only supported on Juno platform, not ", ${PLAT})
+ endif
+
+ ifeq (${TRUSTED_BOARD_BOOT},0)
+ # We rely on TRUSTED_BOARD_BOOT to prevent the firmware code from being
+ # tampered with, which is required to protect the confidentiality of protected
+ # inference data.
+ $(error "ETHOSN_NPU_TZMP1 is only available if TRUSTED_BOARD_BOOT is enabled)
+ endif
+
+ # We need the FW certificate and key certificate
+ $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/npu_fw_key.crt,--npu-fw-key-cert))
+ $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/npu_fw_content.crt,--npu-fw-cert))
+ # We need the firmware to be built into the FIP
+ $(eval $(call TOOL_ADD_IMG,ETHOSN_NPU_FW,--npu-fw))
+
+ # Needed for our OIDs to be available in tbbr_cot_bl2.c
+ $(eval $(call add_define, PLAT_DEF_OID))
+
+ # Needed so that UUIDs from the FIP are available in BL2
+ $(eval $(call add_define,PLAT_DEF_FIP_UUID))
+
+ PLAT_INCLUDES += -I${PLAT_DIR}certificate/include
+ PLAT_INCLUDES += -Iinclude/drivers/arm/
+ PLAT_INCLUDES += -I${PLAT_DIR}fip
+endif
diff --git a/drivers/arm/ethosn/ethosn_smc.c b/drivers/arm/ethosn/ethosn_smc.c
index 299d07c02b..9aa7e238a9 100644
--- a/drivers/arm/ethosn/ethosn_smc.c
+++ b/drivers/arm/ethosn/ethosn_smc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,45 +12,280 @@
#include <drivers/arm/ethosn.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
+#include <lib/utils_def.h>
#include <plat/arm/common/fconf_ethosn_getter.h>
-/* Arm Ethos-N NPU (NPU) status */
-#define ETHOSN_STATUS \
- FCONF_GET_PROPERTY(hw_config, ethosn_config, status)
+#include <platform_def.h>
-/* Number of NPU cores available */
-#define ETHOSN_NUM_CORES \
- FCONF_GET_PROPERTY(hw_config, ethosn_config, num_cores)
+#if ETHOSN_NPU_TZMP1
+#include "ethosn_big_fw.h"
+#endif /* ETHOSN_NPU_TZMP1 */
-/* Address to an NPU core */
-#define ETHOSN_CORE_ADDR(core_idx) \
- FCONF_GET_PROPERTY(hw_config, ethosn_core_addr, core_idx)
+/*
+ * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
+ */
+#define ETHOSN_NUM_DEVICES \
+ FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
+
+#define ETHOSN_GET_DEVICE(dev_idx) \
+ FCONF_GET_PROPERTY(hw_config, ethosn_device, dev_idx)
/* NPU core sec registry address */
#define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
(core_addr + reg_offset)
+#define ETHOSN_FW_VA_BASE 0x20000000UL
+#define ETHOSN_WORKING_DATA_VA_BASE 0x40000000UL
+#define ETHOSN_COMMAND_STREAM_VA_BASE 0x60000000UL
+
/* Reset timeout in us */
#define ETHOSN_RESET_TIMEOUT_US U(10 * 1000 * 1000)
#define ETHOSN_RESET_WAIT_US U(1)
+#define ETHOSN_AUX_FEAT_LEVEL_IRQ U(0x1)
+#define ETHOSN_AUX_FEAT_STASHING U(0x2)
+
+#define SEC_AUXCTLR_REG U(0x0024)
+#define SEC_AUXCTLR_VAL U(0x000ce080)
+#define SEC_AUXCTLR_LEVEL_IRQ_VAL U(0x04)
+#define SEC_AUXCTLR_STASHING_VAL U(0xA5000000)
+
#define SEC_DEL_REG U(0x0004)
-#define SEC_DEL_VAL U(0x81C)
+#if ETHOSN_NPU_TZMP1
+#define SEC_DEL_VAL U(0x808)
+#else
+#define SEC_DEL_VAL U(0x80C)
+#endif /* ETHOSN_NPU_TZMP1 */
#define SEC_DEL_EXCC_MASK U(0x20)
#define SEC_SECCTLR_REG U(0x0010)
-#define SEC_SECCTLR_VAL U(0x3)
-
-#define SEC_DEL_MMUSID_REG U(0x2008)
-#define SEC_DEL_MMUSID_VAL U(0x3FFFF)
+/* Set bit[10] = 1 to workaround erratum 2838783 */
+#define SEC_SECCTLR_VAL U(0x403)
-#define SEC_DEL_ADDR_EXT_REG U(0x201C)
-#define SEC_DEL_ADDR_EXT_VAL U(0x15)
+#define SEC_DEL_ADDR_EXT_REG U(0x201C)
+#define SEC_DEL_ADDR_EXT_VAL U(0x1)
#define SEC_SYSCTRL0_REG U(0x0018)
-#define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
+#define SEC_SYSCTRL0_CPU_WAIT U(1)
+#define SEC_SYSCTRL0_SLEEPING U(1U << 4)
+#define SEC_SYSCTRL0_INITVTOR_MASK U(0x1FFFFF80)
+#define SEC_SYSCTRL0_SOFT_RESET U(1U << 29)
#define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
+#define SEC_SYSCTRL1_REG U(0x001C)
+#define SEC_SYSCTRL1_VAL U(0xe0180110)
+
+#define SEC_NSAID_REG_BASE U(0x3004)
+#define SEC_NSAID_OFFSET U(0x1000)
+
+#define SEC_MMUSID_REG_BASE U(0x3008)
+#define SEC_MMUSID_OFFSET U(0x1000)
+
+#define SEC_ADDR_EXT_REG_BASE U(0x3018)
+#define SEC_ADDR_EXT_OFFSET U(0x1000)
+#define SEC_ADDR_EXT_SHIFT U(0x14)
+#define SEC_ADDR_EXT_MASK U(0x1FFFFE00)
+
+#define SEC_ATTR_CTLR_REG_BASE U(0x3010)
+#define SEC_ATTR_CTLR_OFFSET U(0x1000)
+#define SEC_ATTR_CTLR_NUM U(9)
+#define SEC_ATTR_CTLR_VAL U(0x1)
+
+#define SEC_NPU_ID_REG U(0xF000)
+#define SEC_NPU_ID_ARCH_VER_SHIFT U(0X10)
+
+#define FIRMWARE_STREAM_INDEX U(0x0)
+#define WORKING_STREAM_INDEX U(0x1)
+#define PLE_STREAM_INDEX U(0x4)
+#define INPUT_STREAM_INDEX U(0x6)
+#define INTERMEDIATE_STREAM_INDEX U(0x7)
+#define OUTPUT_STREAM_INDEX U(0x8)
+
+#define TO_EXTEND_ADDR(addr) \
+ ((addr >> SEC_ADDR_EXT_SHIFT) & SEC_ADDR_EXT_MASK)
+
+#if ETHOSN_NPU_TZMP1
+CASSERT(ETHOSN_NPU_FW_IMAGE_BASE > 0U, assert_ethosn_invalid_fw_image_base);
+static const struct ethosn_big_fw *big_fw;
+
+#define FW_INITVTOR_ADDR(big_fw) \
+ ((ETHOSN_FW_VA_BASE + big_fw->vector_table_offset) & \
+ SEC_SYSCTRL0_INITVTOR_MASK)
+
+#define SYSCTRL0_INITVTOR_ADDR(value) \
+ (value & SEC_SYSCTRL0_INITVTOR_MASK)
+
+#endif /* ETHOSN_NPU_TZMP1 */
+
+static bool ethosn_get_device_and_core(uintptr_t core_addr,
+ const struct ethosn_device_t **dev_match,
+ const struct ethosn_core_t **core_match)
+{
+ uint32_t dev_idx;
+ uint32_t core_idx;
+
+ for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
+ const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
+
+ for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
+ const struct ethosn_core_t *core = &(dev->cores[core_idx]);
+
+ if (core->addr == core_addr) {
+ *dev_match = dev;
+ *core_match = core;
+ return true;
+ }
+ }
+ }
+
+ WARN("ETHOSN: Unknown core address given to SMC call.\n");
+ return false;
+}
+
+#if ETHOSN_NPU_TZMP1
+static uint32_t ethosn_core_read_arch_version(uintptr_t core_addr)
+{
+ uint32_t npu_id = mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr,
+ SEC_NPU_ID_REG));
+
+ return (npu_id >> SEC_NPU_ID_ARCH_VER_SHIFT);
+}
+
+static void ethosn_configure_stream_nsaid(const struct ethosn_core_t *core,
+ bool is_protected)
+{
+ size_t i;
+ uint32_t streams[9] = {[0 ... 8] = ETHOSN_NPU_NS_RO_DATA_NSAID};
+
+ streams[FIRMWARE_STREAM_INDEX] = ETHOSN_NPU_PROT_FW_NSAID;
+ streams[PLE_STREAM_INDEX] = ETHOSN_NPU_PROT_FW_NSAID;
+
+ streams[WORKING_STREAM_INDEX] = ETHOSN_NPU_NS_RW_DATA_NSAID;
+
+ if (is_protected) {
+ streams[INPUT_STREAM_INDEX] = ETHOSN_NPU_PROT_RO_DATA_NSAID;
+ streams[INTERMEDIATE_STREAM_INDEX] =
+ ETHOSN_NPU_PROT_RW_DATA_NSAID;
+ streams[OUTPUT_STREAM_INDEX] = ETHOSN_NPU_PROT_RW_DATA_NSAID;
+ } else {
+ streams[INPUT_STREAM_INDEX] = ETHOSN_NPU_NS_RO_DATA_NSAID;
+ streams[INTERMEDIATE_STREAM_INDEX] =
+ ETHOSN_NPU_NS_RW_DATA_NSAID;
+ streams[OUTPUT_STREAM_INDEX] = ETHOSN_NPU_NS_RW_DATA_NSAID;
+ }
+
+ for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
+ const uintptr_t reg_addr = SEC_NSAID_REG_BASE +
+ (SEC_NSAID_OFFSET * i);
+ mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
+ streams[i]);
+ }
+}
+
+static void ethosn_configure_vector_table(uintptr_t core_addr)
+{
+ mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG),
+ FW_INITVTOR_ADDR(big_fw));
+}
+
+#endif /* ETHOSN_NPU_TZMP1 */
+
+static void ethosn_configure_events(uintptr_t core_addr)
+{
+ mmio_write_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL1_REG), SEC_SYSCTRL1_VAL);
+}
+
+static bool ethosn_configure_aux_features(const struct ethosn_device_t *device,
+ uintptr_t core_addr,
+ uint32_t features)
+{
+ uint32_t val = SEC_AUXCTLR_VAL;
+
+ if (features & ETHOSN_AUX_FEAT_LEVEL_IRQ) {
+ val |= SEC_AUXCTLR_LEVEL_IRQ_VAL;
+ }
+
+ if (features & ETHOSN_AUX_FEAT_STASHING) {
+ /* Stashing can't be used with reserved memory */
+ if (device->has_reserved_memory) {
+ return false;
+ }
+
+ val |= SEC_AUXCTLR_STASHING_VAL;
+ }
+
+ mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_AUXCTLR_REG), val);
+
+ return true;
+}
+
+static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
+ const struct ethosn_core_t *core,
+ uint32_t asset_alloc_idx)
+{
+ const struct ethosn_main_allocator_t *main_alloc =
+ &(core->main_allocator);
+ const struct ethosn_asset_allocator_t *asset_alloc =
+ &(device->asset_allocators[asset_alloc_idx]);
+ const uint32_t streams[9] = {
+ main_alloc->firmware.stream_id,
+ main_alloc->working_data.stream_id,
+ asset_alloc->command_stream.stream_id,
+ 0U, /* Not used*/
+ main_alloc->firmware.stream_id,
+ asset_alloc->weight_data.stream_id,
+ asset_alloc->buffer_data.stream_id,
+ asset_alloc->intermediate_data.stream_id,
+ asset_alloc->buffer_data.stream_id
+ };
+ size_t i;
+
+ for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
+ const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
+ (SEC_MMUSID_OFFSET * i);
+ mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
+ streams[i]);
+ }
+}
+
+static void ethosn_configure_stream_addr_extends(const struct ethosn_device_t *device,
+ uintptr_t core_addr)
+{
+ uint32_t addr_extends[3] = { 0 };
+ size_t i;
+
+ if (device->has_reserved_memory) {
+ const uint32_t addr = TO_EXTEND_ADDR(device->reserved_memory_addr);
+
+ addr_extends[0] = addr;
+ addr_extends[1] = addr;
+ addr_extends[2] = addr;
+ } else {
+ addr_extends[0] = TO_EXTEND_ADDR(ETHOSN_FW_VA_BASE);
+ addr_extends[1] = TO_EXTEND_ADDR(ETHOSN_WORKING_DATA_VA_BASE);
+ addr_extends[2] = TO_EXTEND_ADDR(ETHOSN_COMMAND_STREAM_VA_BASE);
+ }
+
+ for (i = 0U; i < ARRAY_SIZE(addr_extends); ++i) {
+ const uintptr_t reg_addr = SEC_ADDR_EXT_REG_BASE +
+ (SEC_ADDR_EXT_OFFSET * i);
+ mmio_write_32(ETHOSN_CORE_SEC_REG(core_addr, reg_addr),
+ addr_extends[i]);
+ }
+}
+
+static void ethosn_configure_stream_attr_ctlr(uintptr_t core_addr)
+{
+ size_t i;
+
+ for (i = 0U; i < SEC_ATTR_CTLR_NUM; ++i) {
+ const uintptr_t reg_addr = SEC_ATTR_CTLR_REG_BASE +
+ (SEC_ATTR_CTLR_OFFSET * i);
+ mmio_write_32(ETHOSN_CORE_SEC_REG(core_addr, reg_addr),
+ SEC_ATTR_CTLR_VAL);
+ }
+}
+
static void ethosn_delegate_to_ns(uintptr_t core_addr)
{
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
@@ -59,16 +294,13 @@ static void ethosn_delegate_to_ns(uintptr_t core_addr)
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
SEC_DEL_VAL);
- mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_MMUSID_REG),
- SEC_DEL_MMUSID_VAL);
-
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
SEC_DEL_ADDR_EXT_VAL);
}
-static int ethosn_is_sec(void)
+static int ethosn_is_sec(uintptr_t core_addr)
{
- if ((mmio_read_32(ETHOSN_CORE_SEC_REG(ETHOSN_CORE_ADDR(0), SEC_DEL_REG))
+ if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
& SEC_DEL_EXCC_MASK) != 0U) {
return 0;
}
@@ -76,13 +308,22 @@ static int ethosn_is_sec(void)
return 1;
}
-static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
+static int ethosn_core_is_sleeping(uintptr_t core_addr)
+{
+ const uintptr_t sysctrl0_reg =
+ ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
+ const uint32_t sleeping_mask = SEC_SYSCTRL0_SLEEPING;
+
+ return ((mmio_read_32(sysctrl0_reg) & sleeping_mask) == sleeping_mask);
+}
+
+static bool ethosn_core_reset(uintptr_t core_addr, bool hard_reset)
{
unsigned int timeout;
const uintptr_t sysctrl0_reg =
ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
- const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
- : SEC_SYSCTRL0_SOFT_RESET;
+ const uint32_t reset_val = hard_reset ? SEC_SYSCTRL0_HARD_RESET :
+ SEC_SYSCTRL0_SOFT_RESET;
mmio_write_32(sysctrl0_reg, reset_val);
@@ -100,8 +341,177 @@ static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
return timeout < ETHOSN_RESET_TIMEOUT_US;
}
+static int ethosn_core_boot_fw(uintptr_t core_addr)
+{
+#if ETHOSN_NPU_TZMP1
+ const uintptr_t sysctrl0_reg = ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
+ const uint32_t sysctrl0_val = mmio_read_32(sysctrl0_reg);
+ const bool waiting = (sysctrl0_val & SEC_SYSCTRL0_CPU_WAIT);
+
+ if (!waiting) {
+ WARN("ETHOSN: Firmware is already running.\n");
+ return ETHOSN_INVALID_STATE;
+ }
+
+ if (SYSCTRL0_INITVTOR_ADDR(sysctrl0_val) != FW_INITVTOR_ADDR(big_fw)) {
+ WARN("ETHOSN: Unknown vector table won't boot firmware.\n");
+ return ETHOSN_INVALID_CONFIGURATION;
+ }
+
+ mmio_clrbits_32(sysctrl0_reg, SEC_SYSCTRL0_CPU_WAIT);
+
+ return ETHOSN_SUCCESS;
+#else
+ return ETHOSN_NOT_SUPPORTED;
+#endif /* ETHOSN_NPU_TZMP1 */
+}
+
+static int ethosn_core_full_reset(const struct ethosn_device_t *device,
+ const struct ethosn_core_t *core,
+ bool hard_reset,
+ u_register_t asset_alloc_idx,
+ u_register_t is_protected,
+ u_register_t aux_features)
+{
+ if (!device->has_reserved_memory &&
+ asset_alloc_idx >= device->num_allocators) {
+ WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
+ return ETHOSN_UNKNOWN_ALLOCATOR_IDX;
+ }
+
+ if (!ethosn_core_reset(core->addr, hard_reset)) {
+ return ETHOSN_FAILURE;
+ }
+
+ if (!ethosn_configure_aux_features(device, core->addr, aux_features)) {
+ return ETHOSN_INVALID_CONFIGURATION;
+ }
+
+ ethosn_configure_events(core->addr);
+
+ if (!device->has_reserved_memory) {
+ ethosn_configure_smmu_streams(device, core, asset_alloc_idx);
+
+#if ETHOSN_NPU_TZMP1
+ ethosn_configure_stream_nsaid(core, is_protected);
+#endif /* ETHOSN_NPU_TZMP1 */
+ }
+
+ ethosn_configure_stream_addr_extends(device, core->addr);
+ ethosn_configure_stream_attr_ctlr(core->addr);
+
+#if ETHOSN_NPU_TZMP1
+ ethosn_configure_vector_table(core->addr);
+#endif /* ETHOSN_NPU_TZMP1 */
+
+ ethosn_delegate_to_ns(core->addr);
+
+ return ETHOSN_SUCCESS;
+}
+
+static uintptr_t ethosn_smc_core_reset_handler(const struct ethosn_device_t *device,
+ const struct ethosn_core_t *core,
+ bool hard_reset,
+ u_register_t asset_alloc_idx,
+ u_register_t reset_type,
+ u_register_t is_protected,
+ u_register_t aux_features,
+ void *handle)
+{
+ int ret;
+
+ switch (reset_type) {
+ case ETHOSN_RESET_TYPE_FULL:
+ ret = ethosn_core_full_reset(device, core, hard_reset,
+ asset_alloc_idx, is_protected,
+ aux_features);
+ break;
+ case ETHOSN_RESET_TYPE_HALT:
+ ret = ethosn_core_reset(core->addr, hard_reset) ? ETHOSN_SUCCESS : ETHOSN_FAILURE;
+ break;
+ default:
+ WARN("ETHOSN: Invalid reset type given to SMC call.\n");
+ ret = ETHOSN_INVALID_PARAMETER;
+ break;
+ }
+
+ SMC_RET1(handle, ret);
+}
+
+static uintptr_t ethosn_smc_core_handler(uint32_t fid,
+ u_register_t core_addr,
+ u_register_t asset_alloc_idx,
+ u_register_t reset_type,
+ u_register_t is_protected,
+ u_register_t aux_features,
+ void *handle)
+{
+ bool hard_reset = false;
+ const struct ethosn_device_t *device = NULL;
+ const struct ethosn_core_t *core = NULL;
+
+ if (!ethosn_get_device_and_core(core_addr, &device, &core)) {
+ SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
+ }
+
+ switch (fid) {
+ case ETHOSN_FNUM_IS_SEC:
+ SMC_RET1(handle, ethosn_is_sec(core->addr));
+ case ETHOSN_FNUM_IS_SLEEPING:
+ SMC_RET1(handle, ethosn_core_is_sleeping(core->addr));
+ case ETHOSN_FNUM_HARD_RESET:
+ hard_reset = true;
+ /* Fallthrough */
+ case ETHOSN_FNUM_SOFT_RESET:
+ return ethosn_smc_core_reset_handler(device, core,
+ hard_reset,
+ asset_alloc_idx,
+ reset_type,
+ is_protected,
+ aux_features,
+ handle);
+ case ETHOSN_FNUM_BOOT_FW:
+ SMC_RET1(handle, ethosn_core_boot_fw(core->addr));
+ default:
+ WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+static uintptr_t ethosn_smc_fw_prop_handler(u_register_t fw_property,
+ void *handle)
+{
+#if ETHOSN_NPU_TZMP1
+ switch (fw_property) {
+ case ETHOSN_FW_PROP_VERSION:
+ SMC_RET4(handle, ETHOSN_SUCCESS,
+ big_fw->fw_ver_major,
+ big_fw->fw_ver_minor,
+ big_fw->fw_ver_patch);
+ case ETHOSN_FW_PROP_MEM_INFO:
+ SMC_RET3(handle, ETHOSN_SUCCESS,
+ ((void *)big_fw) + big_fw->offset,
+ big_fw->size);
+ case ETHOSN_FW_PROP_OFFSETS:
+ SMC_RET3(handle, ETHOSN_SUCCESS,
+ big_fw->ple_offset,
+ big_fw->unpriv_stack_offset);
+ case ETHOSN_FW_PROP_VA_MAP:
+ SMC_RET4(handle, ETHOSN_SUCCESS,
+ ETHOSN_FW_VA_BASE,
+ ETHOSN_WORKING_DATA_VA_BASE,
+ ETHOSN_COMMAND_STREAM_VA_BASE);
+ default:
+ WARN("ETHOSN: Unknown firmware property\n");
+ SMC_RET1(handle, ETHOSN_INVALID_PARAMETER);
+ }
+#else
+ SMC_RET1(handle, ETHOSN_NOT_SUPPORTED);
+#endif /* ETHOSN_NPU_TZMP1 */
+}
+
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
- u_register_t core_idx,
+ u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
@@ -109,8 +519,7 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
void *handle,
u_register_t flags)
{
- uintptr_t core_addr;
- int hard_reset = 0;
+ const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
/* Only SiP fast calls are expected */
if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
@@ -120,45 +529,69 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
/* Truncate parameters to 32-bits for SMC32 */
if (GET_SMC_CC(smc_fid) == SMC_32) {
- core_idx &= 0xFFFFFFFF;
+ x1 &= 0xFFFFFFFF;
x2 &= 0xFFFFFFFF;
x3 &= 0xFFFFFFFF;
x4 &= 0xFFFFFFFF;
}
- if (!is_ethosn_fid(smc_fid)) {
+ if (!is_ethosn_fid(smc_fid) || (fid > ETHOSN_FNUM_BOOT_FW)) {
+ WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
}
- if (ETHOSN_STATUS == ETHOSN_STATUS_DISABLED) {
- WARN("ETHOSN: Arm Ethos-N NPU not available\n");
- SMC_RET1(handle, ETHOSN_NOT_SUPPORTED);
- }
-
- switch (smc_fid & FUNCID_NUM_MASK) {
+ switch (fid) {
case ETHOSN_FNUM_VERSION:
SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
- case ETHOSN_FNUM_IS_SEC:
- SMC_RET1(handle, ethosn_is_sec());
- case ETHOSN_FNUM_HARD_RESET:
- hard_reset = 1;
- /* Fallthrough */
- case ETHOSN_FNUM_SOFT_RESET:
- if (core_idx >= ETHOSN_NUM_CORES) {
- WARN("ETHOSN: core index out of range\n");
- SMC_RET1(handle, ETHOSN_CORE_IDX_OUT_OF_RANGE);
- }
+ case ETHOSN_FNUM_GET_FW_PROP:
+ return ethosn_smc_fw_prop_handler(x1, handle);
+ }
- core_addr = ETHOSN_CORE_ADDR(core_idx);
+ return ethosn_smc_core_handler(fid, x1, x2, x3, x4,
+ SMC_GET_GP(handle, CTX_GPREG_X5),
+ handle);
+}
- if (!ethosn_reset(core_addr, hard_reset)) {
- SMC_RET1(handle, ETHOSN_FAILURE);
- }
+int ethosn_smc_setup(void)
+{
+#if ETHOSN_NPU_TZMP1
+ struct ethosn_device_t *dev;
+ uint32_t arch_ver;
+#endif /* ETHOSN_NPU_TZMP1 */
+
+ if (ETHOSN_NUM_DEVICES == 0U) {
+ ERROR("ETHOSN: No NPU found\n");
+ return ETHOSN_FAILURE;
+ }
- ethosn_delegate_to_ns(core_addr);
+#if ETHOSN_NPU_TZMP1
- SMC_RET1(handle, ETHOSN_SUCCESS);
- default:
- SMC_RET1(handle, SMC_UNK);
+ /* Only one NPU core is supported in the TZMP1 setup */
+ if ((ETHOSN_NUM_DEVICES != 1U) ||
+ (ETHOSN_GET_DEVICE(0U)->num_cores != 1U)) {
+ ERROR("ETHOSN: TZMP1 doesn't support multiple NPU cores\n");
+ return ETHOSN_FAILURE;
}
+
+ dev = ETHOSN_GET_DEVICE(0U);
+ if (dev->has_reserved_memory) {
+ ERROR("ETHOSN: TZMP1 doesn't support using reserved memory\n");
+ return ETHOSN_FAILURE;
+ }
+
+ arch_ver = ethosn_core_read_arch_version(dev->cores[0U].addr);
+ big_fw = (struct ethosn_big_fw *)ETHOSN_NPU_FW_IMAGE_BASE;
+
+ if (!ethosn_big_fw_verify_header(big_fw, arch_ver)) {
+ return ETHOSN_FAILURE;
+ }
+
+ NOTICE("ETHOSN: TZMP1 setup succeeded with firmware version %u.%u.%u\n",
+ big_fw->fw_ver_major, big_fw->fw_ver_minor,
+ big_fw->fw_ver_patch);
+#else
+ NOTICE("ETHOSN: Setup succeeded\n");
+#endif /* ETHOSN_NPU_TZMP1 */
+
+ return 0;
}
diff --git a/drivers/arm/fvp/fvp_pwrc.c b/drivers/arm/fvp/fvp_pwrc.c
index 75a2b66c5b..fb77f77c72 100644
--- a/drivers/arm/fvp/fvp_pwrc.c
+++ b/drivers/arm/fvp/fvp_pwrc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,22 +10,39 @@
#include <plat/arm/common/plat_arm.h>
#include <platform_def.h>
+#define FVP_PWRC_ID_MASK U(0x00FFFFFF)
+
/*
* TODO: Someday there will be a generic power controller api. At the moment
* each platform has its own pwrc so just exporting functions is fine.
*/
ARM_INSTANTIATE_LOCK;
+/*
+ * Core ID field is 24 bits wide and extracted from MPIDR.
+ * Bits[23:16] represent Affinity Level 2
+ * Bits[15:8] represent Affinity Level 1
+ * Bits[7:0] represent Affinity Level 0
+ */
+static unsigned int fvp_pwrc_core_id(u_register_t mpidr)
+{
+ return (unsigned int)(mpidr & FVP_PWRC_ID_MASK);
+}
+
unsigned int fvp_pwrc_get_cpu_wkr(u_register_t mpidr)
{
- return PSYSR_WK(fvp_pwrc_read_psysr(mpidr));
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
+ return PSYSR_WK(fvp_pwrc_read_psysr(id));
}
unsigned int fvp_pwrc_read_psysr(u_register_t mpidr)
{
unsigned int rc;
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
arm_lock_get();
- mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr);
+ mmio_write_32(PWRC_BASE + PSYSR_OFF, id);
rc = mmio_read_32(PWRC_BASE + PSYSR_OFF);
arm_lock_release();
return rc;
@@ -33,38 +50,47 @@ unsigned int fvp_pwrc_read_psysr(u_register_t mpidr)
void fvp_pwrc_write_pponr(u_register_t mpidr)
{
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
arm_lock_get();
- mmio_write_32(PWRC_BASE + PPONR_OFF, (unsigned int) mpidr);
+ mmio_write_32(PWRC_BASE + PPONR_OFF, id);
arm_lock_release();
}
void fvp_pwrc_write_ppoffr(u_register_t mpidr)
{
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
arm_lock_get();
- mmio_write_32(PWRC_BASE + PPOFFR_OFF, (unsigned int) mpidr);
+ mmio_write_32(PWRC_BASE + PPOFFR_OFF, id);
arm_lock_release();
}
void fvp_pwrc_set_wen(u_register_t mpidr)
{
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
arm_lock_get();
mmio_write_32(PWRC_BASE + PWKUPR_OFF,
- (unsigned int) (PWKUPR_WEN | mpidr));
+ (unsigned int) (PWKUPR_WEN | id));
arm_lock_release();
}
void fvp_pwrc_clr_wen(u_register_t mpidr)
{
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
arm_lock_get();
- mmio_write_32(PWRC_BASE + PWKUPR_OFF,
- (unsigned int) mpidr);
+ mmio_write_32(PWRC_BASE + PWKUPR_OFF, id);
arm_lock_release();
}
void fvp_pwrc_write_pcoffr(u_register_t mpidr)
{
+ unsigned int id = fvp_pwrc_core_id(mpidr);
+
arm_lock_get();
- mmio_write_32(PWRC_BASE + PCOFFR_OFF, (unsigned int) mpidr);
+ mmio_write_32(PWRC_BASE + PCOFFR_OFF, id);
arm_lock_release();
}
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
index 939d097188..696bede3c5 100644
--- a/drivers/arm/gic/v2/gicv2_main.c
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
+ * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -251,7 +252,7 @@ void gicv2_end_of_interrupt(unsigned int id)
* Ensure the write to peripheral registers are *complete* before the write
* to GIC_EOIR.
*
- * Note: The completion gurantee depends on various factors of system design
+ * Note: The completion guarantee depends on various factors of system design
* and the barrier is the best core can do by which execution of further
* instructions waits till the barrier is alive.
*/
@@ -389,7 +390,7 @@ void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
* This function assigns group for the interrupt identified by id. The group can
* be any of GICV2_INTR_GROUP*
******************************************************************************/
-void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
+void gicv2_set_interrupt_group(unsigned int id, unsigned int group)
{
assert(driver_data != NULL);
assert(driver_data->gicd_base != 0U);
@@ -397,7 +398,7 @@ void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
/* Serialize read-modify-write to Distributor registers */
spin_lock(&gic_lock);
- switch (type) {
+ switch (group) {
case GICV2_INTR_GROUP1:
gicd_set_igroupr(driver_data->gicd_base, id);
break;
@@ -417,7 +418,7 @@ void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
* The proc_num parameter must be the linear index of the target PE in the
* system.
******************************************************************************/
-void gicv2_raise_sgi(int sgi_num, int proc_num)
+void gicv2_raise_sgi(int sgi_num, bool ns, int proc_num)
{
unsigned int sgir_val, target;
@@ -437,7 +438,7 @@ void gicv2_raise_sgi(int sgi_num, int proc_num)
target = driver_data->target_masks[proc_num];
assert(target != 0U);
- sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num);
+ sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, ns, sgi_num);
/*
* Ensure that any shared variable updates depending on out of band
diff --git a/drivers/arm/gic/v3/gic-x00.c b/drivers/arm/gic/v3/gic-x00.c
index 6e106babfb..83ef32f056 100644
--- a/drivers/arm/gic/v3/gic-x00.c
+++ b/drivers/arm/gic/v3/gic-x00.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -16,15 +16,14 @@
#include <assert.h>
#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/arm_gicv3_common.h>
#include <drivers/arm/gicv3.h>
#include "gicv3_private.h"
/* GIC-600 specific register offsets */
#define GICR_PWRR 0x24U
-#define IIDR_MODEL_ARM_GIC_600 U(0x0200043b)
-#define IIDR_MODEL_ARM_GIC_600AE U(0x0300043b)
-#define IIDR_MODEL_ARM_GIC_CLAYTON U(0x0400043b)
/* GICR_PWRR fields */
#define PWRR_RDPD_SHIFT 0
@@ -44,9 +43,11 @@
#define PWRR_ON (0U << PWRR_RDPD_SHIFT)
#define PWRR_OFF (1U << PWRR_RDPD_SHIFT)
+static bool gic600_errata_wa_2384374 __unused;
+
#if GICV3_SUPPORT_GIC600
-/* GIC-600/Clayton specific accessor functions */
+/* GIC-600/700 specific accessor functions */
static void gicr_write_pwrr(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICR_PWRR, val);
@@ -123,12 +124,12 @@ static bool gicv3_redists_need_power_mgmt(uintptr_t gicr_base)
uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR);
/*
- * The Arm GIC-600 and GIC-Clayton models have their redistributors
+ * The Arm GIC-600 and GIC-700 models have their redistributors
* powered down at reset.
*/
return (((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600AE) ||
- ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_CLAYTON));
+ ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700));
}
#endif /* GICV3_SUPPORT_GIC600 */
@@ -172,3 +173,60 @@ void gicv3_rdistif_on(unsigned int proc_num)
}
#endif
}
+
+#if GIC600_ERRATA_WA_2384374
+/*******************************************************************************
+ * Apply part 2 of workaround for errata-2384374 as per SDEN:
+ * https://developer.arm.com/documentation/sden892601/latest/
+ ******************************************************************************/
+void gicv3_apply_errata_wa_2384374(uintptr_t gicr_base)
+{
+ if (gic600_errata_wa_2384374) {
+ uint32_t gicr_ctlr_val = gicr_read_ctlr(gicr_base);
+
+ gicr_write_ctlr(gicr_base, gicr_ctlr_val |
+ (GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
+ GICR_CTLR_DPG1S_BIT));
+ gicr_write_ctlr(gicr_base, gicr_ctlr_val &
+ ~(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
+ GICR_CTLR_DPG1S_BIT));
+ }
+}
+#endif /* GIC600_ERRATA_WA_2384374 */
+
+void gicv3_check_erratas_applies(uintptr_t gicd_base)
+{
+ unsigned int gic_prod_id;
+ uint8_t gic_rev;
+
+ assert(gicd_base != 0UL);
+
+ gicv3_get_component_prodid_rev(gicd_base, &gic_prod_id, &gic_rev);
+
+ /*
+ * This workaround applicable only to GIC600 and GIC600AE products with
+ * revision less than r1p6 and r0p2 respectively.
+ * As per GIC600/GIC600AE specification -
+ * r1p6 = 0x17 => GICD_IIDR[19:12]
+ * r0p2 = 0x04 => GICD_IIDR[19:12]
+ */
+ if ((gic_prod_id == GIC_PRODUCT_ID_GIC600) ||
+ (gic_prod_id == GIC_PRODUCT_ID_GIC600AE)) {
+ if (((gic_prod_id == GIC_PRODUCT_ID_GIC600) &&
+ (gic_rev <= GIC_REV(GIC_VARIANT_R1, GIC_REV_P6))) ||
+ ((gic_prod_id == GIC_PRODUCT_ID_GIC600AE) &&
+ (gic_rev <= GIC_REV(GIC_VARIANT_R0, GIC_REV_P2)))) {
+#if GIC600_ERRATA_WA_2384374
+ gic600_errata_wa_2384374 = true;
+ VERBOSE("%s applies\n",
+ "GIC600/GIC600AE errata workaround 2384374");
+#else
+ WARN("%s missing\n",
+ "GIC600/GIC600AE errata workaround 2384374");
+#endif /* GIC600_ERRATA_WA_2384374 */
+ } else {
+ VERBOSE("%s not applies\n",
+ "GIC600/GIC600AE errata workaround 2384374");
+ }
+ }
+}
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
index ca7c43bf9c..5e44aa95c1 100644
--- a/drivers/arm/gic/v3/gic600_multichip.c
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,13 +12,35 @@
#include <assert.h>
#include <common/debug.h>
+#include <drivers/arm/arm_gicv3_common.h>
#include <drivers/arm/gic600_multichip.h>
#include <drivers/arm/gicv3.h>
#include "../common/gic_common_private.h"
#include "gic600_multichip_private.h"
-#warning "GIC-600 Multichip driver is currently experimental and the API may change in future."
+static struct gic600_multichip_data *plat_gic_multichip_data;
+
+/*******************************************************************************
+ * Retrieve the address of the chip owner for a given SPI ID
+ ******************************************************************************/
+uintptr_t gic600_multichip_gicd_base_for_spi(uint32_t spi_id)
+{
+ unsigned int i;
+
+ /* Find the multichip instance */
+ for (i = 0U; i < GIC600_MAX_MULTICHIP; i++) {
+ if ((spi_id <= plat_gic_multichip_data->spi_ids[i].spi_id_max) &&
+ (spi_id >= plat_gic_multichip_data->spi_ids[i].spi_id_min)) {
+ break;
+ }
+ }
+
+ /* Ensure that plat_gic_multichip_data contains valid values */
+ assert(i < GIC600_MAX_MULTICHIP);
+
+ return plat_gic_multichip_data->spi_ids[i].gicd_base;
+}
/*******************************************************************************
* GIC-600 multichip operation related helper functions
@@ -27,7 +50,7 @@ static void gicd_dchipr_wait_for_power_update_progress(uintptr_t base)
unsigned int retry = GICD_PUP_UPDATE_RETRIES;
while ((read_gicd_dchipr(base) & GICD_DCHIPR_PUP_BIT) != 0U) {
- if (retry-- == 0) {
+ if (retry-- == 0U) {
ERROR("GIC-600 connection to Routing Table Owner timed "
"out\n");
panic();
@@ -52,7 +75,7 @@ static void set_gicd_dchipr_rt_owner(uintptr_t base, unsigned int rt_owner)
panic();
}
- /* Poll till PUP is zero before intiating write */
+ /* Poll till PUP is zero before initiating write */
gicd_dchipr_wait_for_power_update_progress(base);
write_gicd_dchipr(base, read_gicd_dchipr(base) |
@@ -73,6 +96,7 @@ static void set_gicd_chipr_n(uintptr_t base,
unsigned int spi_id_max)
{
unsigned int spi_block_min, spi_blocks;
+ unsigned int gicd_iidr_val = gicd_read_iidr(base);
uint64_t chipr_n_val;
/*
@@ -97,11 +121,39 @@ static void set_gicd_chipr_n(uintptr_t base,
spi_id_max = GIC600_SPI_ID_MIN;
}
- spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
- spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
+ switch ((gicd_iidr_val & IIDR_MODEL_MASK)) {
+ case IIDR_MODEL_ARM_GIC_600:
+ spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
+ spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
+
+ chipr_n_val = GICD_CHIPR_VALUE_GIC_600(chip_addr,
+ spi_block_min,
+ spi_blocks);
+ break;
+ case IIDR_MODEL_ARM_GIC_700:
+ /* Calculate the SPI_ID_MIN value for ESPI */
+ if (spi_id_min >= GIC700_ESPI_ID_MIN) {
+ spi_block_min = ESPI_BLOCK_MIN_VALUE(spi_id_min);
+ spi_block_min += SPI_BLOCKS_VALUE(GIC700_SPI_ID_MIN,
+ GIC700_SPI_ID_MAX);
+ } else {
+ spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
+ }
+
+ /* Calculate the total number of blocks */
+ spi_blocks = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
- chipr_n_val = (GICD_CHIPR_VALUE(chip_addr, spi_block_min, spi_blocks)) |
- GICD_CHIPRx_SOCKET_STATE;
+ chipr_n_val = GICD_CHIPR_VALUE_GIC_700(chip_addr,
+ spi_block_min,
+ spi_blocks);
+ break;
+ default:
+ ERROR("Unsupported GIC model 0x%x for multichip setup.\n",
+ gicd_iidr_val);
+ panic();
+ break;
+ }
+ chipr_n_val |= GICD_CHIPRx_SOCKET_STATE;
/*
* Wait for DCHIPR.PUP to be zero before commencing writes to
@@ -157,15 +209,15 @@ static void gic600_multichip_validate_data(
panic();
}
- for (i = 0; i < multichip_data->chip_count; i++) {
- spi_id_min = multichip_data->spi_ids[i][SPI_MIN_INDEX];
- spi_id_max = multichip_data->spi_ids[i][SPI_MAX_INDEX];
+ for (i = 0U; i < multichip_data->chip_count; i++) {
+ spi_id_min = multichip_data->spi_ids[i].spi_id_min;
+ spi_id_max = multichip_data->spi_ids[i].spi_id_max;
- if ((spi_id_min != 0) || (spi_id_max != 0)) {
+ if ((spi_id_min != 0U) || (spi_id_max != 0U)) {
/* SPI IDs range check */
if (!(spi_id_min >= GIC600_SPI_ID_MIN) ||
- !(spi_id_max < GIC600_SPI_ID_MAX) ||
+ !(spi_id_max <= GIC600_SPI_ID_MAX) ||
!(spi_id_min <= spi_id_max) ||
!((spi_id_max - spi_id_min + 1) % 32 == 0)) {
ERROR("Invalid SPI IDs {%u, %u} passed for "
@@ -186,15 +238,104 @@ static void gic600_multichip_validate_data(
}
/*******************************************************************************
- * Intialize GIC-600 Multichip operation.
+ * Validates the GIC-700 Multichip data structure passed by the platform.
+ ******************************************************************************/
+static void gic700_multichip_validate_data(
+ struct gic600_multichip_data *multichip_data)
+{
+ unsigned int i, spi_id_min, spi_id_max, blocks_of_32;
+ unsigned int multichip_spi_blocks = 0U, multichip_espi_blocks = 0U;
+
+ assert(multichip_data != NULL);
+
+ if (multichip_data->chip_count > GIC600_MAX_MULTICHIP) {
+ ERROR("GIC-700 Multichip count (%u) should not exceed %u\n",
+ multichip_data->chip_count, GIC600_MAX_MULTICHIP);
+ panic();
+ }
+
+ for (i = 0U; i < multichip_data->chip_count; i++) {
+ spi_id_min = multichip_data->spi_ids[i].spi_id_min;
+ spi_id_max = multichip_data->spi_ids[i].spi_id_max;
+
+ if ((spi_id_min == 0U) || (spi_id_max == 0U)) {
+ continue;
+ }
+
+ /* MIN SPI ID check */
+ if ((spi_id_min < GIC700_SPI_ID_MIN) ||
+ ((spi_id_min >= GIC700_SPI_ID_MAX) &&
+ (spi_id_min < GIC700_ESPI_ID_MIN))) {
+ ERROR("Invalid MIN SPI ID {%u} passed for "
+ "Chip %u\n", spi_id_min, i);
+ panic();
+ }
+
+ if ((spi_id_min > spi_id_max) ||
+ ((spi_id_max - spi_id_min + 1) % 32 != 0)) {
+ ERROR("Unaligned SPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+ }
+
+ /* ESPI IDs range check */
+ if ((spi_id_min >= GIC700_ESPI_ID_MIN) &&
+ (spi_id_max > GIC700_ESPI_ID_MAX)) {
+ ERROR("Invalid ESPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+
+ }
+
+ /* SPI IDs range check */
+ if (((spi_id_min < GIC700_SPI_ID_MAX) &&
+ (spi_id_max > GIC700_SPI_ID_MAX))) {
+ ERROR("Invalid SPI IDs {%u, %u} passed for "
+ "Chip %u\n", spi_id_min,
+ spi_id_max, i);
+ panic();
+ }
+
+ /* SPI IDs overlap check */
+ if (spi_id_max < GIC700_SPI_ID_MAX) {
+ blocks_of_32 = BLOCKS_OF_32(spi_id_min, spi_id_max);
+ if ((multichip_spi_blocks & blocks_of_32) != 0) {
+ ERROR("SPI IDs of Chip %u overlapping\n", i);
+ panic();
+ }
+ multichip_spi_blocks |= blocks_of_32;
+ }
+
+ /* ESPI IDs overlap check */
+ if (spi_id_max > GIC700_ESPI_ID_MIN) {
+ blocks_of_32 = BLOCKS_OF_32(spi_id_min - GIC700_ESPI_ID_MIN,
+ spi_id_max - GIC700_ESPI_ID_MIN);
+ if ((multichip_espi_blocks & blocks_of_32) != 0) {
+ ERROR("SPI IDs of Chip %u overlapping\n", i);
+ panic();
+ }
+ multichip_espi_blocks |= blocks_of_32;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Initialize GIC-600 and GIC-700 Multichip operation.
******************************************************************************/
void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
{
unsigned int i;
+ uint32_t gicd_iidr_val = gicd_read_iidr(multichip_data->rt_owner_base);
- gic600_multichip_validate_data(multichip_data);
+ if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) {
+ gic600_multichip_validate_data(multichip_data);
+ }
- INFO("GIC-600 Multichip driver is experimental\n");
+ if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700) {
+ gic700_multichip_validate_data(multichip_data);
+ }
/*
* Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
@@ -224,9 +365,9 @@ void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
multichip_data->chip_addrs[multichip_data->rt_owner],
multichip_data->
- spi_ids[multichip_data->rt_owner][SPI_MIN_INDEX],
+ spi_ids[multichip_data->rt_owner].spi_id_min,
multichip_data->
- spi_ids[multichip_data->rt_owner][SPI_MAX_INDEX]);
+ spi_ids[multichip_data->rt_owner].spi_id_max);
for (i = 0; i < multichip_data->chip_count; i++) {
if (i == multichip_data->rt_owner)
@@ -234,7 +375,17 @@ void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
set_gicd_chipr_n(multichip_data->rt_owner_base, i,
multichip_data->chip_addrs[i],
- multichip_data->spi_ids[i][SPI_MIN_INDEX],
- multichip_data->spi_ids[i][SPI_MAX_INDEX]);
+ multichip_data->spi_ids[i].spi_id_min,
+ multichip_data->spi_ids[i].spi_id_max);
}
+
+ plat_gic_multichip_data = multichip_data;
+}
+
+/*******************************************************************************
+ * Allow a way to query the status of the GIC600 multichip driver
+ ******************************************************************************/
+bool gic600_multichip_is_initialized(void)
+{
+ return (plat_gic_multichip_data != NULL);
}
diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h
index fe4134cba9..fd1cb57d2f 100644
--- a/drivers/arm/gic/v3/gic600_multichip_private.h
+++ b/drivers/arm/gic/v3/gic600_multichip_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2023, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -27,17 +27,11 @@
#define GICD_CHIPSR_RTS_SHIFT 4
#define GICD_DCHIPR_RT_OWNER_SHIFT 4
-/*
- * If GIC v4 extension is enabled, then use SPI macros specific to GIC-Clayton.
- * Other shifts and mask remains same between GIC-600 and GIC-Clayton.
- */
-#if GIC_ENABLE_V4_EXTN
-#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT 9
-#define GICD_CHIPRx_SPI_BLOCKS_SHIFT 3
-#else
-#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT 10
-#define GICD_CHIPRx_SPI_BLOCKS_SHIFT 5
-#endif
+/* Other shifts and masks remain the same between GIC-600 and GIC-700. */
+#define GIC_700_SPI_BLOCK_MIN_SHIFT 9
+#define GIC_700_SPI_BLOCKS_SHIFT 3
+#define GIC_600_SPI_BLOCK_MIN_SHIFT 10
+#define GIC_600_SPI_BLOCKS_SHIFT 5
#define GICD_CHIPSR_RTS_STATE_DISCONNECTED U(0)
#define GICD_CHIPSR_RTS_STATE_UPDATING U(1)
@@ -45,30 +39,40 @@
/* SPI interrupt id minimum and maximum range */
#define GIC600_SPI_ID_MIN 32
-#define GIC600_SPI_ID_MAX 960
+#define GIC600_SPI_ID_MAX 991
+
+#define GIC700_SPI_ID_MIN 32
+#define GIC700_SPI_ID_MAX 991
+#define GIC700_ESPI_ID_MIN 4096
+#define GIC700_ESPI_ID_MAX 5119
/* Number of retries for PUP update */
#define GICD_PUP_UPDATE_RETRIES 10000
-#define SPI_MIN_INDEX 0
-#define SPI_MAX_INDEX 1
-
#define SPI_BLOCK_MIN_VALUE(spi_id_min) \
(((spi_id_min) - GIC600_SPI_ID_MIN) / \
GIC600_SPI_ID_MIN)
#define SPI_BLOCKS_VALUE(spi_id_min, spi_id_max) \
(((spi_id_max) - (spi_id_min) + 1) / \
GIC600_SPI_ID_MIN)
-#define GICD_CHIPR_VALUE(chip_addr, spi_block_min, spi_blocks) \
+#define ESPI_BLOCK_MIN_VALUE(spi_id_min) \
+ (((spi_id_min) - GIC700_ESPI_ID_MIN + 1) / \
+ GIC700_SPI_ID_MIN)
+#define GICD_CHIPR_VALUE_GIC_700(chip_addr, spi_block_min, spi_blocks) \
+ (((chip_addr) << GICD_CHIPRx_ADDR_SHIFT) | \
+ ((spi_block_min) << GIC_700_SPI_BLOCK_MIN_SHIFT) | \
+ ((spi_blocks) << GIC_700_SPI_BLOCKS_SHIFT))
+#define GICD_CHIPR_VALUE_GIC_600(chip_addr, spi_block_min, spi_blocks) \
(((chip_addr) << GICD_CHIPRx_ADDR_SHIFT) | \
- ((spi_block_min) << GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT) | \
- ((spi_blocks) << GICD_CHIPRx_SPI_BLOCKS_SHIFT))
+ ((spi_block_min) << GIC_600_SPI_BLOCK_MIN_SHIFT) | \
+ ((spi_blocks) << GIC_600_SPI_BLOCKS_SHIFT))
/*
* Multichip data assertion macros
*/
/* Set bits from 0 to ((spi_id_max + 1) / 32) */
-#define SPI_BLOCKS_TILL_MAX(spi_id_max) ((1 << (((spi_id_max) + 1) >> 5)) - 1)
+#define SPI_BLOCKS_TILL_MAX(spi_id_max) \
+ ((1ULL << (((spi_id_max) + 1) >> 5)) - 1)
/* Set bits from 0 to (spi_id_min / 32) */
#define SPI_BLOCKS_TILL_MIN(spi_id_min) ((1 << ((spi_id_min) >> 5)) - 1)
/* Set bits from (spi_id_min / 32) to ((spi_id_max + 1) / 32) */
diff --git a/drivers/arm/gic/v3/gic600ae_fmu.c b/drivers/arm/gic/v3/gic600ae_fmu.c
new file mode 100644
index 0000000000..0262f48358
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600ae_fmu.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC-600AE Fault Management Unit
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gic600ae_fmu.h>
+#include <drivers/arm/gicv3.h>
+
+/* GIC-600 AE FMU specific register offsets */
+
+/* GIC-600 AE FMU specific macros */
+#define FMU_ERRIDR_NUM U(44)
+#define FMU_ERRIDR_NUM_MASK U(0xFFFF)
+
+/* Safety mechanisms for GICD block */
+static char *gicd_sm_info[] = {
+ "Reserved",
+ "GICD dual lockstep error",
+ "GICD AXI4 slave interface error",
+ "GICD-PPI AXI4-Stream interface error",
+ "GICD-ITS AXI4-Stream interface error",
+ "GICD-SPI-Collator AXI4-Stream interface error",
+ "GICD AXI4 master interface error",
+ "SPI RAM DED error",
+ "SGI RAM DED error",
+ "Reserved",
+ "LPI RAM DED error",
+ "GICD-remote-GICD AXI4-Stream interface error",
+ "GICD Q-Channel interface error",
+ "GICD P-Channel interface error",
+ "SPI RAM address decode error",
+ "SGI RAM address decode error",
+ "Reserved",
+ "LPI RAM address decode error",
+ "FMU dual lockstep error",
+ "FMU ping ACK error",
+ "FMU APB parity error",
+ "GICD-Wake AXI4-Stream interface error",
+ "GICD PageOffset or Chip ID error",
+ "MBIST REQ error",
+ "SPI RAM SEC error",
+ "SGI RAM SEC error",
+ "Reserved",
+ "LPI RAM SEC error",
+ "User custom SM0 error",
+ "User custom SM1 error",
+ "GICD-ITS Monolithic switch error",
+ "GICD-ITS Q-Channel interface error",
+ "GICD-ITS Monolithic interface error",
+ "GICD FMU ClkGate override"
+};
+
+/* Safety mechanisms for PPI block */
+static char *ppi_sm_info[] = {
+ "Reserved",
+ "PPI dual lockstep error",
+ "PPI-GICD AXI4-Stream interface error",
+ "PPI-CPU-IF AXI4-Stream interface error",
+ "PPI Q-Channel interface error",
+ "PPI RAM DED error",
+ "PPI RAM address decode error",
+ "PPI RAM SEC error",
+ "PPI User0 SM",
+ "PPI User1 SM",
+ "MBIST REQ error",
+ "PPI interrupt parity protection error",
+ "PPI FMU ClkGate override"
+};
+
+/* Safety mechanisms for ITS block */
+static char *its_sm_info[] = {
+ "Reserved",
+ "ITS dual lockstep error",
+ "ITS-GICD AXI4-Stream interface error",
+ "ITS AXI4 slave interface error",
+ "ITS AXI4 master interface error",
+ "ITS Q-Channel interface error",
+ "ITS RAM DED error",
+ "ITS RAM address decode error",
+ "Bypass ACE switch error",
+ "ITS RAM SEC error",
+ "ITS User0 SM",
+ "ITS User1 SM",
+ "ITS-GICD Monolithic interface error",
+ "MBIST REQ error",
+ "ITS FMU ClkGate override"
+};
+
+/* Safety mechanisms for SPI Collator block */
+static char *spicol_sm_info[] = {
+ "Reserved",
+ "SPI Collator dual lockstep error",
+ "SPI-Collator-GICD AXI4-Stream interface error",
+ "SPI Collator Q-Channel interface error",
+ "SPI Collator Q-Channel clock error",
+ "SPI interrupt parity error"
+};
+
+/* Safety mechanisms for Wake Request block */
+static char *wkrqst_sm_info[] = {
+ "Reserved",
+ "Wake dual lockstep error",
+ "Wake-GICD AXI4-Stream interface error"
+};
+
+/* Helper function to find detailed information for a specific IERR */
+static char __unused *ras_ierr_to_str(unsigned int blkid, unsigned int ierr)
+{
+ char *str = NULL;
+
+ /* Find the correct record */
+ switch (blkid) {
+ case FMU_BLK_GICD:
+ assert(ierr < ARRAY_SIZE(gicd_sm_info));
+ str = gicd_sm_info[ierr];
+ break;
+
+ case FMU_BLK_SPICOL:
+ assert(ierr < ARRAY_SIZE(spicol_sm_info));
+ str = spicol_sm_info[ierr];
+ break;
+
+ case FMU_BLK_WAKERQ:
+ assert(ierr < ARRAY_SIZE(wkrqst_sm_info));
+ str = wkrqst_sm_info[ierr];
+ break;
+
+ case FMU_BLK_ITS0...FMU_BLK_ITS7:
+ assert(ierr < ARRAY_SIZE(its_sm_info));
+ str = its_sm_info[ierr];
+ break;
+
+ case FMU_BLK_PPI0...FMU_BLK_PPI31:
+ assert(ierr < ARRAY_SIZE(ppi_sm_info));
+ str = ppi_sm_info[ierr];
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return str;
+}
+
+/*
+ * Probe for error in memory-mapped registers containing error records.
+ * Upon detecting an error, set probe data to the index of the record
+ * in error, and return 1; otherwise, return 0.
+ */
+int gic600_fmu_probe(uint64_t base, int *probe_data)
+{
+ uint64_t gsr;
+
+ assert(base != 0UL);
+
+ /*
+ * Read ERR_GSR to find the error record 'M'
+ */
+ gsr = gic_fmu_read_errgsr(base);
+ if (gsr == U(0)) {
+ return 0;
+ }
+
+ /* Return the index of the record in error */
+ if (probe_data != NULL) {
+ *probe_data = (int)__builtin_ctzll(gsr);
+ }
+
+ return 1;
+}
+
+/*
+ * The handler function to read RAS records and find the safety
+ * mechanism with the error.
+ */
+int gic600_fmu_ras_handler(uint64_t base, int probe_data)
+{
+ uint64_t errstatus;
+ unsigned int blkid = (unsigned int)probe_data, ierr, serr;
+
+ assert(base != 0UL);
+
+ /*
+ * FMU_ERRGSR indicates the ID of the GIC
+ * block that faulted.
+ */
+ assert(blkid <= FMU_BLK_PPI31);
+
+ /*
+ * Find more information by reading FMU_ERR<M>STATUS
+ * register
+ */
+ errstatus = gic_fmu_read_errstatus(base, blkid);
+
+ /*
+ * If FMU_ERR<M>STATUS.V is set to 0, no RAS records
+ * need to be scanned.
+ */
+ if ((errstatus & FMU_ERRSTATUS_V_BIT) == U(0)) {
+ return 0;
+ }
+
+ /*
+ * FMU_ERR<M>STATUS.IERR indicates which Safety Mechanism
+ * reported the error.
+ */
+ ierr = (errstatus >> FMU_ERRSTATUS_IERR_SHIFT) &
+ FMU_ERRSTATUS_IERR_MASK;
+
+ /*
+ * FMU_ERR<M>STATUS.SERR indicates architecturally
+ * defined primary error code.
+ */
+ serr = errstatus & FMU_ERRSTATUS_SERR_MASK;
+
+ ERROR("**************************************\n");
+ ERROR("RAS %s Error detected by GIC600 AE FMU\n",
+ ((errstatus & FMU_ERRSTATUS_UE_BIT) != 0U) ?
+ "Uncorrectable" : "Corrected");
+ ERROR("\tStatus = 0x%lx \n", errstatus);
+ ERROR("\tBlock ID = 0x%x\n", blkid);
+ ERROR("\tSafety Mechanism ID = 0x%x (%s)\n", ierr,
+ ras_ierr_to_str(blkid, ierr));
+ ERROR("\tArchitecturally defined primary error code = 0x%x\n",
+ serr);
+ ERROR("**************************************\n");
+
+ /* Clear FMU_ERR<M>STATUS */
+ gic_fmu_write_errstatus(base, probe_data, errstatus);
+
+ return 0;
+}
+
+/*
+ * Initialization sequence for the FMU
+ *
+ * 1. enable error detection for error records that are passed in the blk_present_mask
+ * 2. enable MBIST REQ and FMU Clk Gate override safety mechanisms for error records
+ * that are present on the platform
+ *
+ * The platforms are expected to pass `errctlr_ce_en` and `errctlr_ue_en`.
+ */
+void gic600_fmu_init(uint64_t base, uint64_t blk_present_mask,
+ bool errctlr_ce_en, bool errctlr_ue_en)
+{
+ unsigned int num_blk = gic_fmu_read_erridr(base) & FMU_ERRIDR_NUM_MASK;
+ uint64_t errctlr;
+ uint32_t smen;
+
+ INFO("GIC600-AE FMU supports %d error records\n", num_blk);
+
+ assert(num_blk == FMU_ERRIDR_NUM);
+
+ /* sanitize block present mask */
+ blk_present_mask &= FMU_BLK_PRESENT_MASK;
+
+ /* Enable error detection for all error records */
+ for (unsigned int i = 0U; i < num_blk; i++) {
+
+ /*
+ * Disable all safety mechanisms for blocks that are not
+ * present and skip the next steps.
+ */
+ if ((blk_present_mask & BIT(i)) == 0U) {
+ gic_fmu_disable_all_sm_blkid(base, i);
+ continue;
+ }
+
+ /* Read the error record control register */
+ errctlr = gic_fmu_read_errctlr(base, i);
+
+ /* Enable error reporting and logging, if it is disabled */
+ if ((errctlr & FMU_ERRCTLR_ED_BIT) == 0U) {
+ errctlr |= FMU_ERRCTLR_ED_BIT;
+ }
+
+ /* Enable client provided ERRCTLR settings */
+ errctlr |= (errctlr_ce_en ? (FMU_ERRCTLR_CI_BIT | FMU_ERRCTLR_CE_EN_BIT) : 0);
+ errctlr |= (errctlr_ue_en ? FMU_ERRCTLR_UI_BIT : 0U);
+
+ gic_fmu_write_errctlr(base, i, errctlr);
+ }
+
+ /*
+ * Enable MBIST REQ error and FMU CLK gate override safety mechanisms for
+ * all blocks
+ *
+ * GICD, SMID 23 and SMID 33
+ * PPI, SMID 10 and SMID 12
+ * ITS, SMID 13 and SMID 14
+ */
+ if ((blk_present_mask & BIT(FMU_BLK_GICD)) != 0U) {
+ smen = (GICD_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+
+ smen = (GICD_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+ }
+
+ for (unsigned int i = FMU_BLK_PPI0; i < FMU_BLK_PPI31; i++) {
+ if ((blk_present_mask & BIT(i)) != 0U) {
+ smen = (PPI_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+
+ smen = (PPI_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+ }
+ }
+
+ for (unsigned int i = FMU_BLK_ITS0; i < FMU_BLK_ITS7; i++) {
+ if ((blk_present_mask & BIT(i)) != 0U) {
+ smen = (ITS_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+
+ smen = (ITS_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
+ (i << FMU_SMEN_BLK_SHIFT) |
+ FMU_SMEN_EN_BIT;
+ gic_fmu_write_smen(base, smen);
+ }
+ }
+}
+
+/*
+ * This function enable the GICD background ping engine. The GICD sends ping
+ * messages to each remote GIC block, and expects a PING_ACK back within the
+ * specified timeout. Pings need to be enabled after programming the timeout
+ * value.
+ */
+void gic600_fmu_enable_ping(uint64_t base, uint64_t blk_present_mask,
+ unsigned int timeout_val, unsigned int interval_diff)
+{
+ /*
+ * Populate the PING Mask to skip a specific block while generating
+ * background ping messages and enable the ping mechanism.
+ */
+ gic_fmu_write_pingmask(base, ~blk_present_mask);
+ gic_fmu_write_pingctlr(base, (interval_diff << FMU_PINGCTLR_INTDIFF_SHIFT) |
+ (timeout_val << FMU_PINGCTLR_TIMEOUTVAL_SHIFT) | FMU_PINGCTLR_EN_BIT);
+}
+
+/* Print the safety mechanism description for a given block */
+void gic600_fmu_print_sm_info(uint64_t base, unsigned int blk, unsigned int smid)
+{
+ if (blk == FMU_BLK_GICD && smid <= FMU_SMID_GICD_MAX) {
+ INFO("GICD, SMID %d: %s\n", smid, gicd_sm_info[smid]);
+ }
+
+ if (blk == FMU_BLK_SPICOL && smid <= FMU_SMID_SPICOL_MAX) {
+ INFO("SPI Collator, SMID %d: %s\n", smid, spicol_sm_info[smid]);
+ }
+
+ if (blk == FMU_BLK_WAKERQ && (smid <= FMU_SMID_WAKERQ_MAX)) {
+ INFO("Wake Request, SMID %d: %s\n", smid, wkrqst_sm_info[smid]);
+ }
+
+ if (((blk >= FMU_BLK_ITS0) && (blk <= FMU_BLK_ITS7)) && (smid <= FMU_SMID_ITS_MAX)) {
+ INFO("ITS, SMID %d: %s\n", smid, its_sm_info[smid]);
+ }
+
+ if (((blk >= FMU_BLK_PPI0) && (blk <= FMU_BLK_PPI31)) && (smid <= FMU_SMID_PPI_MAX)) {
+ INFO("PPI, SMID %d: %s\n", smid, ppi_sm_info[smid]);
+ }
+}
diff --git a/drivers/arm/gic/v3/gic600ae_fmu_helpers.c b/drivers/arm/gic/v3/gic600ae_fmu_helpers.c
new file mode 100644
index 0000000000..09806dcfc5
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600ae_fmu_helpers.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/gic600ae_fmu.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#define GICFMU_IDLE_TIMEOUT_US U(2000000)
+
+/* Macro to write 32-bit FMU registers */
+#define GIC_FMU_WRITE_32(base, reg, val) \
+ do { \
+ /* \
+ * This register receives the unlock key that is required for \
+ * writes to FMU registers to be successful. \
+ */ \
+ mmio_write_32(base + GICFMU_KEY, 0xBE); \
+ /* Perform the actual write */ \
+ mmio_write_32((base) + (reg), (val)); \
+ } while (false)
+
+/* Macro to write 64-bit FMU registers */
+#define GIC_FMU_WRITE_64(base, reg, n, val) \
+ do { \
+ /* \
+ * This register receives the unlock key that is required for \
+ * writes to FMU registers to be successful. \
+ */ \
+ mmio_write_32(base + GICFMU_KEY, 0xBE); \
+ /* \
+ * APB bus is 32-bit wide; so split the 64-bit write into \
+ * two 32-bit writes \
+ */ \
+ mmio_write_32((base) + reg##_LO + (n * 64), (val)); \
+ mmio_write_32((base) + reg##_HI + (n * 64), (val)); \
+ } while (false)
+
+/* Helper function to wait until FMU is ready to accept the next command */
+static void wait_until_fmu_is_idle(uintptr_t base)
+{
+ uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US;
+ uint64_t status;
+
+ /* wait until status is 'busy' */
+ do {
+ status = (gic_fmu_read_status(base) & BIT(0));
+
+ if (timeout_count-- == 0U) {
+ ERROR("GIC600 AE FMU is not responding\n");
+ panic();
+ }
+
+ udelay(1U);
+
+ } while (status == U(0));
+}
+
+#define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \
+ do { \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ /* Actual register write */ \
+ GIC_FMU_WRITE_32(base, reg, val); \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ } while (false)
+
+#define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \
+ do { \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ /* Actual register write */ \
+ GIC_FMU_WRITE_64(base, reg, n, val); \
+ /* Wait until FMU is ready */ \
+ wait_until_fmu_is_idle(base); \
+ } while (false)
+
+/*******************************************************************************
+ * GIC FMU functions for accessing the Fault Management Unit registers
+ ******************************************************************************/
+
+/*
+ * Accessors to read the Error Record Feature Register bits corresponding
+ * to an error record 'n'
+ */
+uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Error Record Control Register bits corresponding
+ * to an error record 'n'
+ */
+uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Error Record Primary Status Register bits
+ * corresponding to an error record 'n'
+ */
+uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Error Group Status Register
+ */
+uint64_t gic_fmu_read_errgsr(uintptr_t base)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the Ping Control Register
+ */
+uint32_t gic_fmu_read_pingctlr(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_PINGCTLR);
+}
+
+/*
+ * Accessors to read the Ping Now Register
+ */
+uint32_t gic_fmu_read_pingnow(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_PINGNOW);
+}
+
+/*
+ * Accessors to read the Ping Mask Register
+ */
+uint64_t gic_fmu_read_pingmask(uintptr_t base)
+{
+ /*
+ * APB bus is 32-bit wide; so split the 64-bit read into
+ * two 32-bit reads
+ */
+ uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO);
+
+ reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32);
+ return reg_val;
+}
+
+/*
+ * Accessors to read the FMU Status Register
+ */
+uint32_t gic_fmu_read_status(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_STATUS);
+}
+
+/*
+ * Accessors to read the Error Record ID Register
+ */
+uint32_t gic_fmu_read_erridr(uintptr_t base)
+{
+ return mmio_read_32(base + GICFMU_ERRIDR);
+}
+
+/*
+ * Accessors to write a 64 bit value to the Error Record Control Register
+ */
+void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val)
+{
+ GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val);
+}
+
+/*
+ * Accessors to write a 64 bit value to the Error Record Primary Status
+ * Register
+ */
+void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Ping Control Register
+ */
+void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val)
+{
+ GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Ping Now Register
+ */
+void gic_fmu_write_pingnow(uintptr_t base, uint32_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Safety Mechanism Enable Register
+ */
+void gic_fmu_write_smen(uintptr_t base, uint32_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val);
+}
+
+/*
+ * Accessors to write a 32 bit value to the Safety Mechanism Inject Error
+ * Register
+ */
+void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val)
+{
+ /* Wait until FMU is ready before writing */
+ GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val);
+}
+
+/*
+ * Accessors to write a 64 bit value to the Ping Mask Register
+ */
+void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
+{
+ GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
+}
+
+/*
+ * Helper function to disable all safety mechanisms for a given block
+ */
+void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid)
+{
+ uint32_t smen, max_smid = U(0);
+
+ /* Sanity check block ID */
+ assert((blkid >= FMU_BLK_GICD) && (blkid <= FMU_BLK_PPI31));
+
+ /* Find the max safety mechanism ID for the block */
+ switch (blkid) {
+ case FMU_BLK_GICD:
+ max_smid = FMU_SMID_GICD_MAX;
+ break;
+
+ case FMU_BLK_SPICOL:
+ max_smid = FMU_SMID_SPICOL_MAX;
+ break;
+
+ case FMU_BLK_WAKERQ:
+ max_smid = FMU_SMID_WAKERQ_MAX;
+ break;
+
+ case FMU_BLK_ITS0...FMU_BLK_ITS7:
+ max_smid = FMU_SMID_ITS_MAX;
+ break;
+
+ case FMU_BLK_PPI0...FMU_BLK_PPI31:
+ max_smid = FMU_SMID_PPI_MAX;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ /* Disable all Safety Mechanisms for a given block id */
+ for (unsigned int i = 0U; i < max_smid; i++) {
+ smen = (blkid << FMU_SMEN_BLK_SHIFT) | (i << FMU_SMEN_SMID_SHIFT);
+ gic_fmu_write_smen(base, smen);
+ }
+}
diff --git a/drivers/arm/gic/v3/gicv3.mk b/drivers/arm/gic/v3/gicv3.mk
index a2fc16f9ca..89bce95ded 100644
--- a/drivers/arm/gic/v3/gicv3.mk
+++ b/drivers/arm/gic/v3/gicv3.mk
@@ -1,21 +1,29 @@
#
-# Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Default configuration values
GICV3_SUPPORT_GIC600 ?= 0
+GICV3_SUPPORT_GIC600AE_FMU ?= 0
GICV3_IMPL_GIC600_MULTICHIP ?= 0
GICV3_OVERRIDE_DISTIF_PWR_OPS ?= 0
GIC_ENABLE_V4_EXTN ?= 0
GIC_EXT_INTID ?= 0
+GIC600_ERRATA_WA_2384374 ?= ${GICV3_SUPPORT_GIC600}
GICV3_SOURCES += drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \
drivers/arm/gic/v3/gicdv3_helpers.c \
drivers/arm/gic/v3/gicrv3_helpers.c
+ifeq (${GICV3_SUPPORT_GIC600AE_FMU}, 1)
+GICV3_SOURCES += drivers/arm/gic/v3/gic600ae_fmu.c \
+ drivers/arm/gic/v3/gic600ae_fmu_helpers.c
+endif
+
ifeq (${GICV3_OVERRIDE_DISTIF_PWR_OPS}, 0)
GICV3_SOURCES += drivers/arm/gic/v3/arm_gicv3_common.c
endif
@@ -29,6 +37,14 @@ endif
$(eval $(call assert_boolean,GICV3_SUPPORT_GIC600))
$(eval $(call add_define,GICV3_SUPPORT_GIC600))
+# Set GIC-600AE FMU support
+$(eval $(call assert_boolean,GICV3_SUPPORT_GIC600AE_FMU))
+$(eval $(call add_define,GICV3_SUPPORT_GIC600AE_FMU))
+
+# Set GIC-600 multichip support
+$(eval $(call assert_boolean,GICV3_IMPL_GIC600_MULTICHIP))
+$(eval $(call add_define,GICV3_IMPL_GIC600_MULTICHIP))
+
# Set GICv4 extension
$(eval $(call assert_boolean,GIC_ENABLE_V4_EXTN))
$(eval $(call add_define,GIC_ENABLE_V4_EXTN))
@@ -36,3 +52,7 @@ $(eval $(call add_define,GIC_ENABLE_V4_EXTN))
# Set support for extended PPI and SPI range
$(eval $(call assert_boolean,GIC_EXT_INTID))
$(eval $(call add_define,GIC_EXT_INTID))
+
+# Set errata workaround for GIC600/GIC600AE
+$(eval $(call assert_boolean,GIC600_ERRATA_WA_2384374))
+$(eval $(call add_define,GIC600_ERRATA_WA_2384374))
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 23a1dfaecd..b27debfa77 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,11 +11,24 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/interrupt_props.h>
+#include <drivers/arm/gic600_multichip.h>
#include <drivers/arm/gic_common.h>
+#include <platform_def.h>
+
#include "../common/gic_common_private.h"
#include "gicv3_private.h"
+uintptr_t gicv3_get_multichip_base(uint32_t spi_id, uintptr_t gicd_base)
+{
+#if GICV3_IMPL_GIC600_MULTICHIP
+ if (gic600_multichip_is_initialized()) {
+ return gic600_multichip_gicd_base_for_spi(spi_id);
+ }
+#endif
+ return gicd_base;
+}
+
/******************************************************************************
* This function marks the core as awake in the re-distributor and
* ensures that the interface is active.
@@ -86,8 +100,7 @@ void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
if (proc_num < rdistif_num) {
rdistif_base_addrs[proc_num] = rdistif_base;
}
-
- rdistif_base += (1U << GICR_PCPUBASE_SHIFT);
+ rdistif_base += gicv3_redist_size(typer_val);
} while ((typer_val & TYPER_LAST_BIT) == 0U);
}
@@ -110,6 +123,28 @@ unsigned int gicv3_get_spi_limit(uintptr_t gicd_base)
return spi_limit;
}
+#if GIC_EXT_INTID
+/*******************************************************************************
+ * Helper function to get the maximum ESPI INTID + 1.
+ ******************************************************************************/
+unsigned int gicv3_get_espi_limit(uintptr_t gicd_base)
+{
+ unsigned int typer_reg = gicd_read_typer(gicd_base);
+
+ /* Check if extended SPI range is implemented */
+ if ((typer_reg & TYPER_ESPI) != 0U) {
+ /*
+ * (maximum ESPI INTID + 1) is equal to
+ * 32 * (GICD_TYPER.ESPI_range + 1) + 4096
+ */
+ return ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) &
+ TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID;
+ }
+
+ return 0U;
+}
+#endif /* GIC_EXT_INTID */
+
/*******************************************************************************
* Helper function to configure the default attributes of (E)SPIs.
******************************************************************************/
@@ -119,67 +154,50 @@ void gicv3_spis_config_defaults(uintptr_t gicd_base)
#if GIC_EXT_INTID
unsigned int num_eints;
#endif
- unsigned int typer_reg = gicd_read_typer(gicd_base);
-
- /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */
- num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5;
- /*
- * The GICv3 architecture allows GICD_TYPER.ITLinesNumber to be 31, so
- * the maximum possible value for num_ints is 1024. Limit the value to
- * MAX_SPI_ID + 1 to avoid getting wrong address in GICD_OFFSET() macro.
- */
- if (num_ints > MAX_SPI_ID + 1U) {
- num_ints = MAX_SPI_ID + 1U;
- }
+ num_ints = gicv3_get_spi_limit(gicd_base);
INFO("Maximum SPI INTID supported: %u\n", num_ints - 1);
/* Treat all (E)SPIs as G1NS by default. We do 32 at a time. */
for (i = MIN_SPI_ID; i < num_ints; i += (1U << IGROUPR_SHIFT)) {
- gicd_write_igroupr(gicd_base, i, ~0U);
+ gicd_write_igroupr(gicv3_get_multichip_base(i, gicd_base), i, ~0U);
}
#if GIC_EXT_INTID
- /* Check if extended SPI range is implemented */
- if ((typer_reg & TYPER_ESPI) != 0U) {
- /*
- * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095
- */
- num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) &
- TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID;
+ num_eints = gicv3_get_espi_limit(gicd_base);
+ if (num_eints != 0U) {
INFO("Maximum ESPI INTID supported: %u\n", num_eints - 1);
for (i = MIN_ESPI_ID; i < num_eints;
i += (1U << IGROUPR_SHIFT)) {
- gicd_write_igroupr(gicd_base, i, ~0U);
+ gicd_write_igroupr(gicv3_get_multichip_base(i, gicd_base), i, ~0U);
}
} else {
- num_eints = 0U;
INFO("ESPI range is not implemented.\n");
}
#endif
/* Setup the default (E)SPI priorities doing four at a time */
for (i = MIN_SPI_ID; i < num_ints; i += (1U << IPRIORITYR_SHIFT)) {
- gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+ gicd_write_ipriorityr(gicv3_get_multichip_base(i, gicd_base), i, GICD_IPRIORITYR_DEF_VAL);
}
#if GIC_EXT_INTID
for (i = MIN_ESPI_ID; i < num_eints;
i += (1U << IPRIORITYR_SHIFT)) {
- gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+ gicd_write_ipriorityr(gicv3_get_multichip_base(i, gicd_base), i, GICD_IPRIORITYR_DEF_VAL);
}
#endif
/*
* Treat all (E)SPIs as level triggered by default, write 16 at a time
*/
for (i = MIN_SPI_ID; i < num_ints; i += (1U << ICFGR_SHIFT)) {
- gicd_write_icfgr(gicd_base, i, 0U);
+ gicd_write_icfgr(gicv3_get_multichip_base(i, gicd_base), i, 0U);
}
#if GIC_EXT_INTID
for (i = MIN_ESPI_ID; i < num_eints; i += (1U << ICFGR_SHIFT)) {
- gicd_write_icfgr(gicd_base, i, 0U);
+ gicd_write_icfgr(gicv3_get_multichip_base(i, gicd_base), i, 0U);
}
#endif
}
@@ -205,49 +223,54 @@ unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base,
current_prop = &interrupt_props[i];
unsigned int intr_num = current_prop->intr_num;
+ uintptr_t multichip_gicd_base;
/* Skip SGI, (E)PPI and LPI interrupts */
if (!IS_SPI(intr_num)) {
continue;
}
+ multichip_gicd_base =
+ gicv3_get_multichip_base(intr_num, gicd_base);
+
/* Configure this interrupt as a secure interrupt */
- gicd_clr_igroupr(gicd_base, intr_num);
+ gicd_clr_igroupr(multichip_gicd_base, intr_num);
/* Configure this interrupt as G0 or a G1S interrupt */
assert((current_prop->intr_grp == INTR_GROUP0) ||
(current_prop->intr_grp == INTR_GROUP1S));
if (current_prop->intr_grp == INTR_GROUP1S) {
- gicd_set_igrpmodr(gicd_base, intr_num);
+ gicd_set_igrpmodr(multichip_gicd_base, intr_num);
ctlr_enable |= CTLR_ENABLE_G1S_BIT;
} else {
- gicd_clr_igrpmodr(gicd_base, intr_num);
+ gicd_clr_igrpmodr(multichip_gicd_base, intr_num);
ctlr_enable |= CTLR_ENABLE_G0_BIT;
}
/* Set interrupt configuration */
- gicd_set_icfgr(gicd_base, intr_num, current_prop->intr_cfg);
+ gicd_set_icfgr(multichip_gicd_base, intr_num,
+ current_prop->intr_cfg);
/* Set the priority of this interrupt */
- gicd_set_ipriorityr(gicd_base, intr_num,
- current_prop->intr_pri);
+ gicd_set_ipriorityr(multichip_gicd_base, intr_num,
+ current_prop->intr_pri);
/* Target (E)SPIs to the primary CPU */
gic_affinity_val =
gicd_irouter_val_from_mpidr(read_mpidr(), 0U);
- gicd_write_irouter(gicd_base, intr_num,
- gic_affinity_val);
+ gicd_write_irouter(multichip_gicd_base, intr_num,
+ gic_affinity_val);
/* Enable this interrupt */
- gicd_set_isenabler(gicd_base, intr_num);
+ gicd_set_isenabler(multichip_gicd_base, intr_num);
}
return ctlr_enable;
}
/*******************************************************************************
- * Helper function to configure the default attributes of (E)SPIs
+ * Helper function to configure the default attributes of (E)PPIs/SGIs
******************************************************************************/
void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base)
{
@@ -286,7 +309,7 @@ void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base)
regs_num = ppi_regs_num << 3;
for (i = 0U; i < regs_num; ++i) {
/* Setup the default (E)PPI/SGI priorities doing 4 at a time */
- gicr_write_ipriorityr(gicr_base, i, GICD_IPRIORITYR_DEF_VAL);
+ gicr_write_ipriorityr(gicr_base, i << 2, GICD_IPRIORITYR_DEF_VAL);
}
/* 16 interrupt IDs per GICR_ICFGR register */
@@ -378,12 +401,60 @@ unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame)
uintptr_t rdistif_base = gicr_frame;
unsigned int count;
- for (count = 1; count < PLATFORM_CORE_COUNT; count++) {
- if ((gicr_read_typer(rdistif_base) & TYPER_LAST_BIT) != 0U) {
+ for (count = 1U; count < PLATFORM_CORE_COUNT; count++) {
+ uint64_t typer_val = gicr_read_typer(rdistif_base);
+
+ if ((typer_val & TYPER_LAST_BIT) != 0U) {
break;
}
- rdistif_base += (1U << GICR_PCPUBASE_SHIFT);
+ rdistif_base += gicv3_redist_size(typer_val);
}
return count;
}
+
+unsigned int gicv3_get_component_partnum(const uintptr_t gic_frame)
+{
+ unsigned int part_id;
+
+ /*
+ * The lower 8 bits of PIDR0, complemented by the lower 4 bits of
+ * PIDR1 contain a part number identifying the GIC component at a
+ * particular base address.
+ */
+ part_id = mmio_read_32(gic_frame + GICD_PIDR0_GICV3) & 0xff;
+ part_id |= (mmio_read_32(gic_frame + GICD_PIDR1_GICV3) << 8) & 0xf00;
+
+ return part_id;
+}
+
+/*******************************************************************************
+ * Helper function to return product ID and revision of GIC
+ * @gicd_base: base address of the GIC distributor
+ * @gic_prod_id: retrieved product id of GIC
+ * @gic_rev: retrieved revision of GIC
+ ******************************************************************************/
+void gicv3_get_component_prodid_rev(const uintptr_t gicd_base,
+ unsigned int *gic_prod_id,
+ uint8_t *gic_rev)
+{
+ unsigned int gicd_iidr;
+ uint8_t gic_variant;
+
+ gicd_iidr = gicd_read_iidr(gicd_base);
+ *gic_prod_id = gicd_iidr >> IIDR_PRODUCT_ID_SHIFT;
+ *gic_prod_id &= IIDR_PRODUCT_ID_MASK;
+
+ gic_variant = gicd_iidr >> IIDR_VARIANT_SHIFT;
+ gic_variant &= IIDR_VARIANT_MASK;
+
+ *gic_rev = gicd_iidr >> IIDR_REV_SHIFT;
+ *gic_rev &= IIDR_REV_MASK;
+
+ /*
+ * pack gic variant and gic_rev in 1 byte
+ * gic_rev = gic_variant[7:4] and gic_rev[0:3]
+ */
+ *gic_rev = *gic_rev | gic_variant << 0x4;
+
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 5a49b4f5ed..8ea164ce86 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,8 +11,10 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/interrupt_props.h>
+#include <drivers/arm/gic600_multichip.h>
#include <drivers/arm/gicv3.h>
#include <lib/spinlock.h>
+#include <plat/common/platform.h>
#include "gicv3_private.h"
@@ -31,8 +34,8 @@ static spinlock_t gic_lock;
#pragma weak gicv3_rdistif_off
#pragma weak gicv3_rdistif_on
-/* Check interrupt ID for SGI/(E)PPI and (E)SPIs */
-static bool is_sgi_ppi(unsigned int id);
+/* Check for valid SGI/PPI or SPI interrupt ID */
+static bool is_valid_interrupt(unsigned int id);
/*
* Helper macros to save and restore GICR and GICD registers
@@ -123,13 +126,7 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
gic_version &= PIDR2_ARCH_REV_MASK;
/* Check GIC version */
-#if GIC_ENABLE_V4_EXTN
- assert(gic_version == ARCH_REV_GICV4);
-
- /* GICv4 supports Direct Virtual LPI injection */
- assert((gicd_read_typer(plat_driver_data->gicd_base)
- & TYPER_DVIS) != 0);
-#else
+#if !GIC_ENABLE_V4_EXTN
assert(gic_version == ARCH_REV_GICV3);
#endif
/*
@@ -175,6 +172,8 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
flush_dcache_range((uintptr_t)gicv3_driver_data,
sizeof(*gicv3_driver_data));
#endif
+ gicv3_check_erratas_applies(plat_driver_data->gicd_base);
+
INFO("GICv%u with%s legacy support detected.\n", gic_version,
(gicv2_compat == 0U) ? "" : "out");
INFO("ARM GICv%u driver initialized in EL3\n", gic_version);
@@ -331,7 +330,11 @@ void gicv3_cpuif_enable(unsigned int proc_num)
/* Enable Group1 Secure interrupts */
write_icc_igrpen1_el3(read_icc_igrpen1_el3() |
IGRPEN1_EL3_ENABLE_G1S_BIT);
+ /* and restore the original */
+ write_scr_el3(scr_el3);
isb();
+ /* Add DSB to ensure visibility of System register writes */
+ dsb();
}
/*******************************************************************************
@@ -363,10 +366,20 @@ void gicv3_cpuif_disable(unsigned int proc_num)
/* Synchronise accesses to group enable registers */
isb();
+ /* Add DSB to ensure visibility of System register writes */
+ dsb();
- /* Mark the connected core as asleep */
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
- assert(gicr_base != 0U);
+ assert(gicr_base != 0UL);
+
+ /*
+ * dsb() already issued previously after clearing the CPU group
+ * enabled, apply below workaround to toggle the "DPG*"
+ * bits of GICR_CTLR register for unblocking event.
+ */
+ gicv3_apply_errata_wa_2384374(gicr_base);
+
+ /* Mark the connected core as asleep */
gicv3_rdistif_mark_core_asleep(gicr_base);
}
@@ -408,19 +421,19 @@ unsigned int gicv3_get_pending_interrupt_type(void)
}
/*******************************************************************************
- * This function returns the type of the interrupt id depending upon the group
- * this interrupt has been configured under by the interrupt controller i.e.
- * group0 or group1 Secure / Non Secure. The return value can be one of the
- * following :
+ * This function returns the group that has been configured under by the
+ * interrupt controller for the given interrupt id i.e. either group0 or group1
+ * Secure / Non Secure. The return value can be one of the following :
* INTR_GROUP0 : The interrupt type is a Secure Group 0 interrupt
* INTR_GROUP1S : The interrupt type is a Secure Group 1 secure interrupt
* INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure
* interrupt.
******************************************************************************/
-unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num)
+unsigned int gicv3_get_interrupt_group(unsigned int id, unsigned int proc_num)
{
unsigned int igroup, grpmodr;
uintptr_t gicr_base;
+ uintptr_t gicd_base;
assert(IS_IN_EL3());
assert(gicv3_driver_data != NULL);
@@ -434,8 +447,12 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num)
return INTR_GROUP1NS;
}
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
+
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
@@ -444,8 +461,9 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num)
} else {
/* SPIs: 32-1019, ESPIs: 4096-5119 */
assert(gicv3_driver_data->gicd_base != 0U);
- igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
- grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ igroup = gicd_get_igroupr(gicd_base, id);
+ grpmodr = gicd_get_igrpmodr(gicd_base, id);
}
/*
@@ -728,40 +746,17 @@ void gicv3_rdistif_init_restore(unsigned int proc_num,
*****************************************************************************/
void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
{
- unsigned int typer_reg, num_ints;
-#if GIC_EXT_INTID
- unsigned int num_eints;
-#endif
-
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(IS_IN_EL3());
assert(dist_ctx != NULL);
uintptr_t gicd_base = gicv3_driver_data->gicd_base;
-
- typer_reg = gicd_read_typer(gicd_base);
-
- /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */
- num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5;
-
- /* Filter out special INTIDs 1020-1023 */
- if (num_ints > (MAX_SPI_ID + 1U)) {
- num_ints = MAX_SPI_ID + 1U;
- }
-
+ unsigned int num_ints = gicv3_get_spi_limit(gicd_base);
#if GIC_EXT_INTID
- /* Check if extended SPI range is implemented */
- if ((typer_reg & TYPER_ESPI) != 0U) {
- /*
- * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095
- */
- num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) &
- TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID;
- } else {
- num_eints = 0U;
- }
+ unsigned int num_eints = gicv3_get_espi_limit(gicd_base);
#endif
+
/* Wait for pending write to complete */
gicd_wait_for_pending_write(gicd_base);
@@ -838,11 +833,6 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
*****************************************************************************/
void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
{
- unsigned int typer_reg, num_ints;
-#if GIC_EXT_INTID
- unsigned int num_eints;
-#endif
-
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(IS_IN_EL3());
@@ -864,27 +854,9 @@ void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
- typer_reg = gicd_read_typer(gicd_base);
-
- /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */
- num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5;
-
- /* Filter out special INTIDs 1020-1023 */
- if (num_ints > (MAX_SPI_ID + 1U)) {
- num_ints = MAX_SPI_ID + 1U;
- }
-
+ unsigned int num_ints = gicv3_get_spi_limit(gicd_base);
#if GIC_EXT_INTID
- /* Check if extended SPI range is implemented */
- if ((typer_reg & TYPER_ESPI) != 0U) {
- /*
- * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095
- */
- num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) &
- TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID;
- } else {
- num_eints = 0U;
- }
+ unsigned int num_eints = gicv3_get_espi_limit(gicd_base);
#endif
/* Restore GICD_IGROUPR for INTIDs 32 - 1019 */
RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUP);
@@ -967,20 +939,26 @@ unsigned int gicv3_get_running_priority(void)
******************************************************************************/
unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num)
{
+ uintptr_t gicd_base;
+
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
return gicr_get_isactiver(
gicv3_driver_data->rdistif_base_addrs[proc_num], id);
}
/* For SPIs: 32-1019 and ESPIs: 4096-5119 */
- return gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ return gicd_get_isactiver(gicd_base, id);
}
/*******************************************************************************
@@ -990,6 +968,8 @@ unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num)
******************************************************************************/
void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
{
+ uintptr_t gicd_base;
+
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
@@ -1000,15 +980,18 @@ void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
* interrupt trigger are observed before enabling interrupt.
*/
dsbishst();
-
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_set_isenabler(
gicv3_driver_data->rdistif_base_addrs[proc_num], id);
} else {
/* For SPIs: 32-1019 and ESPIs: 4096-5119 */
- gicd_set_isenabler(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ gicd_set_isenabler(gicd_base, id);
}
}
@@ -1019,6 +1002,8 @@ void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
******************************************************************************/
void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
{
+ uintptr_t gicd_base;
+
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
@@ -1028,9 +1013,11 @@ void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
* Disable interrupt, and ensure that any shared variable updates
* depending on out of band interrupt trigger are observed afterwards.
*/
-
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_set_icenabler(
gicv3_driver_data->rdistif_base_addrs[proc_num], id);
@@ -1040,10 +1027,11 @@ void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
gicv3_driver_data->rdistif_base_addrs[proc_num]);
} else {
/* For SPIs: 32-1019 and ESPIs: 4096-5119 */
- gicd_set_icenabler(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ gicd_set_icenabler(gicd_base, id);
/* Write to clear enable requires waiting for pending writes */
- gicd_wait_for_pending_write(gicv3_driver_data->gicd_base);
+ gicd_wait_for_pending_write(gicd_base);
}
dsbishst();
@@ -1057,20 +1045,25 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
unsigned int priority)
{
uintptr_t gicr_base;
+ uintptr_t gicd_base;
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
gicr_set_ipriorityr(gicr_base, id, priority);
} else {
/* For SPIs: 32-1019 and ESPIs: 4096-5119 */
- gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ gicd_set_ipriorityr(gicd_base, id, priority);
}
}
@@ -1079,18 +1072,19 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
* is used if the interrupt is SGI or (E)PPI, and programs the corresponding
* Redistributor interface. The group can be any of GICV3_INTR_GROUP*
******************************************************************************/
-void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
- unsigned int type)
+void gicv3_set_interrupt_group(unsigned int id, unsigned int proc_num,
+ unsigned int group)
{
bool igroup = false, grpmod = false;
uintptr_t gicr_base;
+ uintptr_t gicd_base;
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
- switch (type) {
+ switch (group) {
case INTR_GROUP1S:
igroup = false;
grpmod = true;
@@ -1108,8 +1102,11 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
break;
}
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
@@ -1123,21 +1120,24 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
/* Serialize read-modify-write to Distributor registers */
spin_lock(&gic_lock);
- igroup ? gicd_set_igroupr(gicv3_driver_data->gicd_base, id) :
- gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
- grpmod ? gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id) :
- gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+
+ igroup ? gicd_set_igroupr(gicd_base, id) :
+ gicd_clr_igroupr(gicd_base, id);
+ grpmod ? gicd_set_igrpmodr(gicd_base, id) :
+ gicd_clr_igrpmodr(gicd_base, id);
spin_unlock(&gic_lock);
}
}
/*******************************************************************************
- * This function raises the specified Secure Group 0 SGI.
+ * This function raises the specified SGI of the specified group.
*
* The target parameter must be a valid MPIDR in the system.
******************************************************************************/
-void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target)
+void gicv3_raise_sgi(unsigned int sgi_num, gicv3_irq_group_t group,
+ u_register_t target)
{
unsigned int tgt, aff3, aff2, aff1, aff0;
uint64_t sgi_val;
@@ -1167,7 +1167,22 @@ void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target)
* interrupt trigger are observed before raising SGI.
*/
dsbishst();
- write_icc_sgi0r_el1(sgi_val);
+
+ switch (group) {
+ case GICV3_G0:
+ write_icc_sgi0r_el1(sgi_val);
+ break;
+ case GICV3_G1NS:
+ write_icc_asgi1r(sgi_val);
+ break;
+ case GICV3_G1S:
+ write_icc_sgi1r(sgi_val);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
isb();
}
@@ -1186,6 +1201,7 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr
{
unsigned long long aff;
uint64_t router;
+ uintptr_t gicd_base;
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
@@ -1195,14 +1211,15 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr
assert(IS_SPI(id));
aff = gicd_irouter_val_from_mpidr(mpidr, irm);
- gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ gicd_write_irouter(gicd_base, id, aff);
/*
* In implementations that do not require 1 of N distribution of SPIs,
* IRM might be RAZ/WI. Read back and verify IRM bit.
*/
if (irm == GICV3_IRM_ANY) {
- router = gicd_read_irouter(gicv3_driver_data->gicd_base, id);
+ router = gicd_read_irouter(gicd_base, id);
if (((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK) == 0U) {
ERROR("GICv3 implementation doesn't support routing ANY\n");
panic();
@@ -1217,6 +1234,8 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr
******************************************************************************/
void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
{
+ uintptr_t gicd_base;
+
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
@@ -1226,15 +1245,18 @@ void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
* Clear pending interrupt, and ensure that any shared variable updates
* depending on out of band interrupt trigger are observed afterwards.
*/
-
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_set_icpendr(
- gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
} else {
/* For SPIs: 32-1019 and ESPIs: 4096-5119 */
- gicd_set_icpendr(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ gicd_set_icpendr(gicd_base, id);
}
dsbishst();
@@ -1247,6 +1269,8 @@ void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
******************************************************************************/
void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
{
+ uintptr_t gicd_base;
+
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
@@ -1258,14 +1282,19 @@ void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
*/
dsbishst();
+ if (!is_valid_interrupt(id)) {
+ panic();
+ }
+
/* Check interrupt ID */
- if (is_sgi_ppi(id)) {
+ if (IS_SGI_PPI(id)) {
/* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_set_ispendr(
gicv3_driver_data->rdistif_base_addrs[proc_num], id);
} else {
/* For SPIs: 32-1019 and ESPIs: 4096-5119 */
- gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
+ gicd_base = gicv3_get_multichip_base(id, gicv3_driver_data->gicd_base);
+ gicd_set_ispendr(gicd_base, id);
}
}
@@ -1292,6 +1321,31 @@ unsigned int gicv3_set_pmr(unsigned int mask)
}
/*******************************************************************************
+ * This function restores the PMR register to old value and also triggers
+ * gicv3_apply_errata_wa_2384374() that flushes the GIC buffer allowing any
+ * pending interrupts to processed. Returns the original PMR.
+ ******************************************************************************/
+unsigned int gicv3_deactivate_priority(unsigned int mask)
+{
+
+ unsigned int old_mask, proc_num;
+ uintptr_t gicr_base;
+
+ old_mask = gicv3_set_pmr(mask);
+
+ proc_num = plat_my_core_pos();
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+ assert(gicr_base != 0UL);
+
+ /* Add DSB to ensure visibility of System register writes */
+ dsb();
+
+ gicv3_apply_errata_wa_2384374(gicr_base);
+
+ return old_mask;
+}
+
+/*******************************************************************************
* This function delegates the responsibility of discovering the corresponding
* Redistributor frames to each CPU itself. It is a modified version of
* gicv3_rdistif_base_addrs_probe() and is executed by each CPU in the platform
@@ -1309,12 +1363,14 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
assert(gicv3_driver_data->gicr_base == 0U);
+ if (plat_can_cmo()) {
/* Ensure this function is called with Data Cache enabled */
#ifndef __aarch64__
- assert((read_sctlr() & SCTLR_C_BIT) != 0U);
+ assert((read_sctlr() & SCTLR_C_BIT) != 0U);
#else
- assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+ assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
#endif /* !__aarch64__ */
+ }
mpidr_self = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
rdistif_base = gicr_frame;
@@ -1340,7 +1396,7 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
gicr_frame_found = true;
break;
}
- rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT);
+ rdistif_base += gicv3_redist_size(typer_val);
} while ((typer_val & TYPER_LAST_BIT) == 0U);
if (!gicr_frame_found) {
@@ -1363,21 +1419,19 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
}
/******************************************************************************
- * This function checks the interrupt ID and returns true for SGIs and (E)PPIs
- * and false for (E)SPIs IDs.
+ * This function checks the interrupt ID and returns true for SGIs, (E)PPIs
+ * and (E)SPIs IDs. Any interrupt ID outside the range is invalid and returns
+ * false.
*****************************************************************************/
-static bool is_sgi_ppi(unsigned int id)
+static bool is_valid_interrupt(unsigned int id)
{
- /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
- if (IS_SGI_PPI(id)) {
+ /* Valid interrupts:
+ * SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119
+ * SPIs: 32-1019, ESPIs: 4096-5119
+ */
+ if ((IS_SGI_PPI(id)) || (IS_SPI(id))) {
return true;
}
- /* SPIs: 32-1019, ESPIs: 4096-5119 */
- if (IS_SPI(id)) {
- return false;
- }
-
- assert(false);
- panic();
+ return false;
}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index 7965f40918..8ad251bf8f 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -171,7 +172,7 @@
static inline u_register_t gicd_irouter_val_from_mpidr(u_register_t mpidr,
unsigned int irm)
{
- return (mpidr & ~(U(0xff) << 24)) |
+ return (mpidr & MPIDR_AFFINITY_MASK) |
((irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT);
}
@@ -233,7 +234,9 @@ void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg);
/*******************************************************************************
* Private GICv3 helper function prototypes
******************************************************************************/
+uintptr_t gicv3_get_multichip_base(uint32_t spi_id, uintptr_t gicd_base);
unsigned int gicv3_get_spi_limit(uintptr_t gicd_base);
+unsigned int gicv3_get_espi_limit(uintptr_t gicd_base);
void gicv3_spis_config_defaults(uintptr_t gicd_base);
void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base);
unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base,
diff --git a/drivers/arm/mhu/mhu_v2_x.c b/drivers/arm/mhu/mhu_v2_x.c
new file mode 100644
index 0000000000..3103b92433
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v2_x.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "mhu_v2_x.h"
+
+#define MHU_V2_X_MAX_CHANNELS 124
+#define MHU_V2_1_MAX_CHCOMB_INT 4
+#define ENABLE 0x1
+#define DISABLE 0x0
+#define CLEAR_INTR 0x1
+#define CH_PER_CH_COMB 0x20
+#define SEND_FRAME(p_mhu) ((struct mhu_v2_x_send_frame_t *)p_mhu)
+#define RECV_FRAME(p_mhu) ((struct mhu_v2_x_recv_frame_t *)p_mhu)
+
+#define MHU_MAJOR_REV_V2 0x1u
+#define MHU_MINOR_REV_2_0 0x0u
+#define MHU_MINOR_REV_2_1 0x1u
+
+struct mhu_v2_x_send_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x08 (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0x0C ( /W) Channel Set */
+ volatile uint32_t ch_set;
+ /* Offset: 0x10 (R/ ) Channel Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t ch_int_st;
+ /* Offset: 0x14 ( /W) Channel Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t ch_int_clr;
+ /* Offset: 0x18 (R/W) Channel Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t ch_int_en;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_2;
+};
+
+struct mhu_v2_x_send_frame_t {
+ /* Offset: 0x000 ( / ) Sender Channel Window 0 -123 */
+ struct mhu_v2_x_send_ch_window_t send_ch_window[MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/W) Response Configuration */
+ volatile uint32_t resp_cfg;
+ /* Offset: 0xF88 (R/W) Access Request */
+ volatile uint32_t access_request;
+ /* Offset: 0xF8C (R/ ) Access Ready */
+ volatile uint32_t access_ready;
+ /* Offset: 0xF90 (R/ ) Interrupt Status */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 ( /W) Interrupt Clear */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0xFA0 (R/W) Channel Combined IRQ Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: 0xFC4 (R/ ) Reserved */
+ volatile uint32_t reserved_1[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+struct mhu_v2_x_rec_ch_window_t {
+ /* Offset: 0x00 (R/ ) Channel Status */
+ volatile uint32_t ch_st;
+ /* Offset: 0x04 (R/ ) Channel Status Masked */
+ volatile uint32_t ch_st_msk;
+ /* Offset: 0x08 ( /W) Channel Clear */
+ volatile uint32_t ch_clr;
+ /* Offset: 0x0C (R/ ) Reserved */
+ volatile uint32_t reserved_0;
+ /* Offset: 0x10 (R/ ) Channel Mask Status */
+ volatile uint32_t ch_msk_st;
+ /* Offset: 0x14 ( /W) Channel Mask Set */
+ volatile uint32_t ch_msk_set;
+ /* Offset: 0x18 ( /W) Channel Mask Clear */
+ volatile uint32_t ch_msk_clr;
+ /* Offset: 0x1C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+};
+
+struct mhu_v2_x_recv_frame_t {
+ /* Offset: 0x000 ( / ) Receiver Channel Window 0 -123 */
+ struct mhu_v2_x_rec_ch_window_t rec_ch_window[MHU_V2_X_MAX_CHANNELS];
+ /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+ volatile uint32_t mhu_cfg;
+ /* Offset: 0xF84 (R/ ) Reserved */
+ volatile uint32_t reserved_0[3];
+ /* Offset: 0xF90 (R/ ) Interrupt Status (Reserved in 2.0) */
+ volatile uint32_t int_st;
+ /* Offset: 0xF94 (R/ ) Interrupt Clear (Reserved in 2.0) */
+ volatile uint32_t int_clr;
+ /* Offset: 0xF98 (R/W) Interrupt Enable (Reserved in 2.0) */
+ volatile uint32_t int_en;
+ /* Offset: 0xF9C (R/ ) Reserved */
+ volatile uint32_t reserved_1;
+ /* Offset: 0xFA0 (R/ ) Channel Combined IRQ Stat (Reserved in 2.0) */
+ volatile uint32_t ch_comb_int_st[MHU_V2_1_MAX_CHCOMB_INT];
+ /* Offset: 0xFB0 (R/ ) Reserved */
+ volatile uint32_t reserved_2[6];
+ /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+ volatile uint32_t iidr;
+ /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+ volatile uint32_t aidr;
+ /* Offset: 0xFD0 (R/ ) */
+ volatile uint32_t pid_1[4];
+ /* Offset: 0xFE0 (R/ ) */
+ volatile uint32_t pid_0[4];
+ /* Offset: 0xFF0 (R/ ) */
+ volatile uint32_t cid[4];
+};
+
+union mhu_v2_x_frame {
+ struct mhu_v2_x_send_frame_t send_frame;
+ struct mhu_v2_x_recv_frame_t recv_frame;
+};
+
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev)
+{
+ uint32_t AIDR = 0;
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (dev->is_initialized) {
+ return MHU_V_2_X_ERR_ALREADY_INIT;
+ }
+
+ if (rev == MHU_REV_READ_FROM_HW) {
+ /* Read revision from HW */
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ AIDR = p_mhu->recv_frame.aidr;
+ } else {
+ AIDR = p_mhu->send_frame.aidr;
+ }
+
+ /* Get bits 7:4 to read major revision */
+ if (((AIDR >> 4) & 0b1111) != MHU_MAJOR_REV_V2) {
+ /* Unsupported MHU version */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ } /* No need to save major version, driver only supports MHUv2 */
+
+ /* Get bits 3:0 to read minor revision */
+ dev->subversion = AIDR & 0b1111;
+
+ if (dev->subversion != MHU_MINOR_REV_2_0 &&
+ dev->subversion != MHU_MINOR_REV_2_1) {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ }
+ } else {
+ /* Revisions were provided by caller */
+ if (rev == MHU_REV_2_0) {
+ dev->subversion = MHU_MINOR_REV_2_0;
+ } else if (rev == MHU_REV_2_1) {
+ dev->subversion = MHU_MINOR_REV_2_1;
+ } else {
+ /* Unsupported subversion */
+ return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+ } /* No need to save major version, driver only supports MHUv2 */
+ }
+
+ dev->is_initialized = true;
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ return (SEND_FRAME(p_mhu))->mhu_cfg;
+ } else {
+ assert(dev->frame == MHU_V2_X_RECEIVER_FRAME);
+ return (RECV_FRAME(p_mhu))->mhu_cfg;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_set = val;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t *value)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ *value = (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_clr = UINT32_MAX;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ *value = (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_set = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+ (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_clr = mask;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+ while (!((SEND_FRAME(p_mhu))->access_ready)) {
+ /* Wait in a loop for access ready signal to be high */
+ ;
+ }
+
+ return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(const struct mhu_v2_x_dev_t *dev)
+{
+ union mhu_v2_x_frame *p_mhu;
+
+ assert(dev != NULL);
+
+ p_mhu = (union mhu_v2_x_frame *)dev->base;
+
+ if (!(dev->is_initialized)) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame != MHU_V2_X_SENDER_FRAME) {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+
+ (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+ return MHU_V_2_X_ERR_NONE;
+}
diff --git a/drivers/arm/mhu/mhu_v2_x.h b/drivers/arm/mhu/mhu_v2_x.h
new file mode 100644
index 0000000000..10247d24f4
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v2_x.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_V2_X_H
+#define MHU_V2_X_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define MHU_2_X_INTR_NR2R_OFF (0x0u)
+#define MHU_2_X_INTR_R2NR_OFF (0x1u)
+#define MHU_2_1_INTR_CHCOMB_OFF (0x2u)
+
+#define MHU_2_X_INTR_NR2R_MASK (0x1u << MHU_2_X_INTR_NR2R_OFF)
+#define MHU_2_X_INTR_R2NR_MASK (0x1u << MHU_2_X_INTR_R2NR_OFF)
+#define MHU_2_1_INTR_CHCOMB_MASK (0x1u << MHU_2_1_INTR_CHCOMB_OFF)
+
+enum mhu_v2_x_frame_t {
+ MHU_V2_X_SENDER_FRAME = 0x0u,
+ MHU_V2_X_RECEIVER_FRAME = 0x1u,
+};
+
+enum mhu_v2_x_supported_revisions {
+ MHU_REV_READ_FROM_HW = 0,
+ MHU_REV_2_0,
+ MHU_REV_2_1,
+};
+
+struct mhu_v2_x_dev_t {
+ uintptr_t base;
+ enum mhu_v2_x_frame_t frame;
+ uint32_t subversion; /*!< Hardware subversion: v2.X */
+ bool is_initialized; /*!< Indicates if the MHU driver
+ * is initialized and enabled
+ */
+};
+
+/**
+ * MHU v2 error enumeration types.
+ */
+enum mhu_v2_x_error_t {
+ MHU_V_2_X_ERR_NONE = 0,
+ MHU_V_2_X_ERR_NOT_INIT = -1,
+ MHU_V_2_X_ERR_ALREADY_INIT = -2,
+ MHU_V_2_X_ERR_UNSUPPORTED_VERSION = -3,
+ MHU_V_2_X_ERR_INVALID_ARG = -4,
+ MHU_V_2_X_ERR_GENERAL = -5
+};
+
+/**
+ * Initializes the driver.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * rev MHU revision (if can't be identified from HW).
+ *
+ * Reads the MHU hardware version.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * MHU revision only has to be specified when versions can't be read
+ * from HW (ARCH_MAJOR_REV reg reads as 0x0).
+ *
+ * This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+ enum mhu_v2_x_supported_revisions rev);
+
+/**
+ * Returns the number of channels implemented.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ *
+ * This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_num_channel_implemented(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * Sends the value over a channel.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to send the value over.
+ * val Value to send.
+ *
+ * Sends the value over a channel.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t val);
+
+/**
+ * Polls sender channel status.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to poll the status of.
+ * value Pointer to variable that will store the value.
+ *
+ * Polls sender channel status.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t *value);
+
+/**
+ * Clears the channel after the value is send over it.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to clear.
+ *
+ * Clears the channel after the value is send over it.
+ *
+ * Returns mhu_v2_x_error_t error code..
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel);
+
+/**
+ * Receives the value over a channel.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Channel to receive the value from.
+ * value Pointer to variable that will store the value.
+ *
+ * Receives the value over a channel.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value);
+
+/**
+ * Sets bits in the Channel Mask.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Which channel's mask to set.
+ * mask Mask to be set over a receiver frame.
+ *
+ * Sets bits in the Channel Mask.
+ *
+ * Returns mhu_v2_x_error_t error code..
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * Clears bits in the Channel Mask.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ * channel Which channel's mask to clear.
+ * mask Mask to be clear over a receiver frame.
+ *
+ * Clears bits in the Channel Mask.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ * This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+ const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * Initiates a MHU transfer with the handshake signals.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ *
+ * Initiates a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * Closes a MHU transfer with the handshake signals.
+ *
+ * dev MHU device struct mhu_v2_x_dev_t.
+ *
+ * Closes a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * Returns mhu_v2_x_error_t error code.
+ *
+ * This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(
+ const struct mhu_v2_x_dev_t *dev);
+
+#endif /* MHU_V2_X_H */
diff --git a/drivers/arm/mhu/mhu_v3_x.c b/drivers/arm/mhu/mhu_v3_x.c
new file mode 100644
index 0000000000..118c608ecd
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v3_x.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "mhu_v3_x.h"
+
+#include "mhu_v3_x_private.h"
+
+/*
+ * Get the device base from the device struct. Return an error if the dev is
+ * invalid.
+ */
+static enum mhu_v3_x_error_t get_dev_base(const struct mhu_v3_x_dev_t *dev,
+ union _mhu_v3_x_frame_t **base)
+{
+ if (dev == NULL) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ /* Ensure driver has been initialized */
+ if (dev->is_initialized == false) {
+ return MHU_V_3_X_ERR_NOT_INIT;
+ }
+
+ *base = (union _mhu_v3_x_frame_t *)dev->base;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev)
+{
+ uint32_t aidr = 0;
+ uint8_t mhu_major_rev;
+ union _mhu_v3_x_frame_t *p_mhu;
+
+ if (dev == NULL) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ /* Return if already initialized */
+ if (dev->is_initialized == true) {
+ return MHU_V_3_X_ERR_NONE;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ /* Read revision from MHU hardware */
+ if (dev->frame == MHU_V3_X_PBX_FRAME) {
+ aidr = p_mhu->pbx_frame.pbx_ctrl_page.pbx_aidr;
+ } else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+ aidr = p_mhu->mbx_frame.mbx_ctrl_page.mbx_aidr;
+ } else {
+ /* Only PBX and MBX frames are supported. */
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ /* Read the MHU Architecture Major Revision */
+ mhu_major_rev =
+ ((aidr & MHU_ARCH_MAJOR_REV_MASK) >> MHU_ARCH_MAJOR_REV_OFF);
+
+ /* Return error if the MHU major revision is not 3 */
+ if (mhu_major_rev != MHU_MAJOR_REV_V3) {
+ /* Unsupported MHU version */
+ return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ /* Read the MHU Architecture Minor Revision */
+ dev->subversion =
+ ((aidr & MHU_ARCH_MINOR_REV_MASK) >> MHU_ARCH_MINOR_REV_MASK);
+
+ /* Return error if the MHU minor revision is not 0 */
+ if (dev->subversion != MHU_MINOR_REV_3_0) {
+ /* Unsupported subversion */
+ return MHU_V_3_X_ERR_UNSUPPORTED_VERSION;
+ }
+
+ /* Initialize the Postbox/Mailbox to remain in operational state */
+ if (dev->frame == MHU_V3_X_PBX_FRAME) {
+ p_mhu->pbx_frame.pbx_ctrl_page.pbx_ctrl |= MHU_V3_OP_REQ;
+ } else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+ p_mhu->mbx_frame.mbx_ctrl_page.mbx_ctrl |= MHU_V3_OP_REQ;
+ } else {
+ /* Only PBX and MBX frames are supported. */
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ dev->is_initialized = true;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
+ const struct mhu_v3_x_dev_t *dev,
+ enum mhu_v3_x_channel_type_t ch_type, uint8_t *num_ch)
+{
+ enum mhu_v3_x_error_t status;
+ union _mhu_v3_x_frame_t *p_mhu;
+
+ if (num_ch == NULL) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Only doorbell channel is supported */
+ if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ /* Read the number of channels implemented in the MHU */
+ if (dev->frame == MHU_V3_X_PBX_FRAME) {
+ *num_ch = (p_mhu->pbx_frame.pbx_ctrl_page.pbx_dbch_cfg0 + 1);
+ } else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+ *num_ch = (p_mhu->mbx_frame.mbx_ctrl_page.mbx_dbch_cfg0 + 1);
+ } else {
+ /* Only PBX and MBX frames are supported. */
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(const struct mhu_v3_x_dev_t *dev,
+ const uint32_t channel, uint32_t flags)
+{
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+ enum mhu_v3_x_error_t status;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Only MBX can clear the Doorbell channel */
+ if (dev->frame != MHU_V3_X_MBX_FRAME) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /* Clear the bits in the doorbell channel */
+ mdbcw_reg[channel].mdbcw_clr |= flags;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(const struct mhu_v3_x_dev_t *dev,
+ const uint32_t channel, uint32_t flags)
+{
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+ enum mhu_v3_x_error_t status;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Only PBX can set the Doorbell channel value */
+ if (dev->frame != MHU_V3_X_PBX_FRAME) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+ &(p_mhu->pbx_frame.pdbcw_page);
+
+ /* Write the value to the doorbell channel */
+ pdbcw_reg[channel].pdbcw_set |= flags;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(const struct mhu_v3_x_dev_t *dev,
+ const uint32_t channel, uint32_t *flags)
+{
+ union _mhu_v3_x_frame_t *p_mhu;
+ enum mhu_v3_x_error_t status;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+ struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+
+ if (flags == NULL) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ if (dev->frame == MHU_V3_X_PBX_FRAME) {
+ pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+ &(p_mhu->pbx_frame.pdbcw_page);
+
+ /* Read the value from Postbox Doorbell status register */
+ *flags = pdbcw_reg[channel].pdbcw_st;
+ } else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /* Read the value from Mailbox Doorbell status register */
+ *flags = mdbcw_reg[channel].mdbcw_st;
+ } else {
+ /* Only PBX and MBX frames are supported. */
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ uint32_t flags)
+{
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+ enum mhu_v3_x_error_t status;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Doorbell channel mask is not applicable for PBX */
+ if (dev->frame != MHU_V3_X_MBX_FRAME) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /* Set the Doorbell channel mask */
+ mdbcw_reg[channel].mdbcw_msk_set |= flags;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ uint32_t flags)
+{
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+ enum mhu_v3_x_error_t status;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Doorbell channel mask is not applicable for PBX */
+ if (dev->frame != MHU_V3_X_MBX_FRAME) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /* Clear the Doorbell channel mask */
+ mdbcw_reg[channel].mdbcw_msk_clr = flags;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ uint32_t *flags)
+{
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+ enum mhu_v3_x_error_t status;
+
+ if (flags == NULL) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Doorbell channel mask is not applicable for PBX */
+ if (dev->frame != MHU_V3_X_MBX_FRAME) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /* Save the Doorbell channel mask status */
+ *flags = mdbcw_reg[channel].mdbcw_msk_st;
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ enum mhu_v3_x_channel_type_t ch_type)
+{
+ enum mhu_v3_x_error_t status;
+
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Only doorbell channel is supported */
+ if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ if (dev->frame == MHU_V3_X_PBX_FRAME) {
+ pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+ &(p_mhu->pbx_frame.pdbcw_page);
+
+ /*
+ * Enable this doorbell channel to generate interrupts for
+ * transfer acknowledge events.
+ */
+ pdbcw_reg[channel].pdbcw_int_en = MHU_V3_X_PDBCW_INT_X_TFR_ACK;
+
+ /*
+ * Enable this doorbell channel to contribute to the PBX
+ * combined interrupt.
+ */
+ pdbcw_reg[channel].pdbcw_ctrl = MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN;
+ } else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /*
+ * Enable this doorbell channel to contribute to the MBX
+ * combined interrupt.
+ */
+ mdbcw_reg[channel].mdbcw_ctrl = MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN;
+ } else {
+ /* Only PBX and MBX frames are supported. */
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ enum mhu_v3_x_channel_type_t ch_type)
+{
+ enum mhu_v3_x_error_t status;
+
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+ struct _mhu_v3_x_mdbcw_reg_t *mdbcw_reg;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Only doorbell channel is supported */
+ if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+
+ if (dev->frame == MHU_V3_X_PBX_FRAME) {
+ pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)
+ &(p_mhu->pbx_frame.pdbcw_page);
+
+ /* Clear channel transfer acknowledge event interrupt */
+ pdbcw_reg[channel].pdbcw_int_clr = MHU_V3_X_PDBCW_INT_X_TFR_ACK;
+
+ /* Disable channel transfer acknowledge event interrupt */
+ pdbcw_reg[channel].pdbcw_int_en &=
+ ~(MHU_V3_X_PDBCW_INT_X_TFR_ACK);
+
+ /*
+ * Disable this doorbell channel from contributing to the PBX
+ * combined interrupt.
+ */
+ pdbcw_reg[channel].pdbcw_ctrl &=
+ ~(MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN);
+ } else if (dev->frame == MHU_V3_X_MBX_FRAME) {
+ mdbcw_reg = (struct _mhu_v3_x_mdbcw_reg_t *)
+ &(p_mhu->mbx_frame.mdbcw_page);
+
+ /*
+ * Disable this doorbell channel from contributing to the MBX
+ * combined interrupt.
+ */
+ mdbcw_reg[channel].mdbcw_ctrl &=
+ ~(MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN);
+ } else {
+ /* Only PBX and MBX frames are supported. */
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ return MHU_V_3_X_ERR_NONE;
+}
+
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ enum mhu_v3_x_channel_type_t ch_type)
+{
+ enum mhu_v3_x_error_t status;
+ union _mhu_v3_x_frame_t *p_mhu;
+ struct _mhu_v3_x_pdbcw_reg_t *pdbcw_reg;
+
+ /* Get dev->base if it is valid or return an error if dev is not */
+ status = get_dev_base(dev, &p_mhu);
+ if (status != MHU_V_3_X_ERR_NONE) {
+ return status;
+ }
+
+ /* Only doorbell channel is supported */
+ if (ch_type != MHU_V3_X_CHANNEL_TYPE_DBCH) {
+ return MHU_V_3_X_ERR_UNSUPPORTED;
+ }
+
+ /*
+ * Only postbox doorbell channel transfer acknowledge interrupt can be
+ * cleared manually.
+ *
+ * To clear MBX interrupt the unmasked status must be cleared using
+ * mhu_v3_x_doorbell_clear.
+ */
+ if (dev->frame != MHU_V3_X_PBX_FRAME) {
+ return MHU_V_3_X_ERR_INVALID_PARAM;
+ }
+
+ p_mhu = (union _mhu_v3_x_frame_t *)dev->base;
+ pdbcw_reg = (struct _mhu_v3_x_pdbcw_reg_t *)&(
+ p_mhu->pbx_frame.pdbcw_page);
+
+ /* Clear channel transfer acknowledge event interrupt */
+ pdbcw_reg[channel].pdbcw_int_clr |= 0x1;
+
+ return MHU_V_3_X_ERR_NONE;
+}
diff --git a/drivers/arm/mhu/mhu_v3_x.h b/drivers/arm/mhu/mhu_v3_x.h
new file mode 100644
index 0000000000..a3a19503b0
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v3_x.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_V3_X_H
+#define MHU_V3_X_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* MHU Architecture Major Revision 3 */
+#define MHU_MAJOR_REV_V3 U(0x2)
+/* MHU Architecture Minor Revision 0 */
+#define MHU_MINOR_REV_3_0 U(0x0)
+
+/* MHU Architecture Major Revision offset */
+#define MHU_ARCH_MAJOR_REV_OFF U(0x4)
+/* MHU Architecture Major Revision mask */
+#define MHU_ARCH_MAJOR_REV_MASK (U(0xf) << MHU_ARCH_MAJOR_REV_OFF)
+
+/* MHU Architecture Minor Revision offset */
+#define MHU_ARCH_MINOR_REV_OFF U(0x0)
+/* MHU Architecture Minor Revision mask */
+#define MHU_ARCH_MINOR_REV_MASK (U(0xf) << MHU_ARCH_MINOR_REV_OFF)
+
+/* MHUv3 PBX/MBX Operational Request offset */
+#define MHU_V3_OP_REQ_OFF U(0)
+/* MHUv3 PBX/MBX Operational Request */
+#define MHU_V3_OP_REQ (U(1) << MHU_V3_OP_REQ_OFF)
+
+/**
+ * MHUv3 error enumeration types
+ */
+enum mhu_v3_x_error_t {
+ /* No error */
+ MHU_V_3_X_ERR_NONE,
+ /* MHU driver not initialized */
+ MHU_V_3_X_ERR_NOT_INIT,
+ /* MHU driver alreary initialized */
+ MHU_V_3_X_ERR_ALREADY_INIT,
+ /* MHU Revision not supported error */
+ MHU_V_3_X_ERR_UNSUPPORTED_VERSION,
+ /* Operation not supported */
+ MHU_V_3_X_ERR_UNSUPPORTED,
+ /* Invalid parameter */
+ MHU_V_3_X_ERR_INVALID_PARAM,
+ /* General MHU driver error */
+ MHU_V_3_X_ERR_GENERAL,
+};
+
+/**
+ * MHUv3 channel types
+ */
+enum mhu_v3_x_channel_type_t {
+ /* Doorbell channel */
+ MHU_V3_X_CHANNEL_TYPE_DBCH,
+ /* Channel type count */
+ MHU_V3_X_CHANNEL_TYPE_COUNT,
+};
+
+/**
+ * MHUv3 frame types
+ */
+enum mhu_v3_x_frame_t {
+ /* MHUv3 postbox frame */
+ MHU_V3_X_PBX_FRAME,
+ /* MHUv3 mailbox frame */
+ MHU_V3_X_MBX_FRAME,
+};
+
+/**
+ * MHUv3 device structure
+ */
+struct mhu_v3_x_dev_t {
+ /* Base address of the MHUv3 frame */
+ uintptr_t base;
+ /* Type of the MHUv3 frame */
+ enum mhu_v3_x_frame_t frame;
+ /* Minor revision of the MHUv3 */
+ uint32_t subversion;
+ /* Flag to indicate if the MHUv3 is initialized */
+ bool is_initialized;
+};
+
+/**
+ * Initializes the MHUv3
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_driver_init(struct mhu_v3_x_dev_t *dev);
+
+/**
+ * Returns the number of channels implemented
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * ch_type MHU channel type mhu_v3_x_channel_type_t
+ * num_ch Pointer to the variable that will store the value
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_get_num_channel_implemented(
+ const struct mhu_v3_x_dev_t *dev, enum mhu_v3_x_channel_type_t ch_type,
+ uint8_t *num_ch);
+
+/**
+ * Clear flags from a doorbell channel
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * flags Flags to be cleared from the channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_clear(const struct mhu_v3_x_dev_t *dev,
+ const uint32_t channel, uint32_t flags);
+
+/**
+ * Write flags to a doorbell channel
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * flags Flags to be written to the channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_write(const struct mhu_v3_x_dev_t *dev,
+ const uint32_t channel, uint32_t flags);
+
+/**
+ * Read value from a doorbell channel
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * flags Pointer to the variable that will store the flags read from the
+ * channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_read(const struct mhu_v3_x_dev_t *dev,
+ const uint32_t channel, uint32_t *flags);
+
+/**
+ * Set bits in a doorbell channel mask which is used to disable interrupts for
+ * received flags corresponding to the mask
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * flags Flags to set mask bits in this doorbell channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_set(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ uint32_t flags);
+
+/**
+ * Clear bits in a doorbell channel mask which is used to disable interrupts
+ * for received flags corresponding to the mask
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * flags Flags to clear mask bits in this doorbell channel
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_clear(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel, uint32_t flags);
+
+/**
+ * Get the mask of a doorbell channel which is used to disable interrupts for
+ * received flags corresponding to the mask
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * flags Pointer to the variable that will store the flags read from the
+ * mask value
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_doorbell_mask_get(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel, uint32_t *flags);
+
+/**
+ * Enable the channel interrupt
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * ch_type MHU channel type mhu_v3_x_channel_type_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_enable(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ enum mhu_v3_x_channel_type_t ch_type);
+
+/**
+ * Disable the channel interrupt
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * ch_type MHU channel type mhu_v3_x_channel_type_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_disable(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ enum mhu_v3_x_channel_type_t ch_type);
+
+/**
+ * Clear the channel interrupt
+ *
+ * dev MHU device struct mhu_v3_x_dev_t
+ * channel Doorbell channel number
+ * ch_type MHU channel type mhu_v3_x_channel_type_t
+ *
+ * Returns mhu_v3_x_error_t error code
+ */
+enum mhu_v3_x_error_t mhu_v3_x_channel_interrupt_clear(
+ const struct mhu_v3_x_dev_t *dev, const uint32_t channel,
+ enum mhu_v3_x_channel_type_t ch_type);
+
+#endif /* MHU_V3_X_H */
diff --git a/drivers/arm/mhu/mhu_v3_x_private.h b/drivers/arm/mhu/mhu_v3_x_private.h
new file mode 100644
index 0000000000..9594a2a8dc
--- /dev/null
+++ b/drivers/arm/mhu/mhu_v3_x_private.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MHU_V3_X_PRIVATE_H
+#define MHU_V3_X_PRIVATE_H
+
+#include <stdint.h>
+
+/* Flag for PDBCW Interrupt Transfer Acknowledgment */
+#define MHU_V3_X_PDBCW_INT_X_TFR_ACK 0x1
+
+/* Flag for PDBCW CTRL Postbox combined interrupts enable */
+#define MHU_V3_X_PDBCW_CTRL_PBX_COMB_EN 0x1
+
+/* Flag for MDBCW CTRL Mailbox combined interrupts enable */
+#define MHU_V3_X_MDBCW_CTRL_MBX_COMB_EN 0x1
+
+/**
+ * Postbox control page structure
+ */
+struct _mhu_v3_x_pbx_ctrl_reg_t {
+ /* Offset: 0x000 (R/ ) Postbox Block Identifier */
+ const volatile uint32_t pbx_blk_id;
+ /* Offset: 0x004 (R/ ) Reserved */
+ const volatile uint8_t reserved_0[0x10 - 0x04];
+ /* Offset: 0x010 (R/ ) Postbox Feature Support 0 */
+ const volatile uint32_t pbx_feat_spt0;
+ /* Offset: 0x014 (R/ ) Postbox Feature Support 1 */
+ const volatile uint32_t pbx_feat_spt1;
+ /* Offset: 0x018 (R/ ) Reserved */
+ const volatile uint8_t reserved_1[0x20 - 0x18];
+ /* Offset: 0x020 (R/ ) Postbox Doorbell Channel Configuration 0 */
+ const volatile uint32_t pbx_dbch_cfg0;
+ /* Offset: 0x024 (R/ ) Reserved */
+ const volatile uint8_t reserved_2[0x30 - 0x24];
+ /* Offset: 0x030 (R/ ) Postbox FIFO Channel Configuration 0 */
+ const volatile uint32_t pbx_ffch_cfg0;
+ /* Offset: 0x034 (R/ ) Reserved */
+ const volatile uint8_t reserved_3[0x40 - 0x34];
+ /* Offset: 0x040 (R/ ) Postbox Fast Channel Configuration 0 */
+ const volatile uint32_t pbx_fch_cfg0;
+ /* Offset: 0x044 (R/ ) Reserved */
+ const volatile uint8_t reserved_4[0x100 - 0x44];
+ /* Offset: 0x100 (R/W) Postbox control */
+ volatile uint32_t pbx_ctrl;
+ /* Offset: 0x164 (R/ ) Reserved */
+ const volatile uint8_t reserved_5[0x400 - 0x104];
+ /*
+ * Offset: 0x400 (R/ ) Postbox Doorbell Channel Interrupt Status n,
+ * where n is 0 - 3.
+ */
+ const volatile uint32_t pbx_dbch_int_st[4];
+ /*
+ * Offset: 0x410 (R/ ) Postbox FIFO Channel <n> Interrupt Status n,
+ * where n is 0 - 1.
+ */
+ const volatile uint32_t pbx_ffch_int_st[2];
+ /* Offset: 0x418 (R/ ) Reserved */
+ const uint8_t reserved_6[0xFC8 - 0x418];
+ /* Offset: 0xFC8 (R/ ) Postbox Implementer Identification Register */
+ const volatile uint32_t pbx_iidr;
+ /* Offset: 0xFCC (R/ ) Postbox Architecture Identification Register */
+ const volatile uint32_t pbx_aidr;
+ /*
+ * Offset: 0xFD0 (R/ ) Postbox Implementation Defined Identification
+ * Register n, where n is 0 - 11.
+ */
+ const volatile uint32_t impl_def_id[12];
+};
+
+/**
+ * Postbox doorbell channel window page structure
+ */
+struct _mhu_v3_x_pdbcw_reg_t {
+ /* Offset: 0x000 (R/ ) Postbox Doorbell Channel Window Status */
+ const volatile uint32_t pdbcw_st;
+ /* Offset: 0x004 (R/ ) Reserved */
+ const uint8_t reserved_0[0xC - 0x4];
+ /* Offset: 0x00C ( /W) Postbox Doorbell Channel Window Set */
+ volatile uint32_t pdbcw_set;
+ /*
+ * Offset: 0x010 (R/ ) Postbox Doorbell Channel Window Interrupt Status
+ */
+ const volatile uint32_t pdbcw_int_st;
+ /*
+ * Offset: 0x014 ( /W) Postbox Doorbell Channel Window Interrupt Clear
+ */
+ volatile uint32_t pdbcw_int_clr;
+ /*
+ * Offset: 0x018 (R/W) Postbox Doorbell Channel Window Interrupt Enable
+ */
+ volatile uint32_t pdbcw_int_en;
+ /* Offset: 0x01C (R/W) Postbox Doorbell Channel Window Control */
+ volatile uint32_t pdbcw_ctrl;
+};
+
+/**
+ * Postbox structure
+ */
+struct _mhu_v3_x_pbx {
+ /* Postbox Control */
+ struct _mhu_v3_x_pbx_ctrl_reg_t pbx_ctrl_page;
+ /* Postbox Doorbell Channel Window */
+ struct _mhu_v3_x_pdbcw_reg_t pdbcw_page;
+};
+
+/**
+ * Mailbox control page structure
+ */
+struct _mhu_v3_x_mbx_ctrl_reg_t {
+ /* Offset: 0x000 (R/ ) Mailbox Block Identifier */
+ const volatile uint32_t mbx_blk_id;
+ /* Offset: 0x004 (R/ ) Reserved */
+ const volatile uint8_t reserved_0[0x10 - 0x04];
+ /* Offset: 0x010 (R/ ) Mailbox Feature Support 0 */
+ const volatile uint32_t mbx_feat_spt0;
+ /* Offset: 0x014 (R/ ) Mailbox Feature Support 1 */
+ const volatile uint32_t mbx_feat_spt1;
+ /* Offset: 0x018 (R/ ) Reserved */
+ const volatile uint8_t reserved_1[0x20 - 0x18];
+ /* Offset: 0x020 (R/ ) Mailbox Doorbell Channel Configuration 0 */
+ const volatile uint32_t mbx_dbch_cfg0;
+ /* Offset: 0x024 (R/ ) Reserved */
+ const volatile uint8_t reserved_2[0x30 - 0x24];
+ /* Offset: 0x030 (R/ ) Mailbox FIFO Channel Configuration 0 */
+ const volatile uint32_t mbx_ffch_cfg0;
+ /* Offset: 0x034 (R/ ) Reserved */
+ const volatile uint8_t reserved_4[0x40 - 0x34];
+ /* Offset: 0x040 (R/ ) Mailbox Fast Channel Configuration 0 */
+ const volatile uint32_t mbx_fch_cfg0;
+ /* Offset: 0x044 (R/ ) Reserved */
+ const volatile uint8_t reserved_5[0x100 - 0x44];
+ /* Offset: 0x100 (R/W) Mailbox control */
+ volatile uint32_t mbx_ctrl;
+ /* Offset: 0x104 (R/ ) Reserved */
+ const volatile uint8_t reserved_6[0x140 - 0x104];
+ /* Offset: 0x140 (R/W) Mailbox Fast Channel control */
+ volatile uint32_t mbx_fch_ctrl;
+ /* Offset: 0x144 (R/W) Mailbox Fast Channel Group Interrupt Enable */
+ volatile uint32_t mbx_fcg_int_en;
+ /* Offset: 0x148 (R/ ) Reserved */
+ const volatile uint8_t reserved_7[0x400 - 0x148];
+ /*
+ * Offset: 0x400 (R/ ) Mailbox Doorbell Channel Interrupt Status n,
+ * where n = 0 - 3.
+ */
+ const volatile uint32_t mbx_dbch_int_st[4];
+ /*
+ * Offset: 0x410 (R/ ) Mailbox FIFO Channel Interrupt Status n, where
+ * n = 0 - 1.
+ */
+ const volatile uint32_t mbx_ffch_int_st[2];
+ /* Offset: 0x418 (R/ ) Reserved */
+ const volatile uint8_t reserved_8[0x470 - 0x418];
+ /* Offset: 0x470 (R/ ) Mailbox Fast Channel Group Interrupt Status */
+ const volatile uint32_t mbx_fcg_int_st;
+ /* Offset: 0x474 (R/ ) Reserved */
+ const volatile uint8_t reserved_9[0x480 - 0x474];
+ /*
+ * Offset: 0x480 (R/ ) Mailbox Fast Channel Group <n> Interrupt Status,
+ * where n = 0 - 31.
+ */
+ const volatile uint32_t mbx_fch_grp_int_st[32];
+ /* Offset: 0x500 (R/ ) Reserved */
+ const volatile uint8_t reserved_10[0xFC8 - 0x500];
+ /* Offset: 0xFC8 (R/ ) Mailbox Implementer Identification Register */
+ const volatile uint32_t mbx_iidr;
+ /* Offset: 0xFCC (R/ ) Mailbox Architecture Identification Register */
+ const volatile uint32_t mbx_aidr;
+ /*
+ * Offset: 0xFD0 (R/ ) Mailbox Implementation Defined Identification
+ * Register n, where n is 0 - 11.
+ */
+ const volatile uint32_t impl_def_id[12];
+};
+
+/**
+ * Mailbox doorbell channel window page structure
+ */
+struct _mhu_v3_x_mdbcw_reg_t {
+ /* Offset: 0x000 (R/ ) Mailbox Doorbell Channel Window Status */
+ const volatile uint32_t mdbcw_st;
+ /* Offset: 0x004 (R/ ) Mailbox Doorbell Channel Window Status Masked */
+ const volatile uint32_t mdbcw_st_msk;
+ /* Offset: 0x008 ( /W) Mailbox Doorbell Channel Window Clear */
+ volatile uint32_t mdbcw_clr;
+ /* Offset: 0x00C (R/ ) Reserved */
+ const volatile uint8_t reserved_0[0x10 - 0x0C];
+ /* Offset: 0x010 (R/ ) Mailbox Doorbell Channel Window Mask Status */
+ const volatile uint32_t mdbcw_msk_st;
+ /* Offset: 0x014 ( /W) Mailbox Doorbell Channel Window Mask Set */
+ volatile uint32_t mdbcw_msk_set;
+ /* Offset: 0x018 ( /W) Mailbox Doorbell Channel Window Mask Clear */
+ volatile uint32_t mdbcw_msk_clr;
+ /* Offset: 0x01C (R/W) Mailbox Doorbell Channel Window Control */
+ volatile uint32_t mdbcw_ctrl;
+};
+
+/**
+ * Mailbox structure
+ */
+struct _mhu_v3_x_mbx {
+ /* Mailbox control */
+ struct _mhu_v3_x_mbx_ctrl_reg_t mbx_ctrl_page;
+ /* Mailbox Doorbell Channel Window */
+ struct _mhu_v3_x_mdbcw_reg_t mdbcw_page;
+};
+
+/**
+ * MHUv3 frame type
+ */
+union _mhu_v3_x_frame_t {
+ /* Postbox Frame */
+ struct _mhu_v3_x_pbx pbx_frame;
+ /* Mailbox Frame */
+ struct _mhu_v3_x_mbx mbx_frame;
+};
+
+#endif /* MHU_V3_X_PRIVATE_H */
diff --git a/drivers/arm/mhu/mhu_wrapper_v2_x.c b/drivers/arm/mhu/mhu_wrapper_v2_x.c
new file mode 100644
index 0000000000..54a5881267
--- /dev/null
+++ b/drivers/arm/mhu/mhu_wrapper_v2_x.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/arm/mhu.h>
+
+#include "mhu_v2_x.h"
+
+#define MHU_NOTIFY_VALUE (1234u)
+
+/*
+ * MHU devices for host:
+ * HSE: Host to Secure Enclave (sender device)
+ * SEH: Secure Enclave to Host (receiver device)
+ */
+struct mhu_v2_x_dev_t MHU1_HSE_DEV = {0, MHU_V2_X_SENDER_FRAME};
+struct mhu_v2_x_dev_t MHU1_SEH_DEV = {0, MHU_V2_X_RECEIVER_FRAME};
+
+static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err)
+{
+ switch (err) {
+ case MHU_V_2_X_ERR_NONE:
+ return MHU_ERR_NONE;
+ case MHU_V_2_X_ERR_NOT_INIT:
+ return MHU_ERR_NOT_INIT;
+ case MHU_V_2_X_ERR_ALREADY_INIT:
+ return MHU_ERR_ALREADY_INIT;
+ case MHU_V_2_X_ERR_UNSUPPORTED_VERSION:
+ return MHU_ERR_UNSUPPORTED_VERSION;
+ case MHU_V_2_X_ERR_INVALID_ARG:
+ return MHU_ERR_INVALID_ARG;
+ case MHU_V_2_X_ERR_GENERAL:
+ return MHU_ERR_GENERAL;
+ default:
+ return MHU_ERR_GENERAL;
+ }
+}
+
+static enum mhu_v2_x_error_t signal_and_wait_for_clear(void)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV;
+ uint32_t val = MHU_NOTIFY_VALUE;
+ /* Using the last channel for notifications */
+ uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+ err = mhu_v2_x_channel_send(dev, channel_notify, val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return err;
+ }
+
+ do {
+ err = mhu_v2_x_channel_poll(dev, channel_notify, &val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (val != 0);
+
+ return err;
+}
+
+static enum mhu_v2_x_error_t wait_for_signal(void)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t val = 0;
+ /* Using the last channel for notifications */
+ uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+ do {
+ err = mhu_v2_x_channel_receive(dev, channel_notify, &val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (val != MHU_NOTIFY_VALUE);
+
+ return err;
+}
+
+static enum mhu_v2_x_error_t clear_and_wait_for_next_signal(void)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ uint32_t i;
+
+ /* Clear all channels */
+ for (i = 0; i < num_channels; ++i) {
+ err = mhu_v2_x_channel_clear(dev, i);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return err;
+ }
+ }
+
+ return wait_for_signal();
+}
+
+enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base)
+{
+ enum mhu_v2_x_error_t err;
+
+ assert(mhu_sender_base != (uintptr_t)NULL);
+
+ MHU1_HSE_DEV.base = mhu_sender_base;
+
+ err = mhu_v2_x_driver_init(&MHU1_HSE_DEV, MHU_REV_READ_FROM_HW);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base)
+{
+ enum mhu_v2_x_error_t err;
+ uint32_t num_channels, i;
+
+ assert(mhu_receiver_base != (uintptr_t)NULL);
+
+ MHU1_SEH_DEV.base = mhu_receiver_base;
+
+ err = mhu_v2_x_driver_init(&MHU1_SEH_DEV, MHU_REV_READ_FROM_HW);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(&MHU1_SEH_DEV);
+
+ /* Mask all channels except the notifying channel */
+ for (i = 0; i < (num_channels - 1); ++i) {
+ err = mhu_v2_x_channel_mask_set(&MHU1_SEH_DEV, i, UINT32_MAX);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ /* The last channel is used for notifications */
+ err = mhu_v2_x_channel_mask_clear(
+ &MHU1_SEH_DEV, (num_channels - 1), UINT32_MAX);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of transferring a message:
+ * 1. Initiate MHU transfer.
+ * 2. Send over the size of the payload on Channel 1. It is the very first
+ * 4 Bytes of the transfer. Continue with Channel 2.
+ * 3. Send over the payload, writing the channels one after the other
+ * (4 Bytes each). The last available channel is reserved for controlling
+ * the transfer.
+ * When the last channel is reached or no more data is left, STOP.
+ * 4. Notify the receiver using the last channel and wait for acknowledge.
+ * If there is still data to transfer, jump to step 3. Otherwise, proceed.
+ * 5. Close MHU transfer.
+ *
+ */
+enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ uint32_t chan = 0;
+ uint32_t i;
+ uint32_t *p;
+
+ /* For simplicity, require the send_buffer to be 4-byte aligned */
+ if ((uintptr_t)send_buffer & 0x3U) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v2_x_initiate_transfer(dev);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* First send over the size of the actual message */
+ err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan++;
+
+ p = (uint32_t *)send_buffer;
+ for (i = 0; i < size; i += 4) {
+ err = mhu_v2_x_channel_send(dev, chan, *p++);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ if (++chan == (num_channels - 1)) {
+ err = signal_and_wait_for_clear();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan = 0;
+ }
+ }
+
+ /* Signal the end of transfer.
+ * It's not required to send a signal when the message was
+ * perfectly-aligned (num_channels - 1 channels were used in the last
+ * round) preventing it from signaling twice at the end of transfer.
+ */
+ if (chan != 0) {
+ err = signal_and_wait_for_clear();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ err = mhu_v2_x_close_transfer(dev);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of receiving a message:
+ * 1. Read the size of the payload from Channel 1. It is the very first
+ * 4 Bytes of the transfer. Continue with Channel 2.
+ * 2. Receive the payload, read the channels one after the other
+ * (4 Bytes each). The last available channel is reserved for controlling
+ * the transfer.
+ * When the last channel is reached clear all the channels
+ * (also sending an acknowledge on the last channel).
+ * 3. If there is still data to receive wait for a notification on the last
+ * channel and jump to step 2 as soon as it arrived. Otherwise, proceed.
+ * 4. End of transfer.
+ *
+ */
+enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ uint32_t chan = 0;
+ uint32_t message_len;
+ uint32_t i;
+ uint32_t *p;
+
+ /* For simplicity, require:
+ * - the receive_buffer to be 4-byte aligned,
+ * - the buffer size to be a multiple of 4.
+ */
+ if (((uintptr_t)receive_buffer & 0x3U) || (*size & 0x3U)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ /* Busy wait for incoming reply */
+ err = wait_for_signal();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* The first word is the length of the actual message */
+ err = mhu_v2_x_channel_receive(dev, chan, &message_len);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan++;
+
+ if (message_len > *size) {
+ /* Message buffer too small */
+ *size = message_len;
+ return MHU_ERR_BUFFER_TOO_SMALL;
+ }
+
+ p = (uint32_t *)receive_buffer;
+ for (i = 0; i < message_len; i += 4) {
+ err = mhu_v2_x_channel_receive(dev, chan, p++);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Only wait for next transfer if there is still missing data */
+ if (++chan == (num_channels - 1) && (message_len - i) > 4) {
+ /* Busy wait for next transfer */
+ err = clear_and_wait_for_next_signal();
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan = 0;
+ }
+ }
+
+ /* Clear all channels */
+ for (i = 0; i < num_channels; ++i) {
+ err = mhu_v2_x_channel_clear(dev, i);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ *size = message_len;
+
+ return MHU_ERR_NONE;
+}
+
+size_t mhu_get_max_message_size(void)
+{
+ struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
+ uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+
+ assert(num_channels != 0);
+
+ /*
+ * Returns only usable size of memory. As one channel is specifically
+ * used to inform about the size of payload, discard it from avialable
+ * memory size.
+ */
+ return (num_channels - 1) * sizeof(uint32_t);
+}
diff --git a/drivers/arm/mhu/mhu_wrapper_v3_x.c b/drivers/arm/mhu/mhu_wrapper_v3_x.c
new file mode 100644
index 0000000000..b3d51e3bf7
--- /dev/null
+++ b/drivers/arm/mhu/mhu_wrapper_v3_x.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/arm/mhu.h>
+
+#include "mhu_v3_x.h"
+
+#define MHU_NOTIFY_VALUE U(1234)
+
+#ifndef ALIGN_UP
+#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
+#endif
+
+/*
+ * MHUv3 Wrapper utility macros
+ */
+#define IS_ALIGNED(val, align) (val == ALIGN_UP(val, align))
+
+/*
+ * MHU devices for host:
+ * HSE: Host to Secure Enclave (sender device)
+ * SEH: Secure Enclave to Host (receiver device)
+ */
+struct mhu_v3_x_dev_t mhu_hse_dev = {0, MHU_V3_X_PBX_FRAME};
+struct mhu_v3_x_dev_t mhu_seh_dev = {0, MHU_V3_X_MBX_FRAME};
+
+/* MHUv3 driver error to MHUv3 wrapper error mapping */
+static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v3_x_error_t err)
+{
+ switch (err) {
+ case MHU_V_3_X_ERR_NONE:
+ return MHU_ERR_NONE;
+
+ case MHU_V_3_X_ERR_NOT_INIT:
+ return MHU_ERR_NOT_INIT;
+
+ case MHU_V_3_X_ERR_UNSUPPORTED_VERSION:
+ return MHU_ERR_UNSUPPORTED_VERSION;
+
+ case MHU_V_3_X_ERR_UNSUPPORTED:
+ return MHU_ERR_UNSUPPORTED;
+
+ case MHU_V_3_X_ERR_INVALID_PARAM:
+ return MHU_ERR_INVALID_ARG;
+
+ default:
+ return MHU_ERR_GENERAL;
+ }
+}
+
+static enum mhu_error_t signal_and_wait_for_clear(
+ void *mhu_sender_dev, uint32_t value)
+{
+ enum mhu_v3_x_error_t err;
+ struct mhu_v3_x_dev_t *dev;
+ uint8_t num_channels;
+ uint32_t read_val;
+
+ dev = (struct mhu_v3_x_dev_t *)mhu_sender_dev;
+
+ if ((dev == NULL) || (dev->base == 0)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v3_x_get_num_channel_implemented(dev,
+ MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Wait for any pending acknowledgment from transmitter side */
+ do {
+ err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ } while ((read_val & value) == value);
+
+ /* Use the last channel to notify that a transfer is ready */
+ err = mhu_v3_x_doorbell_write(dev, num_channels - 1, value);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Wait until receiver side acknowledges the transfer */
+ do {
+ err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ } while ((read_val & value) == value);
+
+ return error_mapping_to_mhu_error_t(MHU_V_3_X_ERR_NONE);
+}
+
+static enum mhu_error_t wait_for_signal(
+ void *mhu_receiver_dev, uint32_t value)
+{
+ enum mhu_v3_x_error_t err;
+ struct mhu_v3_x_dev_t *dev;
+ uint32_t read_val;
+ uint8_t num_channels;
+
+ dev = (struct mhu_v3_x_dev_t *)mhu_receiver_dev;
+
+ if ((dev == NULL) || (dev->base == 0)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v3_x_get_num_channel_implemented(dev,
+ MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ do {
+ err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ } while (read_val != value);
+
+ return error_mapping_to_mhu_error_t(err);
+}
+
+static enum mhu_error_t clear_and_wait_for_signal(
+ void *mhu_receiver_dev, uint32_t value)
+{
+ enum mhu_v3_x_error_t err;
+ struct mhu_v3_x_dev_t *dev;
+ uint8_t num_channels;
+
+ dev = (struct mhu_v3_x_dev_t *)mhu_receiver_dev;
+
+ if ((dev == NULL) || (dev->base == 0)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v3_x_get_num_channel_implemented(dev,
+ MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Clear all channels */
+ for (int i = 0; i < num_channels; i++) {
+ err = mhu_v3_x_doorbell_clear(dev, i, UINT32_MAX);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ return wait_for_signal(mhu_receiver_dev, value);
+}
+
+static enum mhu_error_t validate_buffer_params(uintptr_t buf_addr)
+{
+ if ((buf_addr == 0) || (!IS_ALIGNED(buf_addr, sizeof(uint32_t)))) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base)
+{
+ enum mhu_v3_x_error_t err;
+ struct mhu_v3_x_dev_t *dev;
+ uint8_t num_ch;
+ uint32_t ch;
+
+ assert(mhu_sender_base != (uintptr_t)NULL);
+
+ mhu_hse_dev.base = mhu_sender_base;
+ dev = (struct mhu_v3_x_dev_t *)&mhu_hse_dev;
+
+ /* Initialize MHUv3 */
+ err = mhu_v3_x_driver_init(dev);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Read the number of doorbell channels implemented in the MHU */
+ err = mhu_v3_x_get_num_channel_implemented(
+ dev, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ } else if (num_ch < 2) {
+ /* This wrapper requires at least two channels implemented */
+ return MHU_ERR_UNSUPPORTED;
+ }
+
+ /*
+ * The sender polls the postbox doorbell channel window status register
+ * to get notified about successful transfer. So, disable the doorbell
+ * channel's contribution to postbox combined interrupt.
+ *
+ * Also, clear and disable the postbox doorbell channel transfer
+ * acknowledge interrupt.
+ */
+ for (ch = 0; ch < num_ch; ch++) {
+ err = mhu_v3_x_channel_interrupt_disable(
+ dev, ch, MHU_V3_X_CHANNEL_TYPE_DBCH);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base)
+{
+ enum mhu_v3_x_error_t err;
+ struct mhu_v3_x_dev_t *dev;
+ uint32_t ch;
+ uint8_t num_ch;
+
+ assert(mhu_receiver_base != (uintptr_t)NULL);
+
+ mhu_seh_dev.base = mhu_receiver_base;
+ dev = (struct mhu_v3_x_dev_t *)&mhu_seh_dev;
+
+ /* Initialize MHUv3 */
+ err = mhu_v3_x_driver_init(dev);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Read the number of doorbell channels implemented in the MHU */
+ err = mhu_v3_x_get_num_channel_implemented(
+ dev, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ } else if (num_ch < 2) {
+ /* This wrapper requires at least two channels implemented */
+ return MHU_ERR_UNSUPPORTED;
+ }
+
+ /* Mask all channels except the notifying channel */
+ for (ch = 0; ch < (num_ch - 1); ch++) {
+ /* Mask interrupts on channels used for data */
+ err = mhu_v3_x_doorbell_mask_set(dev, ch, UINT32_MAX);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ /* Unmask doorbell notification channel interrupt */
+ err = mhu_v3_x_doorbell_mask_clear(dev, (num_ch - 1), UINT32_MAX);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /*
+ * Enable the doorbell channel's contribution to mailbox combined
+ * interrupt.
+ */
+ err = mhu_v3_x_channel_interrupt_enable(dev, (num_ch - 1),
+ MHU_V3_X_CHANNEL_TYPE_DBCH);
+ if (err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ return MHU_ERR_NONE;
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of transferring a message:
+ * 1. Send the size of the payload on Channel 0. It is the very first Bytes of
+ * the transfer. Continue with Channel 1.
+ * 2. Send the payload, writing the channels one after the other (4 Bytes
+ * each). The last available channel is reserved for controlling the
+ * transfer. When the last channel is reached or no more data is left, STOP.
+ * 3. Notify the receiver using the last channel and wait for acknowledge. If
+ * there is still data to transfer, jump to step 2. Otherwise, proceed.
+ *
+ */
+enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size)
+{
+ enum mhu_error_t mhu_err;
+ enum mhu_v3_x_error_t mhu_v3_err;
+ uint8_t num_channels;
+ uint8_t chan;
+ uint32_t *buffer;
+ struct mhu_v3_x_dev_t *dev;
+
+ if (size == 0) {
+ return MHU_ERR_NONE;
+ }
+
+ dev = (struct mhu_v3_x_dev_t *)&mhu_hse_dev;
+ chan = 0;
+
+ if ((dev == NULL) || (dev->base == 0)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ mhu_err = validate_buffer_params((uintptr_t)send_buffer);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+
+ mhu_v3_err = mhu_v3_x_get_num_channel_implemented(dev,
+ MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+
+ /* First send the size of the actual message. */
+ mhu_v3_err = mhu_v3_x_doorbell_write(dev, chan, (uint32_t)size);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+ chan++;
+
+ buffer = (uint32_t *)send_buffer;
+ for (size_t i = 0; i < size; i += 4) {
+ mhu_v3_err = mhu_v3_x_doorbell_write(dev, chan, *buffer++);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+
+ if (++chan == (num_channels - 1)) {
+ /* Use the last channel to notify transfer complete */
+ mhu_err = signal_and_wait_for_clear(
+ dev, MHU_NOTIFY_VALUE);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+ chan = 0;
+ }
+ }
+
+ if (chan != 0) {
+ /* Use the last channel to notify transfer complete */
+ mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+ }
+
+ return MHU_ERR_NONE;
+}
+
+/*
+ * Public function. See mhu.h
+ *
+ * The basic steps of receiving a message:
+ * 1. Read the size of the payload from Channel 0. It is the very first
+ * 4 Bytes of the transfer. Continue with Channel 1.
+ * 2. Receive the payload, read the channels one after the other
+ * (4 Bytes each). The last available channel is reserved for controlling
+ * the transfer.
+ * When the last channel is reached clear all the channels
+ * (also sending an acknowledge on the last channel).
+ * 3. If there is still data to receive wait for a notification on the last
+ * channel and jump to step 2 as soon as it arrived. Otherwise, proceed.
+ *
+ */
+enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size)
+{
+ enum mhu_error_t mhu_err;
+ enum mhu_v3_x_error_t mhu_v3_err;
+ uint32_t msg_len;
+ uint8_t num_channels;
+ uint8_t chan;
+ uint32_t *buffer;
+ struct mhu_v3_x_dev_t *dev;
+
+ dev = (struct mhu_v3_x_dev_t *)&mhu_seh_dev;
+ chan = 0;
+
+ mhu_err = validate_buffer_params((uintptr_t)receive_buffer);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+
+ mhu_v3_err = mhu_v3_x_get_num_channel_implemented(dev,
+ MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+
+ /* Busy wait for incoming reply */
+ mhu_err = wait_for_signal(dev, MHU_NOTIFY_VALUE);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+
+ /* The first word is the length of the actual message. */
+ mhu_v3_err = mhu_v3_x_doorbell_read(dev, chan, &msg_len);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+ chan++;
+
+ if (*size < msg_len) {
+ /* Message buffer too small */
+ *size = msg_len;
+ return MHU_ERR_BUFFER_TOO_SMALL;
+ }
+
+ buffer = (uint32_t *)receive_buffer;
+ for (size_t i = 0; i < msg_len; i += 4) {
+ mhu_v3_err = mhu_v3_x_doorbell_read(dev, chan, buffer++);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+
+ /* Only wait for next transfer if still missing data. */
+ if (++chan == (num_channels - 1) && (msg_len - i) > 4) {
+ /* Busy wait for next transfer */
+ mhu_err = clear_and_wait_for_signal(
+ dev, MHU_NOTIFY_VALUE);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+ chan = 0;
+ }
+ }
+
+ /* Clear all channels */
+ for (uint8_t i = U(0); i < num_channels; i++) {
+ mhu_v3_err = mhu_v3_x_doorbell_clear(dev, i, UINT32_MAX);
+ if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(mhu_v3_err);
+ }
+ }
+
+ *size = msg_len;
+
+ return MHU_ERR_NONE;
+}
+
+size_t mhu_get_max_message_size(void)
+{
+ enum mhu_v3_x_error_t err;
+ uint8_t num_channels;
+
+ err = mhu_v3_x_get_num_channel_implemented(&mhu_seh_dev,
+ MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels);
+
+ assert(err == MHU_V_3_X_ERR_NONE);
+ assert(num_channels != U(0));
+ /*
+ * Returns only usable size of memory. As one channel is specifically
+ * used to inform about the size of payload, discard it from available
+ * memory size.
+ */
+ return (num_channels - 1) * sizeof(uint32_t);
+}
diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S
index 9caeb0c692..b7d1747f50 100644
--- a/drivers/arm/pl011/aarch32/pl011_console.S
+++ b/drivers/arm/pl011/aarch32/pl011_console.S
@@ -116,7 +116,7 @@ func console_pl011_register
mov r0, r4
pop {r4, lr}
- finish_console_register pl011 putc=1, getc=1, flush=1
+ finish_console_register pl011 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
pop {r4, pc}
diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
index 861d2ed22d..8cb0122bec 100644
--- a/drivers/arm/pl011/aarch64/pl011_console.S
+++ b/drivers/arm/pl011/aarch64/pl011_console.S
@@ -103,7 +103,7 @@ func console_pl011_register
mov x0, x6
mov x30, x7
- finish_console_register pl011 putc=1, getc=1, flush=1
+ finish_console_register pl011 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
ret x7
diff --git a/drivers/arm/rss/rss_comms.c b/drivers/arm/rss/rss_comms.c
new file mode 100644
index 0000000000..332105fda5
--- /dev/null
+++ b/drivers/arm/rss/rss_comms.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/arm/mhu.h>
+#include <drivers/arm/rss_comms.h>
+#include <psa/client.h>
+#include <rss_comms_protocol.h>
+
+/* Union as message space and reply space are never used at the same time, and this saves space as
+ * we can overlap them.
+ */
+union __packed __attribute__((aligned(4))) rss_comms_io_buffer_t {
+ struct serialized_rss_comms_msg_t msg;
+ struct serialized_rss_comms_reply_t reply;
+};
+
+static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
+ const psa_outvec *out_vec, size_t out_len)
+{
+ size_t comms_mhu_msg_size;
+ size_t comms_embed_msg_min_size;
+ size_t comms_embed_reply_min_size;
+ size_t in_size_total = 0;
+ size_t out_size_total = 0;
+ size_t i;
+
+ for (i = 0U; i < in_len; ++i) {
+ in_size_total += in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ out_size_total += out_vec[i].len;
+ }
+
+ comms_mhu_msg_size = mhu_get_max_message_size();
+
+ comms_embed_msg_min_size = sizeof(struct serialized_rss_comms_header_t) +
+ sizeof(struct rss_embed_msg_t) -
+ PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+ comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) +
+ sizeof(struct rss_embed_reply_t) -
+ PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+ /* Use embed if we can pack into one message and reply, else use
+ * pointer_access. The underlying MHU transport protocol uses a
+ * single uint32_t to track the length, so the amount of data that
+ * can be in a message is 4 bytes less than mhu_get_max_message_size
+ * reports.
+ *
+ * TODO tune this with real performance numbers, it's possible a
+ * pointer_access message is less performant than multiple embed
+ * messages due to ATU configuration costs to allow access to the
+ * pointers.
+ */
+ if ((comms_embed_msg_min_size + in_size_total >
+ comms_mhu_msg_size - sizeof(uint32_t)) ||
+ (comms_embed_reply_min_size + out_size_total >
+ comms_mhu_msg_size - sizeof(uint32_t))) {
+ return RSS_COMMS_PROTOCOL_POINTER_ACCESS;
+ } else {
+ return RSS_COMMS_PROTOCOL_EMBED;
+ }
+}
+
+psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
+ * functions not being reentrant becomes a problem.
+ */
+ static union rss_comms_io_buffer_t io_buf;
+ enum mhu_error_t err;
+ psa_status_t status;
+ static uint8_t seq_num = 1U;
+ size_t msg_size;
+ size_t reply_size = sizeof(io_buf.reply);
+ psa_status_t return_val;
+ size_t idx;
+
+ if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN ||
+ in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ io_buf.msg.header.seq_num = seq_num,
+ /* No need to distinguish callers (currently concurrent calls are not supported). */
+ io_buf.msg.header.client_id = 1U,
+ io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
+
+ status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
+ out_len, &io_buf.msg, &msg_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ VERBOSE("[RSS-COMMS] Sending message\n");
+ VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
+ VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
+ VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
+ for (idx = 0; idx < in_len; idx++) {
+ VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
+ VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
+ }
+
+ err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
+ if (err != MHU_ERR_NONE) {
+ return PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+#if DEBUG
+ /*
+ * Poisoning the message buffer (with a known pattern).
+ * Helps in detecting hypothetical RSS communication bugs.
+ */
+ memset(&io_buf.msg, 0xA5, msg_size);
+#endif
+
+ err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
+ if (err != MHU_ERR_NONE) {
+ return PSA_ERROR_COMMUNICATION_FAILURE;
+ }
+
+ VERBOSE("[RSS-COMMS] Received reply\n");
+ VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
+ VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
+ VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
+
+ status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val,
+ &io_buf.reply, reply_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ VERBOSE("return_val=%d\n", return_val);
+ for (idx = 0U; idx < out_len; idx++) {
+ VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
+ VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
+ }
+
+ /* Clear the MHU message buffer to remove assets from memory */
+ memset(&io_buf, 0x0, sizeof(io_buf));
+
+ seq_num++;
+
+ return return_val;
+}
+
+int rss_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
+{
+ enum mhu_error_t err;
+
+ err = mhu_init_sender(mhu_sender_base);
+ if (err != MHU_ERR_NONE) {
+ if (err == MHU_ERR_ALREADY_INIT) {
+ INFO("[RSS-COMMS] Host to RSS MHU driver already initialized\n");
+ } else {
+ ERROR("[RSS-COMMS] Host to RSS MHU driver initialization failed: %d\n", err);
+ return -1;
+ }
+ }
+
+ err = mhu_init_receiver(mhu_receiver_base);
+ if (err != MHU_ERR_NONE) {
+ if (err == MHU_ERR_ALREADY_INIT) {
+ INFO("[RSS-COMMS] RSS to Host MHU driver already initialized\n");
+ } else {
+ ERROR("[RSS-COMMS] RSS to Host MHU driver initialization failed: %d\n", err);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/arm/rss/rss_comms.mk b/drivers/arm/rss/rss_comms.mk
new file mode 100644
index 0000000000..0d1e308751
--- /dev/null
+++ b/drivers/arm/rss/rss_comms.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+$(warning "RSS driver is an experimental feature")
+
+RSS_COMMS_SOURCES := $(addprefix drivers/arm/rss/, \
+ rss_comms.c \
+ rss_comms_protocol.c \
+ rss_comms_protocol_embed.c \
+ rss_comms_protocol_pointer_access.c \
+ )
+
+# Default to MHUv2 if PLAT_MHU_VERSION undefined
+PLAT_MHU_VERSION ?= 2
+
+ifeq (${PLAT_MHU_VERSION}, 3)
+RSS_COMMS_SOURCES += $(addprefix drivers/arm/mhu/, \
+ mhu_v3_x.c \
+ mhu_wrapper_v3_x.c \
+ )
+else ifeq (${PLAT_MHU_VERSION}, 2)
+RSS_COMMS_SOURCES += $(addprefix drivers/arm/mhu/, \
+ mhu_v2_x.c \
+ mhu_wrapper_v2_x.c \
+ )
+else
+$(error Unsupported MHU version)
+endif
+
+PLAT_INCLUDES += -Idrivers/arm/rss \
+ -Idrivers/arm/mhu
diff --git a/drivers/arm/rss/rss_comms_protocol.c b/drivers/arm/rss/rss_comms_protocol.c
new file mode 100644
index 0000000000..a1b1b58cb0
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include "rss_comms_protocol.h"
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct serialized_rss_comms_msg_t *msg,
+ size_t *msg_len)
+{
+ psa_status_t status;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ switch (msg->header.protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ status = rss_protocol_embed_serialize_msg(handle, type, in_vec, in_len, out_vec,
+ out_len, &msg->msg.embed, msg_len);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ status = rss_protocol_pointer_access_serialize_msg(handle, type, in_vec, in_len,
+ out_vec, out_len,
+ &msg->msg.pointer_access,
+ msg_len);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ *msg_len += sizeof(struct serialized_rss_comms_header_t);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct serialized_rss_comms_reply_t *reply,
+ size_t reply_size)
+{
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ switch (reply->header.protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ return rss_protocol_embed_deserialize_reply(out_vec, out_len, return_val,
+ &reply->reply.embed, reply_size);
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ return rss_protocol_pointer_access_deserialize_reply(out_vec, out_len, return_val,
+ &reply->reply.pointer_access,
+ reply_size);
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ return PSA_SUCCESS;
+}
diff --git a/drivers/arm/rss/rss_comms_protocol.h b/drivers/arm/rss/rss_comms_protocol.h
new file mode 100644
index 0000000000..9a38057cd1
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_H__
+#define __RSS_COMMS_PROTOCOL_H__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <psa/client.h>
+#include "rss_comms_protocol_embed.h"
+#include "rss_comms_protocol_pointer_access.h"
+
+enum rss_comms_protocol_version_t {
+ RSS_COMMS_PROTOCOL_EMBED = 0,
+ RSS_COMMS_PROTOCOL_POINTER_ACCESS = 1,
+};
+
+struct __packed serialized_rss_comms_header_t {
+ uint8_t protocol_ver;
+ uint8_t seq_num;
+ uint16_t client_id;
+};
+
+/* MHU message passed from Host to RSS to deliver a PSA client call */
+struct __packed serialized_rss_comms_msg_t {
+ struct serialized_rss_comms_header_t header;
+ union __packed {
+ struct rss_embed_msg_t embed;
+ struct rss_pointer_access_msg_t pointer_access;
+ } msg;
+};
+
+/* MHU reply message to hold the PSA client reply result returned by RSS */
+struct __packed serialized_rss_comms_reply_t {
+ struct serialized_rss_comms_header_t header;
+ union __packed {
+ struct rss_embed_reply_t embed;
+ struct rss_pointer_access_reply_t pointer_access;
+ } reply;
+};
+
+/* in_len and out_len are uint8_ts, therefore if there are more than 255 iovecs
+ * an error may occur.
+ */
+CASSERT(PSA_MAX_IOVEC <= UINT8_MAX, assert_rss_comms_max_iovec_too_large);
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct serialized_rss_comms_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct serialized_rss_comms_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_H__ */
diff --git a/drivers/arm/rss/rss_comms_protocol_common.h b/drivers/arm/rss/rss_comms_protocol_common.h
new file mode 100644
index 0000000000..177d6363cc
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_common.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * Packing scheme of the control parameter
+ *
+ * 31 30-28 27 26-24 23-20 19 18-16 15-0
+ * +------------+-----+------+-------+-----+-------+-------+------+
+ * | | | | invec | | | outvec| type |
+ * | Res | Res | Res | number| Res | Res | number| |
+ * +------------+-----+------+-------+-----+-------+-------+------+
+ *
+ * Res: Reserved.
+ */
+
+#ifndef RSS_COMMS_PROTOCOL_COMMON
+#define RSS_COMMS_PROTOCOL_COMMON
+
+#define TYPE_OFFSET (0U)
+#define TYPE_MASK (0xFFFFUL << TYPE_OFFSET)
+#define IN_LEN_OFFSET (24U)
+#define IN_LEN_MASK (0x7UL << IN_LEN_OFFSET)
+#define OUT_LEN_OFFSET (16U)
+#define OUT_LEN_MASK (0x7UL << OUT_LEN_OFFSET)
+
+#define PARAM_PACK(type, in_len, out_len) \
+ (((((uint32_t)(type)) << TYPE_OFFSET) & TYPE_MASK) | \
+ ((((uint32_t)(in_len)) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
+ ((((uint32_t)(out_len)) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
+
+#endif /* RSS_COMMS_PROTOCOL_COMMON */
diff --git a/drivers/arm/rss/rss_comms_protocol_embed.c b/drivers/arm/rss/rss_comms_protocol_embed.c
new file mode 100644
index 0000000000..05628ccdd3
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_embed.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include "rss_comms_protocol_common.h"
+#include "rss_comms_protocol_embed.h"
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_embed_msg_t *msg,
+ size_t *msg_len)
+{
+ uint32_t payload_size = 0;
+ uint32_t i;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+ msg->handle = handle;
+
+ /* Fill msg iovec lengths */
+ for (i = 0U; i < in_len; ++i) {
+ msg->io_size[i] = in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->io_size[in_len + i] = out_vec[i].len;
+ }
+
+ for (i = 0U; i < in_len; ++i) {
+ if (in_vec[i].len > sizeof(msg->trailer) - payload_size) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ memcpy(msg->trailer + payload_size,
+ in_vec[i].base,
+ in_vec[i].len);
+ payload_size += in_vec[i].len;
+ }
+
+ /* Output the actual size of the message, to optimize sending */
+ *msg_len = sizeof(*msg) - sizeof(msg->trailer) + payload_size;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_embed_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_embed_reply_t *reply,
+ size_t reply_size)
+{
+ uint32_t payload_offset = 0;
+ uint32_t i;
+
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ for (i = 0U; i < out_len; ++i) {
+ if ((sizeof(*reply) - sizeof(reply->trailer) + payload_offset)
+ > reply_size) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ memcpy(out_vec[i].base,
+ reply->trailer + payload_offset,
+ reply->out_size[i]);
+ out_vec[i].len = reply->out_size[i];
+ payload_offset += reply->out_size[i];
+ }
+
+ *return_val = reply->return_val;
+
+ return PSA_SUCCESS;
+}
diff --git a/drivers/arm/rss/rss_comms_protocol_embed.h b/drivers/arm/rss/rss_comms_protocol_embed.h
new file mode 100644
index 0000000000..c81c7954e6
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_embed.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_EMBED_H__
+#define __RSS_COMMS_PROTOCOL_EMBED_H__
+
+#include <cdefs.h>
+
+#include <psa/client.h>
+
+#include <platform_def.h>
+
+
+
+struct __packed rss_embed_msg_t {
+ psa_handle_t handle;
+ uint32_t ctrl_param; /* type, in_len, out_len */
+ uint16_t io_size[PSA_MAX_IOVEC];
+ uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+struct __packed rss_embed_reply_t {
+ int32_t return_val;
+ uint16_t out_size[PSA_MAX_IOVEC];
+ uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_embed_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_embed_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_embed_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_EMBED_H__ */
diff --git a/drivers/arm/rss/rss_comms_protocol_pointer_access.c b/drivers/arm/rss/rss_comms_protocol_pointer_access.c
new file mode 100644
index 0000000000..3a10a98435
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_pointer_access.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include "rss_comms_protocol_common.h"
+#include "rss_comms_protocol_pointer_access.h"
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_pointer_access_msg_t *msg,
+ size_t *msg_len)
+{
+ unsigned int i;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+ msg->handle = handle;
+
+ /* Fill msg iovec lengths */
+ for (i = 0U; i < in_len; ++i) {
+ msg->io_sizes[i] = in_vec[i].len;
+ msg->host_ptrs[i] = (uint64_t)in_vec[i].base;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->io_sizes[in_len + i] = out_vec[i].len;
+ msg->host_ptrs[in_len + i] = (uint64_t)out_vec[i].base;
+ }
+
+ *msg_len = sizeof(*msg);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_pointer_access_reply_t *reply,
+ size_t reply_size)
+{
+ unsigned int i;
+
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ for (i = 0U; i < out_len; ++i) {
+ out_vec[i].len = reply->out_sizes[i];
+ }
+
+ *return_val = reply->return_val;
+
+ return PSA_SUCCESS;
+}
diff --git a/drivers/arm/rss/rss_comms_protocol_pointer_access.h b/drivers/arm/rss/rss_comms_protocol_pointer_access.h
new file mode 100644
index 0000000000..a4d054bd2e
--- /dev/null
+++ b/drivers/arm/rss/rss_comms_protocol_pointer_access.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+#define __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+
+#include <cdefs.h>
+
+#include <psa/client.h>
+
+struct __packed rss_pointer_access_msg_t {
+ psa_handle_t handle;
+ uint32_t ctrl_param;
+ uint32_t io_sizes[PSA_MAX_IOVEC];
+ uint64_t host_ptrs[PSA_MAX_IOVEC];
+};
+
+struct __packed rss_pointer_access_reply_t {
+ int32_t return_val;
+ uint32_t out_sizes[PSA_MAX_IOVEC];
+};
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const psa_invec *in_vec,
+ uint8_t in_len,
+ const psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_pointer_access_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_pointer_access_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__ */
diff --git a/drivers/arm/sbsa/sbsa.c b/drivers/arm/sbsa/sbsa.c
index 79c6f26208..a88e20c046 100644
--- a/drivers/arm/sbsa/sbsa.c
+++ b/drivers/arm/sbsa/sbsa.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -40,3 +40,9 @@ void sbsa_wdog_stop(uintptr_t base)
{
mmio_write_32(base + SBSA_WDOG_WCS_OFFSET, (0x0));
}
+
+/* Refresh the secure watchdog timer explicitly */
+void sbsa_wdog_refresh(uintptr_t refresh_base)
+{
+ mmio_write_32(refresh_base + SBSA_WDOG_WRR_OFFSET, SBSA_WDOG_WRR_REFRESH);
+}
diff --git a/drivers/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
index a082a81074..6932e61ccf 100644
--- a/drivers/arm/smmu/smmu_v3.c
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,11 +9,12 @@
#include <drivers/arm/smmu_v3.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
+#include <arch_features.h>
/* SMMU poll number of retries */
#define SMMU_POLL_TIMEOUT_US U(1000)
-static int __init smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
+static int smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
uint32_t value)
{
uint32_t reg_val;
@@ -68,29 +69,113 @@ int __init smmuv3_security_init(uintptr_t smmu_base)
return smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U);
}
-/*
- * Initialize the SMMU by invalidating all secure caches and TLBs.
- * Abort all incoming transactions in order to implement a default
- * deny policy on reset
- */
+/* Initialize the SMMU by invalidating all secure caches and TLBs. */
int __init smmuv3_init(uintptr_t smmu_base)
{
- /* Abort all incoming transactions */
- if (smmuv3_security_init(smmu_base) != 0)
- return -1;
-
- /* Check if the SMMU supports secure state */
- if ((mmio_read_32(smmu_base + SMMU_S_IDR1) &
- SMMU_S_IDR1_SECURE_IMPL) == 0U)
- return 0;
/*
* Initiate invalidation of secure caches and TLBs if the SMMU
* supports secure state. If not, it's implementation defined
* as to how SMMU_S_INIT register is accessed.
+ * As per Arm SMMUv3 specification the SMMU_S_INIT register in a SMMU
+ * with RME implementation has following properties:
+ * a) all SMMU registers that are specified to be accessible only in
+ * the Secure physical address space are additionally accessible in
+ * Root physical address space.
+ * b) as GPT information is permitted to be cached in a TLB, the
+ * SMMU_S_INIT.INV_ALL operation also invalidates all GPT information
+ * cached in TLBs.
+ * Additionally, it is Root firmware’s responsibility to write to
+ * INV_ALL before enabling SMMU_ROOT_CR0.{ACCESSEN,GPCEN}.
*/
mmio_write_32(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL);
/* Wait for global invalidation operation to finish */
- return smmuv3_poll(smmu_base + SMMU_S_INIT,
- SMMU_S_INIT_INV_ALL, 0U);
+ if (smmuv3_poll(smmu_base + SMMU_S_INIT,
+ SMMU_S_INIT_INV_ALL, 0U) != 0) {
+ return -1;
+ }
+
+#if ENABLE_RME
+
+ if (get_armv9_2_feat_rme_support() != 0U) {
+ if ((mmio_read_32(smmu_base + SMMU_ROOT_IDR0) &
+ SMMU_ROOT_IDR0_ROOT_IMPL) == 0U) {
+ WARN("Skip SMMU GPC configuration.\n");
+ } else {
+ uint64_t gpccr_el3 = read_gpccr_el3();
+ uint64_t gptbr_el3 = read_gptbr_el3();
+
+ /* SMMU_ROOT_GPT_BASE_CFG[16] is RES0. */
+ gpccr_el3 &= ~(1UL << 16);
+
+ /*
+ * TODO: SMMU_ROOT_GPT_BASE_CFG is 64b in the spec,
+ * but SMMU model only accepts 32b access.
+ */
+ mmio_write_32(smmu_base + SMMU_ROOT_GPT_BASE_CFG,
+ gpccr_el3);
+
+ /*
+ * pa_gpt_table_base[51:12] maps to GPTBR_EL3[39:0]
+ * whereas it maps to SMMU_ROOT_GPT_BASE[51:12]
+ * hence needs a 12 bit left shit.
+ */
+ mmio_write_64(smmu_base + SMMU_ROOT_GPT_BASE,
+ gptbr_el3 << 12);
+
+ /*
+ * ACCESSEN=1: SMMU- and client-originated accesses are
+ * not terminated by this mechanism.
+ * GPCEN=1: All clients and SMMU-originated accesses,
+ * except GPT-walks, are subject to GPC.
+ */
+ mmio_setbits_32(smmu_base + SMMU_ROOT_CR0,
+ SMMU_ROOT_CR0_GPCEN |
+ SMMU_ROOT_CR0_ACCESSEN);
+
+ /* Poll for ACCESSEN and GPCEN ack bits. */
+ if (smmuv3_poll(smmu_base + SMMU_ROOT_CR0ACK,
+ SMMU_ROOT_CR0_GPCEN |
+ SMMU_ROOT_CR0_ACCESSEN,
+ SMMU_ROOT_CR0_GPCEN |
+ SMMU_ROOT_CR0_ACCESSEN) != 0) {
+ WARN("Failed enabling SMMU GPC.\n");
+
+ /*
+ * Do not return in error, but fall back to
+ * invalidating all entries through the secure
+ * register file.
+ */
+ }
+ }
+ }
+
+#endif /* ENABLE_RME */
+
+ return 0;
+}
+
+int smmuv3_ns_set_abort_all(uintptr_t smmu_base)
+{
+ /* Attribute update has completed when SMMU_GBPA.Update bit is 0 */
+ if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) {
+ return -1;
+ }
+
+ /*
+ * Set GBPA's ABORT bit. Other GBPA fields are presumably ignored then,
+ * so simply preserve their value.
+ */
+ mmio_setbits_32(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE | SMMU_GBPA_ABORT);
+ if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) {
+ return -1;
+ }
+
+ /* Disable the SMMU to engage the GBPA fields previously configured. */
+ mmio_clrbits_32(smmu_base + SMMU_CR0, SMMU_CR0_SMMUEN);
+ if (smmuv3_poll(smmu_base + SMMU_CR0ACK, SMMU_CR0_SMMUEN, 0U) != 0U) {
+ return -1;
+ }
+
+ return 0;
}
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
index 9fc1578a1a..759824db69 100644
--- a/drivers/arm/tzc/tzc400.c
+++ b/drivers/arm/tzc/tzc400.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -68,6 +68,7 @@ DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400)
DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400)
DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400)
DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
+DEFINE_TZC_COMMON_UPDATE_FILTERS(400, 400)
DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
@@ -271,6 +272,15 @@ void tzc400_configure_region(unsigned int filters,
sec_attr, nsaid_permissions);
}
+void tzc400_update_filters(unsigned int region, unsigned int filters)
+{
+ /* Do range checks on filters and regions. */
+ assert(((filters >> tzc400.num_filters) == 0U) &&
+ (region < tzc400.num_regions));
+
+ _tzc400_update_filters(tzc400.base, region, tzc400.num_filters, filters);
+}
+
void tzc400_enable_filters(void)
{
unsigned int state;
@@ -281,6 +291,11 @@ void tzc400_enable_filters(void)
for (filter = 0U; filter < tzc400.num_filters; filter++) {
state = _tzc400_get_gate_keeper(tzc400.base, filter);
if (state != 0U) {
+ /* Filter 0 is special and cannot be disabled.
+ * So here we allow it being already enabled. */
+ if (filter == 0U) {
+ continue;
+ }
/*
* The TZC filter is already configured. Changing the
* programmer's view in an active system can cause
@@ -291,8 +306,8 @@ void tzc400_enable_filters(void)
* See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R)
* Address Space Controller' Technical Reference Manual.
*/
- ERROR("TZC-400 : Filter %d Gatekeeper already"
- " enabled.\n", filter);
+ ERROR("TZC-400 : Filter %u Gatekeeper already enabled.\n",
+ filter);
panic();
}
_tzc400_set_gate_keeper(tzc400.base, filter, 1);
@@ -302,14 +317,17 @@ void tzc400_enable_filters(void)
void tzc400_disable_filters(void)
{
unsigned int filter;
+ unsigned int state;
+ unsigned int start = 0U;
assert(tzc400.base != 0U);
- /*
- * We don't do the same state check as above as the Gatekeepers are
- * disabled after reset.
- */
- for (filter = 0; filter < tzc400.num_filters; filter++)
+ /* Filter 0 is special and cannot be disabled. */
+ state = _tzc400_get_gate_keeper(tzc400.base, 0);
+ if (state != 0U) {
+ start++;
+ }
+ for (filter = start; filter < tzc400.num_filters; filter++)
_tzc400_set_gate_keeper(tzc400.base, filter, 0);
}
diff --git a/drivers/arm/tzc/tzc_common_private.h b/drivers/arm/tzc/tzc_common_private.h
index 1d99077ad1..2090944a75 100644
--- a/drivers/arm/tzc/tzc_common_private.h
+++ b/drivers/arm/tzc/tzc_common_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -90,6 +90,27 @@
}
/*
+ * It is used to modify the filters status for a defined region.
+ */
+#define DEFINE_TZC_COMMON_UPDATE_FILTERS(fn_name, macro_name) \
+ static inline void _tzc##fn_name##_update_filters( \
+ uintptr_t base, \
+ unsigned int region_no, \
+ unsigned int nbfilters, \
+ unsigned int filters) \
+ { \
+ uint32_t filters_mask = GENMASK(nbfilters - 1U, 0); \
+ \
+ mmio_clrsetbits_32(base + \
+ TZC_REGION_OFFSET( \
+ TZC_##macro_name##_REGION_SIZE, \
+ region_no) + \
+ TZC_##macro_name##_REGION_ATTR_0_OFFSET, \
+ filters_mask << TZC_REGION_ATTR_F_EN_SHIFT, \
+ filters << TZC_REGION_ATTR_F_EN_SHIFT); \
+ }
+
+/*
* It is used to program region 0 ATTRIBUTES and ACCESS register.
*/
#define DEFINE_TZC_COMMON_CONFIGURE_REGION0(fn_name) \
diff --git a/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c
index c7f84afdf5..8c5ff9d125 100644
--- a/drivers/auth/auth_mod.c
+++ b/drivers/auth/auth_mod.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -16,22 +16,17 @@
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/crypto_mod.h>
#include <drivers/auth/img_parser_mod.h>
+#include <drivers/fwu/fwu.h>
#include <lib/fconf/fconf_tbbr_getter.h>
#include <plat/common/platform.h>
+#include <tools_share/zero_oid.h>
+
/* ASN.1 tags */
#define ASN1_INTEGER 0x02
-#define return_if_error(rc) \
- do { \
- if (rc != 0) { \
- return rc; \
- } \
- } while (0)
-
#pragma weak plat_set_nv_ctr2
-
static int cmp_auth_param_type_desc(const auth_param_type_desc_t *a,
const auth_param_type_desc_t *b)
{
@@ -97,24 +92,37 @@ static int auth_hash(const auth_method_param_hash_t *param,
{
void *data_ptr, *hash_der_ptr;
unsigned int data_len, hash_der_len;
- int rc = 0;
+ int rc;
/* Get the hash from the parent image. This hash will be DER encoded
* and contain the hash algorithm */
rc = auth_get_param(param->hash, img_desc->parent,
&hash_der_ptr, &hash_der_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Get the data to be hashed from the current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->data,
img, img_len, &data_ptr, &data_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Ask the crypto module to verify this hash */
rc = crypto_mod_verify_hash(data_ptr, data_len,
hash_der_ptr, hash_der_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
- return rc;
+ return 0;
}
/*
@@ -148,72 +156,150 @@ static int auth_signature(const auth_method_param_sig_t *param,
const auth_img_desc_t *img_desc,
void *img, unsigned int img_len)
{
- void *data_ptr, *pk_ptr, *pk_hash_ptr, *sig_ptr, *sig_alg_ptr;
- unsigned int data_len, pk_len, pk_hash_len, sig_len, sig_alg_len;
+ void *data_ptr, *pk_ptr, *cnv_pk_ptr, *pk_plat_ptr, *sig_ptr, *sig_alg_ptr, *pk_oid;
+ unsigned int data_len, pk_len, cnv_pk_len, pk_plat_len, sig_len, sig_alg_len;
unsigned int flags = 0;
- int rc = 0;
+ int rc;
/* Get the data to be signed from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->data,
img, img_len, &data_ptr, &data_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Get the signature from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->sig,
img, img_len, &sig_ptr, &sig_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Get the signature algorithm from current image */
rc = img_parser_get_auth_param(img_desc->img_type, param->alg,
img, img_len, &sig_alg_ptr, &sig_alg_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Get the public key from the parent. If there is no parent (NULL),
* the certificate has been signed with the ROTPK, so we have to get
* the PK from the platform */
- if (img_desc->parent) {
+ if (img_desc->parent != NULL) {
rc = auth_get_param(param->pk, img_desc->parent,
&pk_ptr, &pk_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
} else {
- rc = plat_get_rotpk_info(param->pk->cookie, &pk_ptr, &pk_len,
- &flags);
- }
- return_if_error(rc);
+ /*
+ * Root certificates are signed with the ROTPK, so we have to
+ * get it from the platform.
+ */
+ rc = plat_get_rotpk_info(param->pk->cookie, &pk_plat_ptr,
+ &pk_plat_len, &flags);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
+
+ assert(is_rotpk_flags_valid(flags));
- if (flags & (ROTPK_IS_HASH | ROTPK_NOT_DEPLOYED)) {
- /* If the PK is a hash of the key or if the ROTPK is not
- deployed on the platform, retrieve the key from the image */
- pk_hash_ptr = pk_ptr;
- pk_hash_len = pk_len;
+ /* Also retrieve the key from the image. */
rc = img_parser_get_auth_param(img_desc->img_type,
- param->pk, img, img_len,
- &pk_ptr, &pk_len);
- return_if_error(rc);
-
- /* Ask the crypto module to verify the signature */
- rc = crypto_mod_verify_signature(data_ptr, data_len,
- sig_ptr, sig_len,
- sig_alg_ptr, sig_alg_len,
- pk_ptr, pk_len);
- return_if_error(rc);
-
- if (flags & ROTPK_NOT_DEPLOYED) {
+ param->pk, img, img_len,
+ &pk_ptr, &pk_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
+
+ /*
+ * Validate the certificate's key against the platform ROTPK.
+ *
+ * Platform may store key in one of the following way -
+ * 1. Hash of ROTPK
+ * 2. Hash if prefixed, suffixed or modified ROTPK
+ * 3. Full ROTPK
+ */
+ if ((flags & ROTPK_NOT_DEPLOYED) != 0U) {
NOTICE("ROTPK is not deployed on platform. "
"Skipping ROTPK verification.\n");
+ } else if ((flags & ROTPK_IS_HASH) != 0U) {
+ /*
+ * platform may store the hash of a prefixed,
+ * suffixed or modified pk
+ */
+ rc = crypto_mod_convert_pk(pk_ptr, pk_len, &cnv_pk_ptr, &cnv_pk_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
+
+ /*
+ * The hash of the certificate's public key must match
+ * the hash of the ROTPK.
+ */
+ rc = crypto_mod_verify_hash(cnv_pk_ptr, cnv_pk_len,
+ pk_plat_ptr, pk_plat_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
} else {
- /* Ask the crypto-module to verify the key hash */
- rc = crypto_mod_verify_hash(pk_ptr, pk_len,
- pk_hash_ptr, pk_hash_len);
+ /* Platform supports full ROTPK */
+ if ((pk_len != pk_plat_len) ||
+ (memcmp(pk_plat_ptr, pk_ptr, pk_len) != 0)) {
+ ERROR("plat and cert ROTPK len mismatch\n");
+ return -1;
+ }
+ }
+
+ /*
+ * Set Zero-OID for ROTPK(subject key) as a the certificate
+ * does not hold Key-OID information for ROTPK.
+ */
+ if (param->pk->cookie != NULL) {
+ pk_oid = param->pk->cookie;
+ } else {
+ pk_oid = ZERO_OID;
+ }
+
+ /*
+ * Public key is verified at this stage, notify platform
+ * to measure and publish it.
+ */
+ rc = plat_mboot_measure_key(pk_oid, pk_ptr, pk_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
}
- } else {
- /* Ask the crypto module to verify the signature */
- rc = crypto_mod_verify_signature(data_ptr, data_len,
- sig_ptr, sig_len,
- sig_alg_ptr, sig_alg_len,
- pk_ptr, pk_len);
}
- return rc;
+ /* Ask the crypto module to verify the signature */
+ rc = crypto_mod_verify_signature(data_ptr, data_len,
+ sig_ptr, sig_len,
+ sig_alg_ptr, sig_alg_len,
+ pk_ptr, pk_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
+
+ return 0;
}
/*
@@ -237,30 +323,42 @@ static int auth_nvctr(const auth_method_param_nv_ctr_t *param,
unsigned int *cert_nv_ctr,
bool *need_nv_ctr_upgrade)
{
- char *p;
+ unsigned char *p;
void *data_ptr = NULL;
unsigned int data_len, len, i;
unsigned int plat_nv_ctr;
- int rc = 0;
+ int rc;
/* Get the counter value from current image. The AM expects the IPM
* to return the counter value as a DER encoded integer */
rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr,
img, img_len, &data_ptr, &data_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Parse the DER encoded integer */
assert(data_ptr);
- p = (char *)data_ptr;
- if (*p != ASN1_INTEGER) {
+ p = (unsigned char *)data_ptr;
+
+ /*
+ * Integers must be at least 3 bytes: 1 for tag, 1 for length, and 1
+ * for value. The first byte (tag) must be ASN1_INTEGER.
+ */
+ if ((data_len < 3) || (*p != ASN1_INTEGER)) {
/* Invalid ASN.1 integer */
return 1;
}
p++;
- /* NV-counters are unsigned integers up to 32-bit */
- len = (unsigned int)(*p & 0x7f);
- if ((*p & 0x80) || (len > 4)) {
+ /*
+ * NV-counters are unsigned integers up to 31 bits. Trailing
+ * padding is not allowed.
+ */
+ len = (unsigned int)*p;
+ if ((len > 4) || (data_len - 2 != len)) {
return 1;
}
p++;
@@ -278,13 +376,25 @@ static int auth_nvctr(const auth_method_param_nv_ctr_t *param,
/* Get the counter from the platform */
rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
if (*cert_nv_ctr < plat_nv_ctr) {
/* Invalid NV-counter */
return 1;
} else if (*cert_nv_ctr > plat_nv_ctr) {
+#if PSA_FWU_SUPPORT && IMAGE_BL2
+ if (fwu_get_active_bank_state() == FWU_BANK_STATE_ACCEPTED) {
+ *need_nv_ctr_upgrade = true;
+ } else {
+ *need_nv_ctr_upgrade = false;
+ }
+#else
*need_nv_ctr_upgrade = true;
+#endif /* PSA_FWU_SUPPORT && IMAGE_BL2 */
}
return 0;
@@ -334,9 +444,6 @@ void auth_mod_init(void)
/* Check we have a valid CoT registered */
assert(cot_desc_ptr != NULL);
- /* Crypto module */
- crypto_mod_init();
-
/* Image parser module */
img_parser_init();
}
@@ -351,6 +458,7 @@ int auth_mod_verify_img(unsigned int img_id,
unsigned int img_len)
{
const auth_img_desc_t *img_desc = NULL;
+ const auth_param_type_desc_t *type_desc = NULL;
const auth_method_desc_t *auth_method = NULL;
void *param_ptr;
unsigned int param_len;
@@ -365,7 +473,11 @@ int auth_mod_verify_img(unsigned int img_id,
/* Ask the parser to check the image integrity */
rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Authenticate the image using the methods indicated in the image
* descriptor. */
@@ -397,7 +509,11 @@ int auth_mod_verify_img(unsigned int img_id,
rc = 1;
break;
}
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
}
/*
@@ -407,7 +523,11 @@ int auth_mod_verify_img(unsigned int img_id,
if (need_nv_ctr_upgrade && sig_auth_done) {
rc = plat_set_nv_ctr2(nv_ctr_param->plat_nv_ctr->cookie,
img_desc, cert_nv_ctr);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
}
/* Extract the parameters indicated in the image descriptor to
@@ -422,7 +542,11 @@ int auth_mod_verify_img(unsigned int img_id,
rc = img_parser_get_auth_param(img_desc->img_type,
img_desc->authenticated_data[i].type_desc,
img_ptr, img_len, &param_ptr, &param_len);
- return_if_error(rc);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ return rc;
+ }
/* Check parameter size */
if (param_len > img_desc->authenticated_data[i].data.len) {
@@ -432,6 +556,21 @@ int auth_mod_verify_img(unsigned int img_id,
/* Copy the parameter for later use */
memcpy((void *)img_desc->authenticated_data[i].data.ptr,
(void *)param_ptr, param_len);
+
+ /*
+ * If this is a public key then measure and publicise
+ * it.
+ */
+ type_desc = img_desc->authenticated_data[i].type_desc;
+ if (type_desc->type == AUTH_PARAM_PUB_KEY) {
+ rc = plat_mboot_measure_key(type_desc->cookie,
+ param_ptr,
+ param_len);
+ if (rc != 0) {
+ VERBOSE("[TBB] %s():%d failed with error code %d.\n",
+ __func__, __LINE__, rc);
+ }
+ }
}
}
diff --git a/drivers/auth/cca/cot.c b/drivers/auth/cca/cot.c
new file mode 100644
index 0000000000..2a0360455f
--- /dev/null
+++ b/drivers/auth/cca/cot.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <mbedtls/version.h>
+
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_mod.h>
+#include <tools_share/cca_oid.h>
+
+#include <platform_def.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char hw_config_hash_buf[HASH_DER_LEN];
+static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
+static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char rmm_hash_buf[HASH_DER_LEN];
+
+#ifdef IMAGE_BL2
+static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
+#if defined(SPD_spmd)
+static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
+#endif /* SPD_spmd */
+
+static unsigned char core_swd_pk_buf[PK_DER_LEN];
+static unsigned char plat_pk_buf[PK_DER_LEN];
+#endif /* IMAGE_BL2 */
+
+/*
+ * Parameter type descriptors.
+ */
+static auth_param_type_desc_t cca_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, CCA_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_RAW_DATA, 0);
+
+static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID);
+static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t rmm_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, RMM_HASH_OID);
+
+#ifdef IMAGE_BL2
+static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
+
+static auth_param_type_desc_t prot_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, PROT_PK_OID);
+static auth_param_type_desc_t swd_rot_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, SWD_ROT_PK_OID);
+static auth_param_type_desc_t core_swd_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, CORE_SWD_PK_OID);
+static auth_param_type_desc_t plat_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, PLAT_PK_OID);
+
+static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID);
+static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
+static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
+#if defined(SPD_spmd)
+static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
+static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
+static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
+static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
+static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
+static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
+static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
+static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
+#endif /* SPD_spmd */
+#endif /* IMAGE_BL2 */
+
+/* CCA Content Certificate */
+static const auth_img_desc_t cca_content_cert = {
+ .img_id = CCA_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &subject_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &cca_nv_ctr,
+ .plat_nv_ctr = &cca_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &tb_fw_hash,
+ .data = {
+ .ptr = (void *)tb_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &tb_fw_config_hash,
+ .data = {
+ .ptr = (void *)tb_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &fw_config_hash,
+ .data = {
+ .ptr = (void *)fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &hw_config_hash,
+ .data = {
+ .ptr = (void *)hw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [4] = {
+ .type_desc = &soc_fw_hash,
+ .data = {
+ .ptr = (void *)soc_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [5] = {
+ .type_desc = &soc_fw_config_hash,
+ .data = {
+ .ptr = (void *)soc_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [6] = {
+ .type_desc = &rmm_hash,
+ .data = {
+ .ptr = (void *)rmm_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+#ifdef IMAGE_BL1
+static const auth_img_desc_t bl2_image = {
+ .img_id = BL2_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tb_fw_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t tb_fw_config = {
+ .img_id = TB_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tb_fw_config_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t fw_config = {
+ .img_id = FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &fw_config_hash
+ }
+ }
+ }
+};
+#endif /* IMAGE_BL1 */
+
+#ifdef IMAGE_BL2
+/* HW Config */
+static const auth_img_desc_t hw_config = {
+ .img_id = HW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &hw_config_hash
+ }
+ }
+ }
+};
+
+/* BL31 */
+static const auth_img_desc_t bl31_image = {
+ .img_id = BL31_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &soc_fw_hash
+ }
+ }
+ }
+};
+
+/* BL31 Config */
+static const auth_img_desc_t soc_fw_config = {
+ .img_id = SOC_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &soc_fw_config_hash
+ }
+ }
+ }
+};
+
+/* RMM */
+static const auth_img_desc_t rmm_image = {
+ .img_id = RMM_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &rmm_hash
+ }
+ }
+ }
+};
+
+/* Core SWD Key Certificate */
+static const auth_img_desc_t core_swd_key_cert = {
+ .img_id = CORE_SWD_KEY_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL, /* SWD ROOT CERT */
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &swd_rot_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &trusted_nv_ctr,
+ .plat_nv_ctr = &trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &core_swd_pk,
+ .data = {
+ .ptr = (void *)core_swd_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+
+/* SPMC Content Certificate */
+static const auth_img_desc_t trusted_os_fw_content_cert = {
+ .img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &core_swd_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &core_swd_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &trusted_nv_ctr,
+ .plat_nv_ctr = &trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &tos_fw_hash,
+ .data = {
+ .ptr = (void *)tos_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &tos_fw_config_hash,
+ .data = {
+ .ptr = (void *)tos_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+/* SPMC */
+static const auth_img_desc_t bl32_image = {
+ .img_id = BL32_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &trusted_os_fw_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tos_fw_hash
+ }
+ }
+ }
+};
+
+/* SPM Config */
+static const auth_img_desc_t tos_fw_config = {
+ .img_id = TOS_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &trusted_os_fw_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tos_fw_config_hash
+ }
+ }
+ }
+};
+
+/* Platform Key Certificate */
+static const auth_img_desc_t plat_key_cert = {
+ .img_id = PLAT_KEY_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL, /* PLATFORM ROOT CERT */
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &prot_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &non_trusted_nv_ctr,
+ .plat_nv_ctr = &non_trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &plat_pk,
+ .data = {
+ .ptr = (void *)plat_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+
+/* Non-Trusted Firmware */
+static const auth_img_desc_t non_trusted_fw_content_cert = {
+ .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &plat_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &plat_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &non_trusted_nv_ctr,
+ .plat_nv_ctr = &non_trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &nt_world_bl_hash,
+ .data = {
+ .ptr = (void *)nt_world_bl_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &nt_fw_config_hash,
+ .data = {
+ .ptr = (void *)nt_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t bl33_image = {
+ .img_id = BL33_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &non_trusted_fw_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &nt_world_bl_hash
+ }
+ }
+ }
+};
+
+/* NT FW Config */
+static const auth_img_desc_t nt_fw_config = {
+ .img_id = NT_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &non_trusted_fw_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &nt_fw_config_hash
+ }
+ }
+ }
+};
+
+/*
+ * Secure Partitions
+ */
+#if defined(SPD_spmd)
+static const auth_img_desc_t sip_sp_content_cert = {
+ .img_id = SIP_SP_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &core_swd_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &core_swd_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &trusted_nv_ctr,
+ .plat_nv_ctr = &trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &sp_pkg1_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[0],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg2_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[1],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg3_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[2],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg4_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[3],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_SIP_SP_PKG(1);
+DEFINE_SIP_SP_PKG(2);
+DEFINE_SIP_SP_PKG(3);
+DEFINE_SIP_SP_PKG(4);
+
+static const auth_img_desc_t plat_sp_content_cert = {
+ .img_id = PLAT_SP_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &plat_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &plat_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &non_trusted_nv_ctr,
+ .plat_nv_ctr = &non_trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &sp_pkg5_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[4],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &sp_pkg6_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[5],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &sp_pkg7_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[6],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [3] = {
+ .type_desc = &sp_pkg8_hash,
+ .data = {
+ .ptr = (void *)sp_pkg_hash_buf[7],
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+DEFINE_PLAT_SP_PKG(5);
+DEFINE_PLAT_SP_PKG(6);
+DEFINE_PLAT_SP_PKG(7);
+DEFINE_PLAT_SP_PKG(8);
+#endif /* SPD_spmd */
+#endif /* IMAGE_BL2 */
+/*
+ * Chain of trust definition
+ */
+#ifdef IMAGE_BL1
+static const auth_img_desc_t * const cot_desc[] = {
+ [CCA_CONTENT_CERT_ID] = &cca_content_cert,
+ [BL2_IMAGE_ID] = &bl2_image,
+ [TB_FW_CONFIG_ID] = &tb_fw_config,
+ [FW_CONFIG_ID] = &fw_config,
+};
+#else /* IMAGE_BL2 */
+static const auth_img_desc_t * const cot_desc[] = {
+ [CCA_CONTENT_CERT_ID] = &cca_content_cert,
+ [HW_CONFIG_ID] = &hw_config,
+ [BL31_IMAGE_ID] = &bl31_image,
+ [SOC_FW_CONFIG_ID] = &soc_fw_config,
+ [RMM_IMAGE_ID] = &rmm_image,
+ [CORE_SWD_KEY_CERT_ID] = &core_swd_key_cert,
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = &trusted_os_fw_content_cert,
+ [BL32_IMAGE_ID] = &bl32_image,
+ [TOS_FW_CONFIG_ID] = &tos_fw_config,
+ [PLAT_KEY_CERT_ID] = &plat_key_cert,
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = &non_trusted_fw_content_cert,
+ [BL33_IMAGE_ID] = &bl33_image,
+ [NT_FW_CONFIG_ID] = &nt_fw_config,
+#if defined(SPD_spmd)
+ [SIP_SP_CONTENT_CERT_ID] = &sip_sp_content_cert,
+ [PLAT_SP_CONTENT_CERT_ID] = &plat_sp_content_cert,
+ [SP_PKG1_ID] = &sp_pkg1,
+ [SP_PKG2_ID] = &sp_pkg2,
+ [SP_PKG3_ID] = &sp_pkg3,
+ [SP_PKG4_ID] = &sp_pkg4,
+ [SP_PKG5_ID] = &sp_pkg5,
+ [SP_PKG6_ID] = &sp_pkg6,
+ [SP_PKG7_ID] = &sp_pkg7,
+ [SP_PKG8_ID] = &sp_pkg8,
+#endif
+};
+#endif /* IMAGE_BL1 */
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/crypto_mod.c b/drivers/auth/crypto_mod.c
index c63ff080f9..e36b2858ac 100644
--- a/drivers/auth/crypto_mod.c
+++ b/drivers/auth/crypto_mod.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -46,14 +46,26 @@ void crypto_mod_init(void)
{
assert(crypto_lib_desc.name != NULL);
assert(crypto_lib_desc.init != NULL);
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
assert(crypto_lib_desc.verify_signature != NULL);
assert(crypto_lib_desc.verify_hash != NULL);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ assert(crypto_lib_desc.calc_hash != NULL);
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
/* Initialize the cryptographic library */
crypto_lib_desc.init();
INFO("Using crypto library '%s'\n", crypto_lib_desc.name);
}
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
/*
* Function to verify a digital signature
*
@@ -103,8 +115,11 @@ int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len,
return crypto_lib_desc.verify_hash(data_ptr, data_len,
digest_info_ptr, digest_info_len);
}
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
-#if MEASURED_BOOT
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
/*
* Calculate a hash
*
@@ -114,8 +129,9 @@ int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len,
* data_ptr, data_len: data to be hashed
* output: resulting hash
*/
-int crypto_mod_calc_hash(unsigned int alg, void *data_ptr,
- unsigned int data_len, unsigned char *output)
+int crypto_mod_calc_hash(enum crypto_md_algo alg, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE])
{
assert(data_ptr != NULL);
assert(data_len != 0);
@@ -123,7 +139,22 @@ int crypto_mod_calc_hash(unsigned int alg, void *data_ptr,
return crypto_lib_desc.calc_hash(alg, data_ptr, data_len, output);
}
-#endif /* MEASURED_BOOT */
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+int crypto_mod_convert_pk(void *full_pk_ptr, unsigned int full_pk_len,
+ void **hashed_pk_ptr, unsigned int *hashed_pk_len)
+{
+ if (crypto_lib_desc.convert_pk != NULL) {
+ return crypto_lib_desc.convert_pk(full_pk_ptr, full_pk_len,
+ hashed_pk_ptr, hashed_pk_len);
+ }
+
+ *hashed_pk_ptr = full_pk_ptr;
+ *hashed_pk_len = full_pk_len;
+
+ return 0;
+}
/*
* Authenticated decryption of data
diff --git a/drivers/auth/cryptocell/712/cryptocell_crypto.c b/drivers/auth/cryptocell/712/cryptocell_crypto.c
deleted file mode 100644
index c7ee36fa71..0000000000
--- a/drivers/auth/cryptocell/712/cryptocell_crypto.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <string.h>
-
-#include <platform_def.h>
-
-#include <arch_helpers.h>
-#include <common/debug.h>
-#include <drivers/arm/cryptocell/712/crypto_driver.h>
-#include <drivers/arm/cryptocell/712/rsa.h>
-#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
-#include <drivers/arm/cryptocell/712/secureboot_base_func.h>
-#include <drivers/arm/cryptocell/712/secureboot_gen_defs.h>
-#include <drivers/arm/cryptocell/712/util.h>
-#include <drivers/auth/crypto_mod.h>
-#include <drivers/auth/mbedtls/mbedtls_common.h>
-#include <lib/utils.h>
-
-#include <mbedtls/oid.h>
-#include <mbedtls/x509.h>
-
-#define LIB_NAME "CryptoCell 712 SBROM"
-#define RSA_SALT_LEN 32
-#define RSA_EXPONENT 65537
-
-/*
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * SubjectPublicKeyInfo ::= SEQUENCE {
- * algorithm AlgorithmIdentifier,
- * subjectPublicKey BIT STRING
- * }
- *
- * DigestInfo ::= SEQUENCE {
- * digestAlgorithm AlgorithmIdentifier,
- * digest OCTET STRING
- * }
- *
- * RSASSA-PSS-params ::= SEQUENCE {
- * hashAlgorithm [0] HashAlgorithm,
- * maskGenAlgorithm [1] MaskGenAlgorithm,
- * saltLength [2] INTEGER,
- * trailerField [3] TrailerField DEFAULT trailerFieldBC
- * }
- */
-
-/*
- * Initialize the library and export the descriptor
- */
-static void init(void)
-{
- CCError_t ret;
- uint32_t lcs;
-
- /* Initialize CC SBROM */
- ret = CC_BsvSbromInit((uintptr_t)PLAT_CRYPTOCELL_BASE);
- if (ret != CC_OK) {
- ERROR("CryptoCell CC_BsvSbromInit() error %x\n", ret);
- panic();
- }
-
- /* Initialize lifecycle state */
- ret = CC_BsvLcsGetAndInit((uintptr_t)PLAT_CRYPTOCELL_BASE, &lcs);
- if (ret != CC_OK) {
- ERROR("CryptoCell CC_BsvLcsGetAndInit() error %x\n", ret);
- panic();
- }
-
- /* If the lifecyclestate is `SD`, then stop further execution */
- if (lcs == CC_BSV_SECURITY_DISABLED_LCS) {
- ERROR("CryptoCell LCS is security-disabled\n");
- panic();
- }
-}
-
-/*
- * Verify a signature.
- *
- * Parameters are passed using the DER encoding format following the ASN.1
- * structures detailed above.
- */
-static int verify_signature(void *data_ptr, unsigned int data_len,
- void *sig_ptr, unsigned int sig_len,
- void *sig_alg, unsigned int sig_alg_len,
- void *pk_ptr, unsigned int pk_len)
-{
- CCError_t error;
- CCSbNParams_t pk;
- CCSbSignature_t signature;
- int rc, exp;
- mbedtls_asn1_buf sig_oid, alg_oid, params;
- mbedtls_md_type_t md_alg;
- mbedtls_pk_type_t pk_alg;
- mbedtls_pk_rsassa_pss_options pss_opts;
- size_t len;
- uint8_t *p, *end;
- /* Temp buf to store the public key modulo (N) in LE format */
- uint32_t RevN[SB_RSA_MOD_SIZE_IN_WORDS];
-
- /* Verify the signature algorithm */
- /* Get pointers to signature OID and parameters */
- p = sig_alg;
- end = p + sig_alg_len;
- rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &params);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Get the actual signature algorithm (MD + PK) */
- rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- /* The CryptoCell only supports RSASSA-PSS signature */
- if (pk_alg != MBEDTLS_PK_RSASSA_PSS || md_alg != MBEDTLS_MD_NONE)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Verify the RSASSA-PSS params */
- /* The trailer field is verified to be 0xBC internally by this API */
- rc = mbedtls_x509_get_rsassa_pss_params(&params, &md_alg,
- &pss_opts.mgf1_hash_id,
- &pss_opts.expected_salt_len);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- /* The CryptoCell only supports SHA256 as hash algorithm */
- if (md_alg != MBEDTLS_MD_SHA256 || pss_opts.mgf1_hash_id != MBEDTLS_MD_SHA256)
- return CRYPTO_ERR_SIGNATURE;
-
- if (pss_opts.expected_salt_len != RSA_SALT_LEN)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Parse the public key */
- p = pk_ptr;
- end = p + pk_len;
- rc = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- end = p + len;
- rc = mbedtls_asn1_get_alg_null(&p, end, &alg_oid);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (mbedtls_oid_get_pk_alg(&alg_oid, &pk_alg) != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (pk_alg != MBEDTLS_PK_RSA)
- return CRYPTO_ERR_SIGNATURE;
-
- rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- rc = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (*p == 0) {
- p++; len--;
- }
- if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end))
- return CRYPTO_ERR_SIGNATURE;
-
- /*
- * The CCSbVerifySignature() API expects N and Np in BE format and
- * the signature in LE format. Copy N from certificate.
- */
- memcpy(pk.N, p, RSA_MOD_SIZE_IN_BYTES);
-
- /* Verify the RSA exponent */
- p += len;
- rc = mbedtls_asn1_get_int(&p, end, &exp);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (exp != RSA_EXPONENT)
- return CRYPTO_ERR_SIGNATURE;
-
- /*
- * Calculate the Np (Barrett n' value). The RSA_CalcNp() API expects
- * N in LE format. Hence reverse N into a temporary buffer `RevN`.
- */
- UTIL_ReverseMemCopy((uint8_t *)RevN, (uint8_t *)pk.N, sizeof(RevN));
-
- RSA_CalcNp((uintptr_t)PLAT_CRYPTOCELL_BASE, RevN, pk.Np);
-
- /* Np is in LE format. Reverse it to BE */
- UTIL_ReverseBuff((uint8_t *)pk.Np, sizeof(pk.Np));
-
- /* Get the signature (bitstring) */
- p = sig_ptr;
- end = p + sig_len;
- rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end))
- return CRYPTO_ERR_SIGNATURE;
-
- /*
- * The signature is BE format. Convert it to LE before calling
- * CCSbVerifySignature().
- */
- UTIL_ReverseMemCopy((uint8_t *)signature.sig, p, RSA_MOD_SIZE_IN_BYTES);
-
- /*
- * CryptoCell utilises DMA internally to transfer data. Flush the data
- * from caches.
- */
- flush_dcache_range((uintptr_t)data_ptr, data_len);
-
- /* Verify the signature */
- error = CCSbVerifySignature((uintptr_t)PLAT_CRYPTOCELL_BASE,
- (uint32_t *)data_ptr, &pk, &signature,
- data_len, RSA_PSS);
- if (error != CC_OK)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Signature verification success */
- return CRYPTO_SUCCESS;
-}
-
-/*
- * Match a hash
- *
- * Digest info is passed in DER format following the ASN.1 structure detailed
- * above.
- */
-static int verify_hash(void *data_ptr, unsigned int data_len,
- void *digest_info_ptr, unsigned int digest_info_len)
-{
- mbedtls_asn1_buf hash_oid, params;
- mbedtls_md_type_t md_alg;
- uint8_t *p, *end, *hash;
- CCHashResult_t pubKeyHash;
- size_t len;
- int rc;
- CCError_t error;
-
- /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
- p = digest_info_ptr;
- end = p + digest_info_len;
- rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- /* Get the hash algorithm */
- rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
- /* Verify that hash algorithm is SHA256 */
- if (md_alg != MBEDTLS_MD_SHA256)
- return CRYPTO_ERR_HASH;
-
- /* Hash should be octet string type */
- rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- /* Length of hash must match the algorithm's size */
- if (len != HASH_RESULT_SIZE_IN_BYTES)
- return CRYPTO_ERR_HASH;
-
- /*
- * CryptoCell utilises DMA internally to transfer data. Flush the data
- * from caches.
- */
- flush_dcache_range((uintptr_t)data_ptr, data_len);
-
- hash = p;
- error = SBROM_CryptoHash((uintptr_t)PLAT_CRYPTOCELL_BASE,
- (uintptr_t)data_ptr, data_len, pubKeyHash);
- if (error != CC_OK)
- return CRYPTO_ERR_HASH;
-
- rc = memcmp(pubKeyHash, hash, HASH_RESULT_SIZE_IN_BYTES);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- return CRYPTO_SUCCESS;
-}
-
-/*
- * Register crypto library descriptor
- */
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
-
diff --git a/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c b/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c
deleted file mode 100644
index 53d77dbe13..0000000000
--- a/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <platform_def.h>
-
-#include <plat/common/platform.h>
-#include <tools_share/tbbr_oid.h>
-
-#include <common/debug.h>
-#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
-#include <drivers/arm/cryptocell/712/nvm.h>
-#include <drivers/arm/cryptocell/712/nvm_otp.h>
-
-/*
- * Return the ROTPK hash
- *
- * dst: buffer into which the ROTPK hash will be copied into
- * len: length of the provided buffer, which must be at least enough for a
- * SHA256 hash
- * flags: a pointer to integer that will be set to indicate the ROTPK status
- *
- * Return: 0 = success, Otherwise = error
- */
-int cc_get_rotpk_hash(unsigned char *dst, unsigned int len, unsigned int *flags)
-{
- CCError_t error;
- uint32_t lcs;
-
- assert(dst != NULL);
- assert(len >= HASH_RESULT_SIZE_IN_WORDS);
- assert(flags != NULL);
-
- error = NVM_GetLCS(PLAT_CRYPTOCELL_BASE, &lcs);
- if (error != CC_OK)
- return 1;
-
- /* If the lifecycle state is `SD`, return failure */
- if (lcs == CC_BSV_SECURITY_DISABLED_LCS)
- return 1;
-
- /*
- * If the lifecycle state is `CM` or `DM`, ROTPK shouldn't be verified.
- * Return success after setting ROTPK_NOT_DEPLOYED flag
- */
- if ((lcs == CC_BSV_CHIP_MANUFACTURE_LCS) ||
- (lcs == CC_BSV_DEVICE_MANUFACTURE_LCS)) {
- *flags = ROTPK_NOT_DEPLOYED;
- return 0;
- }
-
- /* Copy the DER header */
- error = NVM_ReadHASHPubKey(PLAT_CRYPTOCELL_BASE,
- CC_SB_HASH_BOOT_KEY_256B,
- (uint32_t *)dst, HASH_RESULT_SIZE_IN_WORDS);
- if (error != CC_OK)
- return 1;
-
- *flags = ROTPK_IS_HASH;
- return 0;
-}
-
-/*
- * Return the non-volatile counter value stored in the platform. The cookie
- * specifies the OID of the counter in the certificate.
- *
- * Return: 0 = success, Otherwise = error
- */
-int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
-{
- CCError_t error = CC_FAIL;
-
- if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = NVM_GetSwVersion(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_COUNTER1, nv_ctr);
- } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = NVM_GetSwVersion(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_COUNTER2, nv_ctr);
- }
-
- return (error != CC_OK);
-}
-
-/*
- * Store a new non-volatile counter value in the counter specified by the OID
- * in the cookie. This function is not expected to be called if the Lifecycle
- * state is RMA as the values in the certificate are expected to always match
- * the nvcounter values. But if called when the LCS is RMA, the underlying
- * helper functions will return success but without updating the counter.
- *
- * Return: 0 = success, Otherwise = error
- */
-int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
-{
- CCError_t error = CC_FAIL;
-
- if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = NVM_SetSwVersion(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_COUNTER1, nv_ctr);
- } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = NVM_SetSwVersion(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_COUNTER2, nv_ctr);
- }
-
- return (error != CC_OK);
-}
-
diff --git a/drivers/auth/cryptocell/713/cryptocell_crypto.c b/drivers/auth/cryptocell/713/cryptocell_crypto.c
deleted file mode 100644
index 5f390a2264..0000000000
--- a/drivers/auth/cryptocell/713/cryptocell_crypto.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <drivers/arm/cryptocell/713/bsv_api.h>
-#include <drivers/arm/cryptocell/713/bsv_crypto_asym_api.h>
-#include <drivers/auth/crypto_mod.h>
-
-#include <mbedtls/oid.h>
-
-#define LIB_NAME "CryptoCell 713 SBROM"
-#define RSA_SALT_LEN 32
-#define RSA_EXPONENT 65537
-
-/*
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL
- * }
- *
- * SubjectPublicKeyInfo ::= SEQUENCE {
- * algorithm AlgorithmIdentifier,
- * subjectPublicKey BIT STRING
- * }
- *
- * DigestInfo ::= SEQUENCE {
- * digestAlgorithm AlgorithmIdentifier,
- * digest OCTET STRING
- * }
- *
- * RSASSA-PSS-params ::= SEQUENCE {
- * hashAlgorithm [0] HashAlgorithm,
- * maskGenAlgorithm [1] MaskGenAlgorithm,
- * saltLength [2] INTEGER,
- * trailerField [3] TrailerField DEFAULT trailerFieldBC
- * }
- */
-
-/*
- * Initialize the library and export the descriptor
- */
-static void init(void)
-{
- CCError_t ret;
- uint32_t lcs;
-
- /* Initialize CC SBROM */
- ret = CC_BsvInit((uintptr_t)PLAT_CRYPTOCELL_BASE);
- if (ret != CC_OK) {
- ERROR("CryptoCell CC_BsvInit() error %x\n", ret);
- panic();
- }
-
- /* Initialize lifecycle state */
- ret = CC_BsvGetAndInitLcs((uintptr_t)PLAT_CRYPTOCELL_BASE, &lcs);
- if (ret != CC_OK) {
- ERROR("CryptoCell CC_BsvGetAndInitLcs() error %x\n", ret);
- panic();
- }
-}
-
-/*
- * Verify a signature.
- *
- * Parameters are passed using the DER encoding format following the ASN.1
- * structures detailed above.
- */
-static int verify_signature(void *data_ptr, unsigned int data_len,
- void *sig_ptr, unsigned int sig_len,
- void *sig_alg, unsigned int sig_alg_len,
- void *pk_ptr, unsigned int pk_len)
-{
- CCError_t error;
- CCBsvNBuff_t NBuff;
- CCBsvSignature_t signature;
- int rc, exp;
- mbedtls_asn1_buf sig_oid, alg_oid, params;
- mbedtls_md_type_t md_alg;
- mbedtls_pk_type_t pk_alg;
- mbedtls_pk_rsassa_pss_options pss_opts;
- size_t len;
- uint8_t *p, *end;
- CCHashResult_t digest;
- CCBool_t is_verified;
- /* This is a rather large array, we don't want it on stack */
- static uint32_t workspace[BSV_RSA_WORKSPACE_MIN_SIZE];
-
- /* Verify the signature algorithm */
- /* Get pointers to signature OID and parameters */
- p = sig_alg;
- end = p + sig_alg_len;
- rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &params);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Get the actual signature algorithm (MD + PK) */
- rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- /* The CryptoCell only supports RSASSA-PSS signature */
- if (pk_alg != MBEDTLS_PK_RSASSA_PSS || md_alg != MBEDTLS_MD_NONE)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Verify the RSASSA-PSS params */
- /* The trailer field is verified to be 0xBC internally by this API */
- rc = mbedtls_x509_get_rsassa_pss_params(&params, &md_alg,
- &pss_opts.mgf1_hash_id,
- &pss_opts.expected_salt_len);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- /* The CryptoCell only supports SHA256 as hash algorithm */
- if (md_alg != MBEDTLS_MD_SHA256 ||
- pss_opts.mgf1_hash_id != MBEDTLS_MD_SHA256)
- return CRYPTO_ERR_SIGNATURE;
-
- if (pss_opts.expected_salt_len != RSA_SALT_LEN)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Parse the public key */
- p = pk_ptr;
- end = p + pk_len;
- rc = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- end = p + len;
- rc = mbedtls_asn1_get_alg_null(&p, end, &alg_oid);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (mbedtls_oid_get_pk_alg(&alg_oid, &pk_alg) != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (pk_alg != MBEDTLS_PK_RSA)
- return CRYPTO_ERR_SIGNATURE;
-
- rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- rc = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (*p == 0) {
- p++; len--;
- }
- if (len != BSV_CERT_RSA_KEY_SIZE_IN_BYTES || ((p + len) > end))
- return CRYPTO_ERR_SIGNATURE;
-
- /*
- * Copy N from certificate.
- */
- memcpy(NBuff, p, BSV_CERT_RSA_KEY_SIZE_IN_BYTES);
-
- /* Verify the RSA exponent */
- p += len;
- rc = mbedtls_asn1_get_int(&p, end, &exp);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (exp != RSA_EXPONENT)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Get the signature (bitstring) */
- p = sig_ptr;
- end = p + sig_len;
- rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
- if (rc != 0)
- return CRYPTO_ERR_SIGNATURE;
-
- if (len != BSV_CERT_RSA_KEY_SIZE_IN_BYTES || ((p + len) > end))
- return CRYPTO_ERR_SIGNATURE;
-
- /*
- * Copy the signature (in BE format)
- */
- memcpy((uint8_t *)signature, p, BSV_CERT_RSA_KEY_SIZE_IN_BYTES);
-
- error = CC_BsvSha256((uintptr_t)PLAT_CRYPTOCELL_BASE,
- data_ptr, data_len, digest);
- if (error != CC_OK)
- return CRYPTO_ERR_SIGNATURE;
-
- /* Verify the signature */
- error = CC_BsvRsaPssVerify((uintptr_t)PLAT_CRYPTOCELL_BASE, NBuff,
- NULL, signature, digest, workspace,
- BSV_RSA_WORKSPACE_MIN_SIZE, &is_verified);
- if ((error != CC_OK) || (is_verified != CC_TRUE))
- return CRYPTO_ERR_SIGNATURE;
-
- /* Signature verification success */
- return CRYPTO_SUCCESS;
-}
-
-/*
- * Match a hash
- *
- * Digest info is passed in DER format following the ASN.1 structure detailed
- * above.
- */
-static int verify_hash(void *data_ptr, unsigned int data_len,
- void *digest_info_ptr, unsigned int digest_info_len)
-{
- mbedtls_asn1_buf hash_oid, params;
- mbedtls_md_type_t md_alg;
- uint8_t *p, *end, *hash;
- CCHashResult_t pubKeyHash;
- size_t len;
- int rc;
- CCError_t error;
-
- /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
- p = digest_info_ptr;
- end = p + digest_info_len;
- rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- /* Get the hash algorithm */
- rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
- /* Verify that hash algorithm is SHA256 */
- if (md_alg != MBEDTLS_MD_SHA256)
- return CRYPTO_ERR_HASH;
-
- /* Hash should be octet string type */
- rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- /* Length of hash must match the algorithm's size */
- if (len != HASH_RESULT_SIZE_IN_BYTES)
- return CRYPTO_ERR_HASH;
-
- hash = p;
- error = CC_BsvSha256((uintptr_t)PLAT_CRYPTOCELL_BASE, data_ptr,
- data_len, pubKeyHash);
- if (error != CC_OK)
- return CRYPTO_ERR_HASH;
-
- rc = memcmp(pubKeyHash, hash, HASH_RESULT_SIZE_IN_BYTES);
- if (rc != 0)
- return CRYPTO_ERR_HASH;
-
- return CRYPTO_SUCCESS;
-}
-
-/*
- * Register crypto library descriptor
- */
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
diff --git a/drivers/auth/cryptocell/713/cryptocell_plat_helpers.c b/drivers/auth/cryptocell/713/cryptocell_plat_helpers.c
deleted file mode 100644
index 17e12807c0..0000000000
--- a/drivers/auth/cryptocell/713/cryptocell_plat_helpers.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2017-2020 ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <plat/common/platform.h>
-#include <tools_share/tbbr_oid.h>
-
-#include <lib/libc/endian.h>
-#include <drivers/arm/cryptocell/713/bsv_api.h>
-#include <drivers/arm/cryptocell/713/bsv_error.h>
-
-/*
- * Return the ROTPK hash
- *
- * Return: 0 = success, Otherwise = error
- */
-int cc_get_rotpk_hash(unsigned char *dst, unsigned int len, unsigned int *flags)
-{
- CCError_t error;
- uint32_t lcs;
- int i;
- uint32_t *key = (uint32_t *)dst;
-
- assert(dst != NULL);
- assert(len >= HASH_RESULT_SIZE_IN_WORDS);
- assert(flags != NULL);
-
- error = CC_BsvLcsGet(PLAT_CRYPTOCELL_BASE, &lcs);
- if (error != CC_OK)
- return 1;
-
- if ((lcs == CC_BSV_CHIP_MANUFACTURE_LCS) || (lcs == CC_BSV_RMA_LCS)) {
- *flags = ROTPK_NOT_DEPLOYED;
- return 0;
- }
-
- error = CC_BsvPubKeyHashGet(PLAT_CRYPTOCELL_BASE,
- CC_SB_HASH_BOOT_KEY_256B,
- key, HASH_RESULT_SIZE_IN_WORDS);
-
- if (error == CC_BSV_HASH_NOT_PROGRAMMED_ERR) {
- *flags = ROTPK_NOT_DEPLOYED;
- return 0;
- }
-
- if (error == CC_OK) {
-
- /* Keys are stored in OTP in little-endian format */
- for (i = 0; i < HASH_RESULT_SIZE_IN_WORDS; i++)
- key[i] = le32toh(key[i]);
-
- *flags = ROTPK_IS_HASH;
- return 0;
- }
-
- return 1;
-}
-
-/*
- * Return the non-volatile counter value stored in the platform. The cookie
- * specifies the OID of the counter in the certificate.
- *
- * Return: 0 = success, Otherwise = error
- */
-int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
-{
- CCError_t error = CC_FAIL;
-
- if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = CC_BsvSwVersionGet(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_TRUSTED, nv_ctr);
- } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = CC_BsvSwVersionGet(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_NON_TRUSTED, nv_ctr);
- }
-
- return (error != CC_OK);
-}
-
-/*
- * Store a new non-volatile counter value in the counter specified by the OID
- * in the cookie. This function is not expected to be called if the Lifecycle
- * state is RMA as the values in the certificate are expected to always match
- * the nvcounter values. But if called when the LCS is RMA, the underlying
- * helper functions will return success but without updating the counter.
- *
- * Return: 0 = success, Otherwise = error
- */
-int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
-{
- CCError_t error = CC_FAIL;
-
- if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = CC_BsvSwVersionSet(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_TRUSTED, nv_ctr);
- } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
- error = CC_BsvSwVersionSet(PLAT_CRYPTOCELL_BASE,
- CC_SW_VERSION_NON_TRUSTED, nv_ctr);
- }
-
- return (error != CC_OK);
-}
-
diff --git a/drivers/auth/cryptocell/cryptocell_crypto.mk b/drivers/auth/cryptocell/cryptocell_crypto.mk
deleted file mode 100644
index db390471fa..0000000000
--- a/drivers/auth/cryptocell/cryptocell_crypto.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-include drivers/auth/mbedtls/mbedtls_common.mk
-
-# The algorithm is RSA when using Cryptocell crypto driver
-TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_RSA
-
-# Needs to be set to drive mbed TLS configuration correctly
-$(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID))
-
-$(eval $(call add_define,KEY_SIZE))
-
-# CCSBROM_LIB_PATH must be set to the Cryptocell SBROM library path
-ifeq (${CCSBROM_LIB_PATH},)
- $(error Error: CCSBROM_LIB_PATH not set)
-endif
-
-CRYPTOCELL_VERSION ?= 712
-ifeq (${CRYPTOCELL_VERSION},712)
- CCSBROM_LIB_FILENAME := cc_712sbromx509
-else ifeq (${CRYPTOCELL_VERSION},713)
- CCSBROM_LIB_FILENAME := cc_713bsv
-else
- $(error Error: CRYPTOCELL_VERSION set to invalid version)
-endif
-
-CRYPTOCELL_SRC_DIR := drivers/auth/cryptocell/${CRYPTOCELL_VERSION}/
-
-CRYPTOCELL_SOURCES := ${CRYPTOCELL_SRC_DIR}/cryptocell_crypto.c \
- ${CRYPTOCELL_SRC_DIR}/cryptocell_plat_helpers.c
-
-TF_LDFLAGS += -L$(CCSBROM_LIB_PATH)
-LDLIBS += -l$(CCSBROM_LIB_FILENAME)
-
-BL1_SOURCES += ${CRYPTOCELL_SOURCES}
-BL2_SOURCES += ${CRYPTOCELL_SOURCES}
diff --git a/drivers/auth/dualroot/cot.c b/drivers/auth/dualroot/cot.c
index e1e47bca0b..c89930c1ef 100644
--- a/drivers/auth/dualroot/cot.c
+++ b/drivers/auth/dualroot/cot.c
@@ -1,17 +1,20 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
-#include <platform_def.h>
+#include <mbedtls/version.h>
-#include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <common/tbbr/cot_def.h>
#include <drivers/auth/auth_mod.h>
+
#include <tools_share/dualroot_oid.h>
+#include <platform_def.h>
+
/*
* Allocate static buffers to store the authentication parameters extracted from
* the certificates.
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
index 4a8efaebb7..4f30d82773 100644
--- a/drivers/auth/mbedtls/mbedtls_common.c
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,10 +10,11 @@
/* mbed TLS headers */
#include <mbedtls/memory_buffer_alloc.h>
#include <mbedtls/platform.h>
+#include <mbedtls/version.h>
#include <common/debug.h>
#include <drivers/auth/mbedtls/mbedtls_common.h>
-#include <drivers/auth/mbedtls/mbedtls_config.h>
+
#include <plat/common/platform.h>
static void cleanup(void)
diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk
index 53ebe30b63..2bb23f961e 100644
--- a/drivers/auth/mbedtls/mbedtls_common.mk
+++ b/drivers/auth/mbedtls/mbedtls_common.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2015-2024, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -15,40 +15,74 @@ endif
MBEDTLS_INC = -I${MBEDTLS_DIR}/include
+MBEDTLS_MAJOR=$(shell grep -hP "define MBEDTLS_VERSION_MAJOR" ${MBEDTLS_DIR}/include/mbedtls/*.h | grep -oe '\([0-9.]*\)')
+MBEDTLS_MINOR=$(shell grep -hP "define MBEDTLS_VERSION_MINOR" ${MBEDTLS_DIR}/include/mbedtls/*.h | grep -oe '\([0-9.]*\)')
+$(info MBEDTLS_VERSION_MAJOR is [${MBEDTLS_MAJOR}] MBEDTLS_VERSION_MINOR is [${MBEDTLS_MINOR}])
+
+ifneq (${MBEDTLS_MAJOR}, 3)
+ $(error Error: TF-A only supports MbedTLS versions > 3.x)
+endif
+
# Specify mbed TLS configuration file
-MBEDTLS_CONFIG_FILE := "<drivers/auth/mbedtls/mbedtls_config.h>"
+ifeq (${PSA_CRYPTO},1)
+ MBEDTLS_CONFIG_FILE ?= "<drivers/auth/mbedtls/psa_mbedtls_config.h>"
+else
+ MBEDTLS_CONFIG_FILE ?= "<drivers/auth/mbedtls/mbedtls_config-3.h>"
+endif
+
$(eval $(call add_define,MBEDTLS_CONFIG_FILE))
MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_common.c
+LIBMBEDTLS_SRCS += $(addprefix ${MBEDTLS_DIR}/library/, \
+ aes.c \
+ asn1parse.c \
+ asn1write.c \
+ cipher.c \
+ cipher_wrap.c \
+ constant_time.c \
+ hash_info.c \
+ memory_buffer_alloc.c \
+ oid.c \
+ platform.c \
+ platform_util.c \
+ bignum.c \
+ bignum_core.c \
+ gcm.c \
+ md.c \
+ pk.c \
+ pk_wrap.c \
+ pkparse.c \
+ pkwrite.c \
+ sha256.c \
+ sha512.c \
+ ecdsa.c \
+ ecp_curves.c \
+ ecp.c \
+ rsa.c \
+ rsa_alt_helpers.c \
+ x509.c \
+ x509_crt.c \
+ )
+
+# Currently on Mbedtls-3 there is outstanding bug due to usage
+# of redundant declaration[1], So disable redundant-decls
+# compilation flag to avoid compilation error when compiling with
+# Mbedtls-3.
+# [1]: https://github.com/Mbed-TLS/mbedtls/issues/6910
+LIBMBEDTLS_CFLAGS += -Wno-error=redundant-decls
-LIBMBEDTLS_SRCS := $(addprefix ${MBEDTLS_DIR}/library/, \
- aes.c \
- asn1parse.c \
- asn1write.c \
- cipher.c \
- cipher_wrap.c \
- memory_buffer_alloc.c \
- oid.c \
- platform.c \
- platform_util.c \
- bignum.c \
- gcm.c \
- md.c \
- pk.c \
- pk_wrap.c \
- pkparse.c \
- pkwrite.c \
- sha256.c \
- sha512.c \
- ecdsa.c \
- ecp_curves.c \
- ecp.c \
- rsa.c \
- rsa_internal.c \
- x509.c \
- x509_crt.c \
+ifeq (${PSA_CRYPTO},1)
+LIBMBEDTLS_SRCS += $(addprefix ${MBEDTLS_DIR}/library/, \
+ psa_crypto.c \
+ psa_crypto_client.c \
+ psa_crypto_driver_wrappers.c \
+ psa_crypto_hash.c \
+ psa_crypto_rsa.c \
+ psa_crypto_ecp.c \
+ psa_crypto_slot_management.c \
)
+endif
# The platform may define the variable 'TF_MBEDTLS_KEY_ALG' to select the key
# algorithm to use. If the variable is not defined, select it based on
@@ -64,11 +98,21 @@ endif
ifeq (${TF_MBEDTLS_KEY_SIZE},)
ifneq ($(findstring rsa,${TF_MBEDTLS_KEY_ALG}),)
- ifeq (${KEY_SIZE},)
+ ifeq (${KEY_SIZE},)
TF_MBEDTLS_KEY_SIZE := 2048
- else
+ else ifneq ($(filter $(KEY_SIZE), 1024 2048 3072 4096),)
+ TF_MBEDTLS_KEY_SIZE := ${KEY_SIZE}
+ else
+ $(error "Invalid value for KEY_SIZE: ${KEY_SIZE}")
+ endif
+ else ifneq ($(findstring ecdsa,${TF_MBEDTLS_KEY_ALG}),)
+ ifeq (${KEY_SIZE},)
+ TF_MBEDTLS_KEY_SIZE := 256
+ else ifneq ($(filter $(KEY_SIZE), 256 384),)
TF_MBEDTLS_KEY_SIZE := ${KEY_SIZE}
- endif
+ else
+ $(error "Invalid value for KEY_SIZE: ${KEY_SIZE}")
+ endif
endif
endif
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
index 6d6efb5036..230cec9d4d 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.c
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,16 +14,29 @@
#include <mbedtls/memory_buffer_alloc.h>
#include <mbedtls/oid.h>
#include <mbedtls/platform.h>
+#include <mbedtls/version.h>
#include <mbedtls/x509.h>
#include <common/debug.h>
#include <drivers/auth/crypto_mod.h>
#include <drivers/auth/mbedtls/mbedtls_common.h>
-#include <drivers/auth/mbedtls/mbedtls_config.h>
+
#include <plat/common/platform.h>
#define LIB_NAME "mbed TLS"
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * CRYPTO_MD_MAX_SIZE value is as per current stronger algorithm available
+ * so make sure that mbed TLS MD maximum size must be lesser than this.
+ */
+CASSERT(CRYPTO_MD_MAX_SIZE >= MBEDTLS_MD_MAX_SIZE,
+ assert_mbedtls_md_size_overflow);
+
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
/*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
@@ -50,6 +63,8 @@ static void init(void)
mbedtls_init();
}
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
/*
* Verify a signature.
*
@@ -101,7 +116,7 @@ static int verify_signature(void *data_ptr, unsigned int data_len,
end = (unsigned char *)(p + sig_len);
signature.tag = *p;
rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len);
- if (rc != 0) {
+ if ((rc != 0) || ((size_t)(end - p) != signature.len)) {
rc = CRYPTO_ERR_SIGNATURE;
goto end1;
}
@@ -156,7 +171,11 @@ static int verify_hash(void *data_ptr, unsigned int data_len,
size_t len;
int rc;
- /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
+ /*
+ * Digest info should be an MBEDTLS_ASN1_SEQUENCE, but padding after
+ * it is allowed. This is necessary to support multiple hash
+ * algorithms.
+ */
p = (unsigned char *)digest_info_ptr;
end = p + digest_info_len;
rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
@@ -165,6 +184,8 @@ static int verify_hash(void *data_ptr, unsigned int data_len,
return CRYPTO_ERR_HASH;
}
+ end = p + len;
+
/* Get the hash algorithm */
rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
if (rc != 0) {
@@ -181,9 +202,9 @@ static int verify_hash(void *data_ptr, unsigned int data_len,
return CRYPTO_ERR_HASH;
}
- /* Hash should be octet string type */
+ /* Hash should be octet string type and consume all bytes */
rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
- if (rc != 0) {
+ if ((rc != 0) || ((size_t)(end - p) != len)) {
return CRYPTO_ERR_HASH;
}
@@ -208,27 +229,55 @@ static int verify_hash(void *data_ptr, unsigned int data_len,
return CRYPTO_SUCCESS;
}
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * Map a generic crypto message digest algorithm to the corresponding macro used
+ * by Mbed TLS.
+ */
+static inline mbedtls_md_type_t md_type(enum crypto_md_algo algo)
+{
+ switch (algo) {
+ case CRYPTO_MD_SHA512:
+ return MBEDTLS_MD_SHA512;
+ case CRYPTO_MD_SHA384:
+ return MBEDTLS_MD_SHA384;
+ case CRYPTO_MD_SHA256:
+ return MBEDTLS_MD_SHA256;
+ default:
+ /* Invalid hash algorithm. */
+ return MBEDTLS_MD_NONE;
+ }
+}
-#if MEASURED_BOOT
/*
* Calculate a hash
*
* output points to the computed hash
*/
-int calc_hash(unsigned int alg, void *data_ptr,
- unsigned int data_len, unsigned char *output)
+static int calc_hash(enum crypto_md_algo md_algo, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE])
{
const mbedtls_md_info_t *md_info;
- md_info = mbedtls_md_info_from_type((mbedtls_md_type_t)alg);
+ md_info = mbedtls_md_info_from_type(md_type(md_algo));
if (md_info == NULL) {
return CRYPTO_ERR_HASH;
}
- /* Calculate the hash of the data */
+ /*
+ * Calculate the hash of the data, it is safe to pass the
+ * 'output' hash buffer pointer considering its size is always
+ * bigger than or equal to MBEDTLS_MD_MAX_SIZE.
+ */
return mbedtls_md(md_info, data_ptr, data_len, output);
}
-#endif /* MEASURED_BOOT */
+#endif /* CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
#if TF_MBEDTLS_USE_AES_GCM
/*
@@ -249,6 +298,7 @@ static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
unsigned char *pt = data_ptr;
size_t dec_len;
int diff, i, rc;
+ size_t output_length __unused;
mbedtls_gcm_init(&ctx);
@@ -258,7 +308,11 @@ static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
goto exit_gcm;
}
+#if (MBEDTLS_VERSION_MAJOR < 3)
rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len, NULL, 0);
+#else
+ rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len);
+#endif
if (rc != 0) {
rc = CRYPTO_ERR_DECRYPTION;
goto exit_gcm;
@@ -267,7 +321,12 @@ static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
while (len > 0) {
dec_len = MIN(sizeof(buf), len);
+#if (MBEDTLS_VERSION_MAJOR < 3)
rc = mbedtls_gcm_update(&ctx, dec_len, pt, buf);
+#else
+ rc = mbedtls_gcm_update(&ctx, pt, dec_len, buf, sizeof(buf), &output_length);
+#endif
+
if (rc != 0) {
rc = CRYPTO_ERR_DECRYPTION;
goto exit_gcm;
@@ -278,7 +337,12 @@ static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
len -= dec_len;
}
+#if (MBEDTLS_VERSION_MAJOR < 3)
rc = mbedtls_gcm_finish(&ctx, tag_buf, sizeof(tag_buf));
+#else
+ rc = mbedtls_gcm_finish(&ctx, NULL, 0, &output_length, tag_buf, sizeof(tag_buf));
+#endif
+
if (rc != 0) {
rc = CRYPTO_ERR_DECRYPTION;
goto exit_gcm;
@@ -332,19 +396,22 @@ static int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
/*
* Register crypto library descriptor
*/
-#if MEASURED_BOOT
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
#if TF_MBEDTLS_USE_AES_GCM
REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
- auth_decrypt);
+ auth_decrypt, NULL);
#else
REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
- NULL);
+ NULL, NULL);
#endif
-#else /* MEASURED_BOOT */
+#elif CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY
#if TF_MBEDTLS_USE_AES_GCM
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash,
- auth_decrypt);
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
+ auth_decrypt, NULL);
#else
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
+ NULL, NULL);
#endif
-#endif /* MEASURED_BOOT */
+#elif CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY
+REGISTER_CRYPTO_LIB(LIB_NAME, init, NULL, NULL, calc_hash, NULL, NULL);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.mk b/drivers/auth/mbedtls/mbedtls_crypto.mk
index 2a9fbbf99a..bd367300b3 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.mk
+++ b/drivers/auth/mbedtls/mbedtls_crypto.mk
@@ -1,11 +1,16 @@
#
-# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
include drivers/auth/mbedtls/mbedtls_common.mk
-MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_crypto.c
-
-
+ifeq (${PSA_CRYPTO},1)
+ # Some of the PSA functions are declared in multiple header files
+ # that triggers this warning.
+ TF_CFLAGS += -Wno-error=redundant-decls
+ MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_psa_crypto.c
+else
+ MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_crypto.c
+endif
diff --git a/drivers/auth/mbedtls/mbedtls_psa_crypto.c b/drivers/auth/mbedtls/mbedtls_psa_crypto.c
new file mode 100644
index 0000000000..5891acf371
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_psa_crypto.c
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+/* mbed TLS headers */
+#include <mbedtls/gcm.h>
+#include <mbedtls/md.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+#include <mbedtls/version.h>
+#include <mbedtls/x509.h>
+#include <psa/crypto.h>
+#include <psa/crypto_platform.h>
+#include <psa/crypto_types.h>
+#include <psa/crypto_values.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <plat/common/platform.h>
+
+#define LIB_NAME "mbed TLS PSA"
+
+/* Maximum length of R_S pair in the ECDSA signature in bytes */
+#define MAX_ECDSA_R_S_PAIR_LEN 64U
+
+/* Size of ASN.1 length and tag in bytes*/
+#define SIZE_OF_ASN1_LEN 1U
+#define SIZE_OF_ASN1_TAG 1U
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * CRYPTO_MD_MAX_SIZE value is as per current stronger algorithm available
+ * so make sure that mbed TLS MD maximum size must be lesser than this.
+ */
+CASSERT(CRYPTO_MD_MAX_SIZE >= MBEDTLS_MD_MAX_SIZE,
+ assert_mbedtls_md_size_overflow);
+
+#endif /*
+ * CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ */
+
+static inline psa_algorithm_t mbedtls_md_psa_alg_from_type(
+ mbedtls_md_type_t md_type)
+{
+ assert((md_type == MBEDTLS_MD_SHA256) ||
+ (md_type == MBEDTLS_MD_SHA384) ||
+ (md_type == MBEDTLS_MD_SHA512));
+
+ return PSA_ALG_CATEGORY_HASH | (psa_algorithm_t) (md_type + 0x5);
+}
+
+/*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING
+ * }
+ */
+
+/*
+ * We pretend using an external RNG (through MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+ * mbedTLS config option) so we need to provide an implementation of
+ * mbedtls_psa_external_get_random(). Provide a fake one, since we do not
+ * actually have any external RNG and TF-A itself doesn't engage in
+ * cryptographic operations that demands randomness.
+ */
+psa_status_t mbedtls_psa_external_get_random(
+ mbedtls_psa_external_random_context_t *context,
+ uint8_t *output, size_t output_size,
+ size_t *output_length)
+{
+ return PSA_ERROR_INSUFFICIENT_ENTROPY;
+}
+
+/*
+ * Initialize the library and export the descriptor
+ */
+static void init(void)
+{
+ /* Initialize mbed TLS */
+ mbedtls_init();
+
+ /* Initialise PSA mbedTLS */
+ psa_status_t status = psa_crypto_init();
+
+ if (status != PSA_SUCCESS) {
+ ERROR("Failed to initialize %s crypto (%d).\n", LIB_NAME, status);
+ panic();
+ }
+
+ INFO("PSA crypto initialized successfully!\n");
+}
+
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+
+static void construct_psa_key_alg_and_type(mbedtls_pk_type_t pk_alg,
+ mbedtls_md_type_t md_alg,
+ psa_ecc_family_t psa_ecc_family,
+ psa_algorithm_t *psa_alg,
+ psa_key_type_t *psa_key_type)
+{
+ psa_algorithm_t psa_md_alg = mbedtls_md_psa_alg_from_type(md_alg);
+
+ switch (pk_alg) {
+ case MBEDTLS_PK_RSASSA_PSS:
+ *psa_alg = PSA_ALG_RSA_PSS(psa_md_alg);
+ *psa_key_type = PSA_KEY_TYPE_RSA_PUBLIC_KEY;
+ break;
+ case MBEDTLS_PK_ECDSA:
+ *psa_alg = PSA_ALG_ECDSA(psa_md_alg);
+ *psa_key_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(psa_ecc_family);
+ break;
+ default:
+ *psa_alg = PSA_ALG_NONE;
+ *psa_key_type = PSA_KEY_TYPE_NONE;
+ break;
+ }
+}
+
+
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+
+/*
+ * This is a helper function to detect padding byte (if the MSB bit of the
+ * first data byte is set to 1, for example 0x80) and on detection, ignore the
+ * padded byte(0x00) and increase the buffer pointer beyond padded byte and
+ * decrease the length of the buffer by 1.
+ *
+ * On Success returns 0, error otherwise.
+ **/
+static inline int ignore_asn1_int_padding_byte(unsigned char **buf_start,
+ size_t *buf_len)
+{
+ unsigned char *local_buf = *buf_start;
+
+ /* Check for negative number */
+ if ((local_buf[0] & 0x80U) != 0U) {
+ return -1;
+ }
+
+ if ((local_buf[0] == 0U) && (local_buf[1] > 0x7FU) &&
+ (*buf_len > 1U)) {
+ *buf_start = &local_buf[1];
+ (*buf_len)--;
+ }
+
+ return 0;
+}
+
+/*
+ * This is a helper function that gets a pointer to the encoded ECDSA publicKey
+ * and its length (as per RFC5280) and returns corresponding decoded publicKey
+ * and its length. As well, it retrieves the family of ECC key in the PSA
+ * format.
+ *
+ * This function returns error(CRYPTO_ERR_SIGNATURE) on ASN.1 parsing failure,
+ * otherwise success(0).
+ **/
+static int get_ecdsa_pkinfo_from_asn1(unsigned char **pk_start,
+ unsigned int *pk_len,
+ psa_ecc_family_t *psa_ecc_family)
+{
+ mbedtls_asn1_buf alg_oid, alg_params;
+ mbedtls_ecp_group_id grp_id;
+ int rc;
+ unsigned char *pk_end;
+ size_t len;
+ size_t curve_bits;
+ unsigned char *pk_ptr = *pk_start;
+
+ pk_end = pk_ptr + *pk_len;
+ rc = mbedtls_asn1_get_tag(&pk_ptr, pk_end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ pk_end = pk_ptr + len;
+ rc = mbedtls_asn1_get_alg(&pk_ptr, pk_end, &alg_oid, &alg_params);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ if (alg_params.tag == MBEDTLS_ASN1_OID) {
+ if (mbedtls_oid_get_ec_grp(&alg_params, &grp_id) != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+ *psa_ecc_family = mbedtls_ecc_group_to_psa(grp_id,
+ &curve_bits);
+ } else {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ pk_end = pk_ptr + len - (alg_oid.len + alg_params.len +
+ 2 * (SIZE_OF_ASN1_LEN + SIZE_OF_ASN1_TAG));
+ rc = mbedtls_asn1_get_bitstring_null(&pk_ptr, pk_end, &len);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ *pk_start = pk_ptr;
+ *pk_len = len;
+
+ return rc;
+}
+
+/*
+ * Ecdsa-Sig-Value ::= SEQUENCE {
+ * r INTEGER,
+ * s INTEGER
+ * }
+ *
+ * This helper function that gets a pointer to the encoded ECDSA signature and
+ * its length (as per RFC5280) and returns corresponding decoded signature
+ * (R_S pair) and its size.
+ *
+ * This function returns error(CRYPTO_ERR_SIGNATURE) on ASN.1 parsing failure,
+ * otherwise success(0).
+ **/
+static int get_ecdsa_signature_from_asn1(unsigned char *sig_ptr,
+ size_t *sig_len,
+ unsigned char *r_s_pair)
+{
+ int rc;
+ unsigned char *sig_end;
+ size_t len, r_len, s_len;
+
+ sig_end = sig_ptr + *sig_len;
+ rc = mbedtls_asn1_get_tag(&sig_ptr, sig_end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ sig_end = sig_ptr + len;
+ rc = mbedtls_asn1_get_tag(&sig_ptr, sig_end, &r_len,
+ MBEDTLS_ASN1_INTEGER);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ if (ignore_asn1_int_padding_byte(&sig_ptr, &r_len) != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ (void)memcpy((void *)&r_s_pair[0], (const void *)sig_ptr, r_len);
+
+ sig_ptr = sig_ptr + r_len;
+ sig_end = sig_ptr + len - (r_len + (SIZE_OF_ASN1_LEN +
+ SIZE_OF_ASN1_TAG));
+ rc = mbedtls_asn1_get_tag(&sig_ptr, sig_end, &s_len,
+ MBEDTLS_ASN1_INTEGER);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ if (ignore_asn1_int_padding_byte(&sig_ptr, &s_len) != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ (void)memcpy((void *)&r_s_pair[r_len], (const void *)sig_ptr, s_len);
+
+ *sig_len = s_len + r_len;
+
+ return 0;
+}
+#endif /*
+ * TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+ * TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+ **/
+
+/*
+ * Verify a signature.
+ *
+ * Parameters are passed using the DER encoding format following the ASN.1
+ * structures detailed above.
+ */
+static int verify_signature(void *data_ptr, unsigned int data_len,
+ void *sig_ptr, unsigned int sig_len,
+ void *sig_alg, unsigned int sig_alg_len,
+ void *pk_ptr, unsigned int pk_len)
+{
+ mbedtls_asn1_buf sig_oid, sig_params;
+ mbedtls_asn1_buf signature;
+ mbedtls_md_type_t md_alg;
+ mbedtls_pk_type_t pk_alg;
+ int rc;
+ void *sig_opts = NULL;
+ unsigned char *p, *end;
+ unsigned char *local_sig_ptr;
+ size_t local_sig_len;
+ psa_ecc_family_t psa_ecc_family = 0U;
+ __unused unsigned char reformatted_sig[MAX_ECDSA_R_S_PAIR_LEN] = {0};
+
+ /* construct PSA key algo and type */
+ psa_status_t status = PSA_SUCCESS;
+ psa_key_attributes_t psa_key_attr = PSA_KEY_ATTRIBUTES_INIT;
+ psa_key_id_t psa_key_id = PSA_KEY_ID_NULL;
+ psa_key_type_t psa_key_type;
+ psa_algorithm_t psa_alg;
+
+ /* Get pointers to signature OID and parameters */
+ p = (unsigned char *)sig_alg;
+ end = (unsigned char *)(p + sig_alg_len);
+ rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* Get the actual signature algorithm (MD + PK) */
+ rc = mbedtls_x509_get_sig_alg(&sig_oid, &sig_params, &md_alg, &pk_alg, &sig_opts);
+ if (rc != 0) {
+ return CRYPTO_ERR_SIGNATURE;
+ }
+
+ /* Get the signature (bitstring) */
+ p = (unsigned char *)sig_ptr;
+ end = (unsigned char *)(p + sig_len);
+ signature.tag = *p;
+ rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len);
+ if ((rc != 0) || ((size_t)(end - p) != signature.len)) {
+ rc = CRYPTO_ERR_SIGNATURE;
+ goto end2;
+ }
+
+ local_sig_ptr = p;
+ local_sig_len = signature.len;
+
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+ if (pk_alg == MBEDTLS_PK_ECDSA) {
+ rc = get_ecdsa_signature_from_asn1(local_sig_ptr,
+ &local_sig_len,
+ reformatted_sig);
+ if (rc != 0) {
+ goto end2;
+ }
+
+ local_sig_ptr = reformatted_sig;
+
+ rc = get_ecdsa_pkinfo_from_asn1((unsigned char **)&pk_ptr,
+ &pk_len,
+ &psa_ecc_family);
+ if (rc != 0) {
+ goto end2;
+ }
+ }
+#endif /*
+ * TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA || \
+ * TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+ **/
+
+ /* Convert this pk_alg and md_alg to PSA key type and key algorithm */
+ construct_psa_key_alg_and_type(pk_alg, md_alg, psa_ecc_family,
+ &psa_alg, &psa_key_type);
+
+
+ if ((psa_alg == PSA_ALG_NONE) || (psa_key_type == PSA_KEY_TYPE_NONE)) {
+ rc = CRYPTO_ERR_SIGNATURE;
+ goto end2;
+ }
+
+ /* filled-in key_attributes */
+ psa_set_key_algorithm(&psa_key_attr, psa_alg);
+ psa_set_key_type(&psa_key_attr, psa_key_type);
+ psa_set_key_usage_flags(&psa_key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
+
+ /* Get the key_id using import API */
+ status = psa_import_key(&psa_key_attr,
+ pk_ptr,
+ (size_t)pk_len,
+ &psa_key_id);
+
+ if (status != PSA_SUCCESS) {
+ rc = CRYPTO_ERR_SIGNATURE;
+ goto end2;
+ }
+
+ /*
+ * Hash calculation and Signature verification of the given data payload
+ * is wrapped under the psa_verify_message function.
+ */
+ status = psa_verify_message(psa_key_id, psa_alg,
+ data_ptr, data_len,
+ local_sig_ptr, local_sig_len);
+
+ if (status != PSA_SUCCESS) {
+ rc = CRYPTO_ERR_SIGNATURE;
+ goto end1;
+ }
+
+ /* Signature verification success */
+ rc = CRYPTO_SUCCESS;
+
+end1:
+ /*
+ * Destroy the key if it is created successfully
+ */
+ psa_destroy_key(psa_key_id);
+end2:
+ mbedtls_free(sig_opts);
+ return rc;
+}
+
+/*
+ * Match a hash
+ *
+ * Digest info is passed in DER format following the ASN.1 structure detailed
+ * above.
+ */
+static int verify_hash(void *data_ptr, unsigned int data_len,
+ void *digest_info_ptr, unsigned int digest_info_len)
+{
+ mbedtls_asn1_buf hash_oid, params;
+ mbedtls_md_type_t md_alg;
+ unsigned char *p, *end, *hash;
+ size_t len;
+ int rc;
+ psa_status_t status;
+ psa_algorithm_t psa_md_alg;
+
+ /*
+ * Digest info should be an MBEDTLS_ASN1_SEQUENCE, but padding after
+ * it is allowed. This is necessary to support multiple hash
+ * algorithms.
+ */
+ p = (unsigned char *)digest_info_ptr;
+ end = p + digest_info_len;
+ rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE);
+ if (rc != 0) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ end = p + len;
+
+ /* Get the hash algorithm */
+ rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
+ if (rc != 0) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ /* Hash should be octet string type and consume all bytes */
+ rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
+ if ((rc != 0) || ((size_t)(end - p) != len)) {
+ return CRYPTO_ERR_HASH;
+ }
+ hash = p;
+
+ rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
+ if (rc != 0) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ /* convert the md_alg to psa_algo */
+ psa_md_alg = mbedtls_md_psa_alg_from_type(md_alg);
+
+ /* Length of hash must match the algorithm's size */
+ if (len != PSA_HASH_LENGTH(psa_md_alg)) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ /*
+ * Calculate Hash and compare it against the retrieved hash from
+ * the certificate (one shot API).
+ */
+ status = psa_hash_compare(psa_md_alg,
+ data_ptr, (size_t)data_len,
+ (const uint8_t *)hash, len);
+
+ if (status != PSA_SUCCESS) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ return CRYPTO_SUCCESS;
+}
+#endif /*
+ * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY || \
+ * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ */
+
+#if CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+/*
+ * Map a generic crypto message digest algorithm to the corresponding macro used
+ * by Mbed TLS.
+ */
+static inline mbedtls_md_type_t md_type(enum crypto_md_algo algo)
+{
+ switch (algo) {
+ case CRYPTO_MD_SHA512:
+ return MBEDTLS_MD_SHA512;
+ case CRYPTO_MD_SHA384:
+ return MBEDTLS_MD_SHA384;
+ case CRYPTO_MD_SHA256:
+ return MBEDTLS_MD_SHA256;
+ default:
+ /* Invalid hash algorithm. */
+ return MBEDTLS_MD_NONE;
+ }
+}
+
+/*
+ * Calculate a hash
+ *
+ * output points to the computed hash
+ */
+static int calc_hash(enum crypto_md_algo md_algo, void *data_ptr,
+ unsigned int data_len,
+ unsigned char output[CRYPTO_MD_MAX_SIZE])
+{
+ size_t hash_length;
+ psa_status_t status;
+ psa_algorithm_t psa_md_alg;
+
+ /* convert the md_alg to psa_algo */
+ psa_md_alg = mbedtls_md_psa_alg_from_type(md_type(md_algo));
+
+ /*
+ * Calculate the hash of the data, it is safe to pass the
+ * 'output' hash buffer pointer considering its size is always
+ * bigger than or equal to MBEDTLS_MD_MAX_SIZE.
+ */
+ status = psa_hash_compute(psa_md_alg, data_ptr, (size_t)data_len,
+ (uint8_t *)output, CRYPTO_MD_MAX_SIZE,
+ &hash_length);
+ if (status != PSA_SUCCESS) {
+ return CRYPTO_ERR_HASH;
+ }
+
+ return CRYPTO_SUCCESS;
+}
+#endif /*
+ * CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY || \
+ * CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+ */
+
+#if TF_MBEDTLS_USE_AES_GCM
+/*
+ * Stack based buffer allocation for decryption operation. It could
+ * be configured to balance stack usage vs execution speed.
+ */
+#define DEC_OP_BUF_SIZE 128
+
+static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
+ unsigned int key_len, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len)
+{
+ mbedtls_gcm_context ctx;
+ mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
+ unsigned char buf[DEC_OP_BUF_SIZE];
+ unsigned char tag_buf[CRYPTO_MAX_TAG_SIZE];
+ unsigned char *pt = data_ptr;
+ size_t dec_len;
+ int diff, i, rc;
+ size_t output_length __unused;
+
+ mbedtls_gcm_init(&ctx);
+
+ rc = mbedtls_gcm_setkey(&ctx, cipher, key, key_len * 8);
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+#if (MBEDTLS_VERSION_MAJOR < 3)
+ rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len, NULL, 0);
+#else
+ rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len);
+#endif
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ while (len > 0) {
+ dec_len = MIN(sizeof(buf), len);
+
+#if (MBEDTLS_VERSION_MAJOR < 3)
+ rc = mbedtls_gcm_update(&ctx, dec_len, pt, buf);
+#else
+ rc = mbedtls_gcm_update(&ctx, pt, dec_len, buf, sizeof(buf), &output_length);
+#endif
+
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ memcpy(pt, buf, dec_len);
+ pt += dec_len;
+ len -= dec_len;
+ }
+
+#if (MBEDTLS_VERSION_MAJOR < 3)
+ rc = mbedtls_gcm_finish(&ctx, tag_buf, sizeof(tag_buf));
+#else
+ rc = mbedtls_gcm_finish(&ctx, NULL, 0, &output_length, tag_buf, sizeof(tag_buf));
+#endif
+
+ if (rc != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ /* Check tag in "constant-time" */
+ for (diff = 0, i = 0; i < tag_len; i++)
+ diff |= ((const unsigned char *)tag)[i] ^ tag_buf[i];
+
+ if (diff != 0) {
+ rc = CRYPTO_ERR_DECRYPTION;
+ goto exit_gcm;
+ }
+
+ /* GCM decryption success */
+ rc = CRYPTO_SUCCESS;
+
+exit_gcm:
+ mbedtls_gcm_free(&ctx);
+ return rc;
+}
+
+/*
+ * Authenticated decryption of an image
+ */
+static int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+ size_t len, const void *key, unsigned int key_len,
+ unsigned int key_flags, const void *iv,
+ unsigned int iv_len, const void *tag,
+ unsigned int tag_len)
+{
+ int rc;
+
+ assert((key_flags & ENC_KEY_IS_IDENTIFIER) == 0);
+
+ switch (dec_algo) {
+ case CRYPTO_GCM_DECRYPT:
+ rc = aes_gcm_decrypt(data_ptr, len, key, key_len, iv, iv_len,
+ tag, tag_len);
+ if (rc != 0)
+ return rc;
+ break;
+ default:
+ return CRYPTO_ERR_DECRYPTION;
+ }
+
+ return CRYPTO_SUCCESS;
+}
+#endif /* TF_MBEDTLS_USE_AES_GCM */
+
+/*
+ * Register crypto library descriptor
+ */
+#if CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC
+#if TF_MBEDTLS_USE_AES_GCM
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
+ auth_decrypt, NULL);
+#else
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
+ NULL, NULL);
+#endif
+#elif CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_ONLY
+#if TF_MBEDTLS_USE_AES_GCM
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
+ auth_decrypt, NULL);
+#else
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL,
+ NULL, NULL);
+#endif
+#elif CRYPTO_SUPPORT == CRYPTO_HASH_CALC_ONLY
+REGISTER_CRYPTO_LIB(LIB_NAME, init, NULL, NULL, calc_hash, NULL, NULL);
+#endif /* CRYPTO_SUPPORT == CRYPTO_AUTH_VERIFY_AND_HASH_CALC */
diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c
index 129566bd69..8bde5bb7cc 100644
--- a/drivers/auth/mbedtls/mbedtls_x509_parser.c
+++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -66,68 +66,115 @@ static void clear_temp_vars(void)
* Get X509v3 extension
*
* Global variable 'v3_ext' must point to the extensions region
- * in the certificate. No need to check for errors since the image has passed
- * the integrity check.
+ * in the certificate. OID may be NULL to request that get_ext()
+ * is only being called for integrity checking.
*/
static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
{
- int oid_len;
+ int oid_len, ret, is_critical;
size_t len;
- unsigned char *end_ext_data, *end_ext_octet;
unsigned char *p;
const unsigned char *end;
char oid_str[MAX_OID_STR_LEN];
mbedtls_asn1_buf extn_oid;
- int is_critical;
-
- assert(oid != NULL);
p = v3_ext.p;
end = v3_ext.p + v3_ext.len;
- mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
-
- while (p < end) {
- zeromem(&extn_oid, sizeof(extn_oid));
- is_critical = 0; /* DEFAULT FALSE */
+ /*
+ * Check extensions integrity. At least one extension is
+ * required: the ASN.1 specifies a minimum size of 1, and at
+ * least one extension is needed to authenticate the next stage
+ * in the boot chain.
+ */
+ do {
+ unsigned char *end_ext_data;
- mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
+ ret = mbedtls_asn1_get_tag(&p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE);
+ if (ret != 0) {
+ return IMG_PARSER_ERR_FORMAT;
+ }
end_ext_data = p + len;
/* Get extension ID */
- extn_oid.tag = *p;
- mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID);
+ ret = mbedtls_asn1_get_tag(&p, end_ext_data, &extn_oid.len,
+ MBEDTLS_ASN1_OID);
+ if (ret != 0) {
+ return IMG_PARSER_ERR_FORMAT;
+ }
+ extn_oid.tag = MBEDTLS_ASN1_OID;
extn_oid.p = p;
p += extn_oid.len;
/* Get optional critical */
- mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
+ ret = mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
+ if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
+ return IMG_PARSER_ERR_FORMAT;
+ }
- /* Extension data */
- mbedtls_asn1_get_tag(&p, end_ext_data, &len,
- MBEDTLS_ASN1_OCTET_STRING);
- end_ext_octet = p + len;
+ /*
+ * Data should be octet string type and must use all bytes in
+ * the Extension.
+ */
+ ret = mbedtls_asn1_get_tag(&p, end_ext_data, &len,
+ MBEDTLS_ASN1_OCTET_STRING);
+ if ((ret != 0) || ((p + len) != end_ext_data)) {
+ return IMG_PARSER_ERR_FORMAT;
+ }
/* Detect requested extension */
oid_len = mbedtls_oid_get_numeric_string(oid_str,
MAX_OID_STR_LEN,
&extn_oid);
- if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
+ if ((oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) || (oid_len < 0)) {
return IMG_PARSER_ERR;
}
- if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
+
+ if ((oid != NULL) &&
+ ((size_t)oid_len == strlen(oid_str)) &&
+ (strcmp(oid, oid_str) == 0)) {
+ /* Extension must be ASN.1 DER */
+ if (len < 2) {
+ /* too short */
+ return IMG_PARSER_ERR_FORMAT;
+ }
+
+ if ((p[0] & 0x1F) == 0x1F) {
+ /* multi-byte ASN.1 DER tag, not allowed */
+ return IMG_PARSER_ERR_FORMAT;
+ }
+
+ if ((p[0] & 0xDF) == 0) {
+ /* UNIVERSAL 0 tag, not allowed */
+ return IMG_PARSER_ERR_FORMAT;
+ }
+
*ext = (void *)p;
*ext_len = (unsigned int)len;
+
+ /* Advance past the tag byte */
+ p++;
+
+ if (mbedtls_asn1_get_len(&p, end_ext_data, &len)) {
+ /* not valid DER */
+ return IMG_PARSER_ERR_FORMAT;
+ }
+
+ if (p + len != end_ext_data) {
+ /* junk after ASN.1 object */
+ return IMG_PARSER_ERR_FORMAT;
+ }
+
return IMG_PARSER_OK;
}
/* Next */
- p = end_ext_octet;
- }
+ p = end_ext_data;
+ } while (p < end);
- return IMG_PARSER_ERR_NOT_FOUND;
+ return (oid == NULL) ? IMG_PARSER_OK : IMG_PARSER_ERR_NOT_FOUND;
}
@@ -142,14 +189,30 @@ static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
*/
static int cert_parse(void *img, unsigned int img_len)
{
- int ret, is_critical;
+ int ret;
size_t len;
- unsigned char *p, *end, *crt_end;
- mbedtls_asn1_buf sig_alg1, sig_alg2;
+ unsigned char *p, *end, *crt_end, *pk_end;
+ mbedtls_asn1_buf sig_alg1;
+ /*
+ * The unique ASN.1 DER encoding of [0] EXPLICIT INTEGER { v3(2} }.
+ */
+ static const char v3[] = {
+ /* The outer CONTEXT SPECIFIC 0 tag */
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0,
+ /* The number bytes used to encode the inner INTEGER */
+ 3,
+ /* The tag of the inner INTEGER */
+ MBEDTLS_ASN1_INTEGER,
+ /* The number of bytes needed to represent 2 */
+ 1,
+ /* The actual value 2 */
+ 2,
+ };
p = (unsigned char *)img;
len = img_len;
- end = p + len;
+ crt_end = p + len;
+ end = crt_end;
/*
* Certificate ::= SEQUENCE {
@@ -159,14 +222,9 @@ static int cert_parse(void *img, unsigned int img_len)
*/
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE);
- if (ret != 0) {
- return IMG_PARSER_ERR_FORMAT;
- }
-
- if (len > (size_t)(end - p)) {
+ if ((ret != 0) || ((p + len) != end)) {
return IMG_PARSER_ERR_FORMAT;
}
- crt_end = p + len;
/*
* TBSCertificate ::= SEQUENCE {
@@ -181,15 +239,14 @@ static int cert_parse(void *img, unsigned int img_len)
tbs.len = end - tbs.p;
/*
- * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ * Version ::= [0] EXPLICIT INTEGER { v1(0), v2(1), v3(2) }
+ * -- only v3 accepted
*/
- ret = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONTEXT_SPECIFIC |
- MBEDTLS_ASN1_CONSTRUCTED | 0);
- if (ret != 0) {
+ if (((end - p) <= (ptrdiff_t)sizeof(v3)) ||
+ (memcmp(p, v3, sizeof(v3)) != 0)) {
return IMG_PARSER_ERR_FORMAT;
}
- p += len;
+ p += sizeof(v3);
/*
* CertificateSerialNumber ::= INTEGER
@@ -209,9 +266,6 @@ static int cert_parse(void *img, unsigned int img_len)
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
- if ((end - p) < 1) {
- return IMG_PARSER_ERR_FORMAT;
- }
sig_alg1.len = (p + len) - sig_alg1.p;
p += len;
@@ -257,93 +311,85 @@ static int cert_parse(void *img, unsigned int img_len)
if (ret != 0) {
return IMG_PARSER_ERR_FORMAT;
}
- pk.len = (p + len) - pk.p;
- p += len;
+ pk_end = p + len;
+ pk.len = pk_end - pk.p;
- /*
- * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
- */
- ret = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONTEXT_SPECIFIC |
- MBEDTLS_ASN1_CONSTRUCTED | 1);
+ /* algorithm */
+ ret = mbedtls_asn1_get_tag(&p, pk_end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE);
if (ret != 0) {
- if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
- return IMG_PARSER_ERR_FORMAT;
- }
- } else {
- p += len;
+ return IMG_PARSER_ERR_FORMAT;
+ }
+ p += len;
+
+ /* Key is a BIT STRING and must use all bytes in SubjectPublicKeyInfo */
+ ret = mbedtls_asn1_get_bitstring_null(&p, pk_end, &len);
+ if ((ret != 0) || (p + len != pk_end)) {
+ return IMG_PARSER_ERR_FORMAT;
}
+ p = pk_end;
/*
+ * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- technically these contain BIT STRINGs but that is not worth
+ * -- validating
*/
- ret = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONTEXT_SPECIFIC |
- MBEDTLS_ASN1_CONSTRUCTED | 2);
- if (ret != 0) {
+ for (int i = 1; i < 3; i++) {
+ ret = mbedtls_asn1_get_tag(&p, end, &len,
+ MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+ MBEDTLS_ASN1_CONSTRUCTED | i);
+ /*
+ * Unique IDs are obsolete, so MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
+ * is the common case.
+ */
if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
- return IMG_PARSER_ERR_FORMAT;
+ if (ret != 0) {
+ return IMG_PARSER_ERR_FORMAT;
+ }
+ p += len;
}
- } else {
- p += len;
}
/*
* extensions [3] EXPLICIT Extensions OPTIONAL
+ * }
+ *
+ * X.509 and RFC5280 allow omitting the extensions entirely.
+ * However, in TF-A, a certificate with no extensions would
+ * always fail later on, as the extensions contain the
+ * information needed to authenticate the next stage in the
+ * boot chain. Furthermore, get_ext() assumes that the
+ * extensions have been parsed into v3_ext, and allowing
+ * there to be no extensions would pointlessly complicate
+ * the code. Therefore, just reject certificates without
+ * extensions. This is also why version 1 and 2 certificates
+ * are rejected above.
*/
ret = mbedtls_asn1_get_tag(&p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 3);
- if (ret != 0) {
+ if ((ret != 0) || (len != (size_t)(end - p))) {
return IMG_PARSER_ERR_FORMAT;
}
/*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ * -- must use all remaining bytes in TBSCertificate
*/
- v3_ext.p = p;
ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE);
- if (ret != 0) {
+ if ((ret != 0) || (len != (size_t)(end - p))) {
return IMG_PARSER_ERR_FORMAT;
}
- v3_ext.len = (p + len) - v3_ext.p;
-
- /*
- * Check extensions integrity
- */
- while (p < end) {
- ret = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
- if (ret != 0) {
- return IMG_PARSER_ERR_FORMAT;
- }
-
- /* Get extension ID */
- ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID);
- if (ret != 0) {
- return IMG_PARSER_ERR_FORMAT;
- }
- p += len;
-
- /* Get optional critical */
- ret = mbedtls_asn1_get_bool(&p, end, &is_critical);
- if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
- return IMG_PARSER_ERR_FORMAT;
- }
-
- /* Data should be octet string type */
- ret = mbedtls_asn1_get_tag(&p, end, &len,
- MBEDTLS_ASN1_OCTET_STRING);
- if (ret != 0) {
- return IMG_PARSER_ERR_FORMAT;
- }
- p += len;
- }
+ v3_ext.p = p;
+ v3_ext.len = len;
+ p += len;
- if (p != end) {
- return IMG_PARSER_ERR_FORMAT;
+ /* Check extensions integrity */
+ ret = get_ext(NULL, NULL, NULL);
+ if (ret != IMG_PARSER_OK) {
+ return ret;
}
end = crt_end;
@@ -353,43 +399,27 @@ static int cert_parse(void *img, unsigned int img_len)
* -- end of TBSCertificate
*
* signatureAlgorithm AlgorithmIdentifier
+ * -- Does not need to be parsed. Ensuring it is bitwise
+ * -- identical (including the tag!) with the first signature
+ * -- algorithm is sufficient.
*/
- sig_alg2.p = p;
- ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_ASN1_SEQUENCE);
- if (ret != 0) {
- return IMG_PARSER_ERR_FORMAT;
- }
- if ((end - p) < 1) {
- return IMG_PARSER_ERR_FORMAT;
- }
- sig_alg2.len = (p + len) - sig_alg2.p;
- p += len;
-
- /* Compare both signature algorithms */
- if (sig_alg1.len != sig_alg2.len) {
- return IMG_PARSER_ERR_FORMAT;
- }
- if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
+ if ((sig_alg1.len >= (size_t)(end - p)) ||
+ (0 != memcmp(sig_alg1.p, p, sig_alg1.len))) {
return IMG_PARSER_ERR_FORMAT;
}
+ p += sig_alg1.len;
memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
/*
* signatureValue BIT STRING
+ * } -- must consume all bytes
*/
signature.p = p;
- ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING);
- if (ret != 0) {
- return IMG_PARSER_ERR_FORMAT;
- }
- signature.len = (p + len) - signature.p;
- p += len;
-
- /* Check certificate length */
- if (p != end) {
+ ret = mbedtls_asn1_get_bitstring_null(&p, end, &len);
+ if ((ret != 0) || ((p + len) != end)) {
return IMG_PARSER_ERR_FORMAT;
}
+ signature.len = end - signature.p;
return IMG_PARSER_OK;
}
@@ -447,7 +477,7 @@ static int get_auth_param(const auth_param_type_desc_t *type_desc,
rc = get_ext(type_desc->cookie, param, param_len);
break;
case AUTH_PARAM_PUB_KEY:
- if (type_desc->cookie != 0) {
+ if (type_desc->cookie != NULL) {
/* Get public key from extension */
rc = get_ext(type_desc->cookie, param, param_len);
} else {
@@ -474,5 +504,5 @@ static int get_auth_param(const auth_param_type_desc_t *type_desc,
return rc;
}
-REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
+REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init,
check_integrity, get_auth_param);
diff --git a/drivers/auth/tbbr/tbbr_cot_bl1.c b/drivers/auth/tbbr/tbbr_cot_bl1.c
index e4c92213ae..21942b494f 100644
--- a/drivers/auth/tbbr/tbbr_cot_bl1.c
+++ b/drivers/auth/tbbr/tbbr_cot_bl1.c
@@ -1,22 +1,24 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
-#include <platform_def.h>
-#include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <mbedtls/version.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/tbbr_cot_common.h>
+
#if USE_TBBR_DEFS
#include <tools_share/tbbr_oid.h>
#else
#include <platform_oid.h>
#endif
+#include <platform_def.h>
+
static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC(
AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID);
static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC(
diff --git a/drivers/auth/tbbr/tbbr_cot_bl1_r64.c b/drivers/auth/tbbr/tbbr_cot_bl1_r64.c
new file mode 100644
index 0000000000..236823a4b3
--- /dev/null
+++ b/drivers/auth/tbbr/tbbr_cot_bl1_r64.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <mbedtls/version.h>
+
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/tbbr_cot_common.h>
+
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+#include <platform_def.h>
+
+static unsigned char trusted_world_pk_buf[PK_DER_LEN];
+static unsigned char non_trusted_world_pk_buf[PK_DER_LEN];
+static unsigned char content_pk_buf[PK_DER_LEN];
+static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
+
+static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t trusted_world_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, TRUSTED_WORLD_PK_OID);
+static auth_param_type_desc_t non_trusted_world_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, NON_TRUSTED_WORLD_PK_OID);
+static auth_param_type_desc_t nt_fw_content_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, NON_TRUSTED_FW_CONTENT_CERT_PK_OID);
+static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
+static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
+/*
+ * Trusted key certificate
+ */
+static const auth_img_desc_t trusted_key_cert = {
+ .img_id = TRUSTED_KEY_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &subject_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &trusted_nv_ctr,
+ .plat_nv_ctr = &trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &trusted_world_pk,
+ .data = {
+ .ptr = (void *)trusted_world_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &non_trusted_world_pk,
+ .data = {
+ .ptr = (void *)non_trusted_world_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+/*
+ * Non-Trusted Firmware
+ */
+static const auth_img_desc_t non_trusted_fw_key_cert = {
+ .img_id = NON_TRUSTED_FW_KEY_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &trusted_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &non_trusted_world_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &non_trusted_nv_ctr,
+ .plat_nv_ctr = &non_trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &nt_fw_content_pk,
+ .data = {
+ .ptr = (void *)content_pk_buf,
+ .len = (unsigned int)PK_DER_LEN
+ }
+ }
+ }
+};
+static const auth_img_desc_t non_trusted_fw_content_cert = {
+ .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = &non_trusted_fw_key_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &nt_fw_content_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &non_trusted_nv_ctr,
+ .plat_nv_ctr = &non_trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &nt_world_bl_hash,
+ .data = {
+ .ptr = (void *)nt_world_bl_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &nt_fw_config_hash,
+ .data = {
+ .ptr = (void *)nt_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+static const auth_img_desc_t bl33_image = {
+ .img_id = BL33_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &non_trusted_fw_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &nt_world_bl_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [TRUSTED_KEY_CERT_ID] = &trusted_key_cert,
+ [NON_TRUSTED_FW_KEY_CERT_ID] = &non_trusted_fw_key_cert,
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = &non_trusted_fw_content_cert,
+ [BL33_IMAGE_ID] = &bl33_image,
+};
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/tbbr/tbbr_cot_bl2.c b/drivers/auth/tbbr/tbbr_cot_bl2.c
index 65a0478abf..ce2aa7e249 100644
--- a/drivers/auth/tbbr/tbbr_cot_bl2.c
+++ b/drivers/auth/tbbr/tbbr_cot_bl2.c
@@ -1,22 +1,24 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
-#include <platform_def.h>
-#include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <mbedtls/version.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/tbbr_cot_common.h>
+
#if USE_TBBR_DEFS
#include <tools_share/tbbr_oid.h>
#else
#include <platform_oid.h>
#endif
+#include <platform_def.h>
+
static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
static unsigned char tos_fw_extra1_hash_buf[HASH_DER_LEN];
diff --git a/drivers/auth/tbbr/tbbr_cot_common.c b/drivers/auth/tbbr/tbbr_cot_common.c
index ff3f22de15..8c3724880a 100644
--- a/drivers/auth/tbbr/tbbr_cot_common.c
+++ b/drivers/auth/tbbr/tbbr_cot_common.c
@@ -1,22 +1,23 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
-#include <platform_def.h>
-#include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <mbedtls/version.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/tbbr_cot_common.h>
+
#if USE_TBBR_DEFS
#include <tools_share/tbbr_oid.h>
#else
#include <platform_oid.h>
#endif
+#include <platform_def.h>
/*
* The platform must allocate buffers to store the authentication parameters
* extracted from the certificates. In this case, because of the way the CoT is
diff --git a/drivers/brcm/emmc/emmc_chal_sd.c b/drivers/brcm/emmc/emmc_chal_sd.c
index 34d761c730..5379ec1a71 100644
--- a/drivers/brcm/emmc/emmc_chal_sd.c
+++ b/drivers/brcm/emmc/emmc_chal_sd.c
@@ -119,7 +119,7 @@ static int32_t chal_sd_set_power(struct sd_dev *handle,
mmio_setbits_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CTRL_OFFSET,
SD4_EMMC_TOP_CTRL_SDPWR_MASK);
- /* dummy write & ack to verify if the sdio is ready to send commads */
+ /* dummy write & ack to verify if the sdio is ready to send commands */
mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_ARG_OFFSET, 0);
mmio_write_32(handle->ctrl.sdRegBaseAddr + SD4_EMMC_TOP_CMD_OFFSET, 0);
@@ -600,7 +600,7 @@ uint32_t chal_sd_freq_2_div_ctrl_setting(uint32_t desired_freq)
if (actual_freq > desired_freq) {
/*
- * Division does not result in exact freqency match.
+ * Division does not result in exact frequency match.
* Make sure resulting frequency does not exceed requested freq.
*/
div_ctrl_setting++;
diff --git a/drivers/brcm/emmc/emmc_csl_sdcard.c b/drivers/brcm/emmc/emmc_csl_sdcard.c
index d6ad4bc9cc..789ed9c823 100644
--- a/drivers/brcm/emmc/emmc_csl_sdcard.c
+++ b/drivers/brcm/emmc/emmc_csl_sdcard.c
@@ -4,9 +4,11 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <stddef.h>
#include <arch_helpers.h>
#include <lib/mmio.h>
@@ -242,7 +244,7 @@ static int abort_err(struct sd_handle *handle)
* The function handles real data transmission on both DMA and
* none DMA mode, In None DMA mode the data transfer starts
* when the command is sent to the card, data has to be written
- * into the host contollers buffer at this time one block
+ * into the host controllers buffer at this time one block
* at a time.
* In DMA mode, the real data transfer is done by the DMA engine
* and this functions just waits for the data transfer to complete.
@@ -316,7 +318,7 @@ int select_blk_sz(struct sd_handle *handle, uint16_t size)
/*
- * The function initalizes the SD/SDIO/MMC/CEATA and detects
+ * The function initializes the SD/SDIO/MMC/CEATA and detects
* the card according to the flag of detection.
* Once this function is called, the card is put into ready state
* so application can do data transfer to and from the card.
@@ -391,7 +393,7 @@ int init_card(struct sd_handle *handle, int detection)
/*
- * The function handles MMC/CEATA card initalization.
+ * The function handles MMC/CEATA card initialization.
*/
int init_mmc_card(struct sd_handle *handle)
{
@@ -477,10 +479,11 @@ int init_mmc_card(struct sd_handle *handle)
handle->device->cfg.blockSize = 512;
}
- if (handle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ if (handle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
EMMC_TRACE("Sector addressing\n");
- else
+ } else {
EMMC_TRACE("Byte addressing\n");
+ }
EMMC_TRACE("Ext_CSD_storage[162]: 0x%02X Ext_CSD_storage[179]: 0x%02X\n",
emmc_global_buf_ptr->u.Ext_CSD_storage[162],
@@ -521,7 +524,7 @@ static int xfer_data(struct sd_handle *handle,
{
int rc = SD_OK;
- VERBOSE("XFER: dest: 0x%llx, addr: 0x%x, size: 0x%x bytes\n",
+ VERBOSE("XFER: dest: 0x%" PRIx64 ", addr: 0x%x, size: 0x%x bytes\n",
(uint64_t)base, addr, length);
if ((length / handle->device->cfg.blockSize) > 1) {
diff --git a/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c b/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
index 68f93e75ef..fcd499f16b 100644
--- a/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
+++ b/drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
@@ -278,8 +278,9 @@ struct sd_handle *sdio_init(void)
SDIO_base = EMMC_CTRL_REGS_BASE_ADDR;
- if (SDIO_base == SDIO0_EMMCSDXC_SYSADDR)
+ if (SDIO_base == SDIO0_EMMCSDXC_SYSADDR) {
EMMC_TRACE(" ---> for SDIO 0 Controller\n\n");
+ }
memset(p_sdhandle, 0, sizeof(struct sd_handle));
@@ -290,8 +291,9 @@ struct sd_handle *sdio_init(void)
memset(p_sdhandle->card, 0, sizeof(struct sd_card_info));
if (chal_sd_start((CHAL_HANDLE *) p_sdhandle->device,
- SD_PIO_MODE, SDIO_base, SDIO_base) != SD_OK)
+ SD_PIO_MODE, SDIO_base, SDIO_base) != SD_OK) {
return NULL;
+ }
set_config(p_sdhandle, SD_NORMAL_SPEED, MAX_CMD_RETRY, SD_DMA_OFF,
SD_DMA_BOUNDARY_4K, EMMC_BLOCK_SIZE, EMMC_WFE_RETRY);
@@ -330,14 +332,16 @@ uint32_t sdio_read(struct sd_handle *p_sdhandle,
VERBOSE("EMMC READ: dst=0x%lx, src=0x%lx, size=0x%lx\n",
storage_addr, mem_addr, bytes_to_read);
- if (storage_size < bytes_to_read)
+ if (storage_size < bytes_to_read) {
/* Don't have sufficient storage to complete the operation */
return 0;
+ }
/* Range check non high capacity memory */
if ((p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) == 0) {
- if (mem_addr > 0x80000000)
+ if (mem_addr > 0x80000000) {
return 0;
+ }
}
/* High capacity card use block address mode */
@@ -384,10 +388,11 @@ uint32_t sdio_read(struct sd_handle *p_sdhandle,
/* Update Physical address */
outputBuf += manual_copy_size;
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
blockAddr++;
- else
+ } else {
blockAddr += blockSize;
+ }
} else {
return 0;
}
@@ -395,10 +400,11 @@ uint32_t sdio_read(struct sd_handle *p_sdhandle,
while (remSize >= blockSize) {
- if (remSize >= SD_MAX_BLK_TRANSFER_LENGTH)
+ if (remSize >= SD_MAX_BLK_TRANSFER_LENGTH) {
readLen = SD_MAX_BLK_TRANSFER_LENGTH;
- else
+ } else {
readLen = (remSize / blockSize) * blockSize;
+ }
/* Check for overflow */
if ((rdCount + readLen) > storage_size ||
@@ -409,10 +415,11 @@ uint32_t sdio_read(struct sd_handle *p_sdhandle,
}
if (!read_block(p_sdhandle, outputBuf, blockAddr, readLen)) {
- if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY)
+ if (p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) {
blockAddr += (readLen / blockSize);
- else
+ } else {
blockAddr += readLen;
+ }
remSize -= readLen;
rdCount += readLen;
@@ -463,8 +470,9 @@ static uint32_t sdio_write(struct sd_handle *p_sdhandle, uintptr_t mem_addr,
/* range check non high capacity memory */
if ((p_sdhandle->device->ctrl.ocr & SD_CARD_HIGH_CAPACITY) == 0) {
- if (mem_addr > 0x80000000)
+ if (mem_addr > 0x80000000) {
return 0;
+ }
}
/* the high capacity card use block address mode */
@@ -491,11 +499,12 @@ static uint32_t sdio_write(struct sd_handle *p_sdhandle, uintptr_t mem_addr,
blockAddr, p_sdhandle->device->cfg.blockSize)) {
if (remSize <
- (p_sdhandle->device->cfg.blockSize - offset))
+ (p_sdhandle->device->cfg.blockSize - offset)) {
manual_copy_size = remSize;
- else
+ } else {
manual_copy_size =
p_sdhandle->device->cfg.blockSize - offset;
+ }
memcpy((void *)((uintptr_t)
(emmc_global_buf_ptr->u.tempbuf + offset)),
@@ -530,11 +539,12 @@ static uint32_t sdio_write(struct sd_handle *p_sdhandle, uintptr_t mem_addr,
inputBuf += manual_copy_size;
if (p_sdhandle->device->ctrl.ocr &
- SD_CARD_HIGH_CAPACITY)
+ SD_CARD_HIGH_CAPACITY) {
blockAddr++;
- else
+ } else {
blockAddr +=
p_sdhandle->device->cfg.blockSize;
+ }
} else
return 0;
} else {
diff --git a/drivers/brcm/i2c/i2c.c b/drivers/brcm/i2c/i2c.c
index 2096a82595..b45c0e7719 100644
--- a/drivers/brcm/i2c/i2c.c
+++ b/drivers/brcm/i2c/i2c.c
@@ -612,7 +612,7 @@ int i2c_probe(uint32_t bus_id, uint8_t devaddr)
*
* Description:
* This function reads I2C data from a device without specifying
- * a command regsiter.
+ * a command register.
*
* Parameters:
* bus_id - I2C bus ID
@@ -647,7 +647,7 @@ int i2c_recv_byte(uint32_t bus_id, uint8_t devaddr, uint8_t *value)
*
* Description:
* This function send I2C data to a device without specifying
- * a command regsiter.
+ * a command register.
*
* Parameters:
* bus_id - I2C bus ID
diff --git a/drivers/brcm/sotp.c b/drivers/brcm/sotp.c
index 63c4820661..20c6441296 100644
--- a/drivers/brcm/sotp.c
+++ b/drivers/brcm/sotp.c
@@ -168,7 +168,7 @@ void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata)
BIT(SOTP_STATUS__FDONE))
;
- /* Enable OTP acces by CPU */
+ /* Enable OTP access by CPU */
mmio_setbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
@@ -244,7 +244,7 @@ void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata)
/* Command done is cleared w1c */
mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
- /* disable OTP acces by CPU */
+ /* disable OTP access by CPU */
mmio_clrbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
diff --git a/drivers/cadence/combo_phy/cdns_combo_phy.c b/drivers/cadence/combo_phy/cdns_combo_phy.c
new file mode 100644
index 0000000000..f00d0c1006
--- /dev/null
+++ b/drivers/cadence/combo_phy/cdns_combo_phy.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2022-2023, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/cadence/cdns_combo_phy.h>
+#include <drivers/cadence/cdns_sdmmc.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+int cdns_sdmmc_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value,
+ uint32_t phy_reg_data, uint32_t phy_reg_data_value)
+{
+ uint32_t data = 0U;
+ uint32_t value = 0U;
+
+ /* Get PHY register address, write HRS04*/
+ value = mmio_read_32(phy_reg_addr);
+ value &= ~PHY_REG_ADDR_MASK;
+ value |= phy_reg_addr_value;
+ mmio_write_32(phy_reg_addr, value);
+ data = mmio_read_32(phy_reg_addr);
+ if ((data & PHY_REG_ADDR_MASK) != phy_reg_addr_value) {
+ ERROR("PHY_REG_ADDR is not set properly\n");
+ return -ENXIO;
+ }
+
+ /* Get PHY register data, write HRS05 */
+ value &= ~PHY_REG_DATA_MASK;
+ value |= phy_reg_data_value;
+ mmio_write_32(phy_reg_data, value);
+ data = mmio_read_32(phy_reg_data);
+ if (data != phy_reg_data_value) {
+ ERROR("PHY_REG_DATA is not set properly\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+int cdns_sd_card_detect(void)
+{
+ uint32_t value = 0;
+
+ /* Card detection */
+ do {
+ value = mmio_read_32(SDMMC_CDN(SRS09));
+ /* Wait for card insertion. SRS09.CI = 1 */
+ } while ((value & (1 << SDMMC_CDN_CI)) == 0);
+
+ if ((value & (1 << SDMMC_CDN_CI)) == 0) {
+ ERROR("Card does not detect\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+int cdns_emmc_card_reset(void)
+{
+ uint32_t _status = 0;
+
+ /* Reset embedded card */
+ mmio_write_32(SDMMC_CDN(SRS10), (7 << SDMMC_CDN_BVS) | (1 << SDMMC_CDN_BP) | _status);
+ mdelay(68680); /* ~68680us */
+ mmio_write_32(SDMMC_CDN(SRS10), (7 << SDMMC_CDN_BVS) | (0 << SDMMC_CDN_BP));
+ udelay(340); /* ~340us */
+
+ /* Turn on supply voltage */
+ /* BVS = 7, BP = 1, BP2 only in UHS2 mode */
+ mmio_write_32(SDMMC_CDN(SRS10), (7 << SDMMC_CDN_BVS) | (1 << SDMMC_CDN_BP) | _status);
+
+ return 0;
+}
diff --git a/drivers/cadence/emmc/cdns_sdmmc.c b/drivers/cadence/emmc/cdns_sdmmc.c
new file mode 100644
index 0000000000..d2cd4d6a54
--- /dev/null
+++ b/drivers/cadence/emmc/cdns_sdmmc.c
@@ -0,0 +1,824 @@
+/*
+ * Copyright (c) 2022-2023, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/cadence/cdns_sdmmc.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+/* Card busy and present */
+#define CARD_BUSY 1
+#define CARD_NOT_BUSY 0
+
+/* 500 ms delay to read the RINST register */
+#define DELAY_MS_SRS_READ 500
+#define DELAY_RES 10
+
+/* SRS12 error mask */
+#define SRS12_ERR_MASK 0xFFFF8000
+
+/* Check DV dfi_init val=0 */
+#define IO_MASK_END_DATA 0x0
+
+/* Check DV dfi_init val=2; DDR Mode */
+#define IO_MASK_END_DATA_DDR 0x2
+#define IO_MASK_START_DATA 0x0
+#define DATA_SELECT_OE_END_DATA 0x1
+
+#define TIMEOUT 100000
+
+/* General define */
+#define SDHC_REG_MASK UINT_MAX
+#define SD_HOST_BLOCK_SIZE 0x200
+#define DTCVVAL_DEFAULT_VAL 0xE
+#define CDMMC_DMA_MAX_BUFFER_SIZE 64*1024
+#define CDNSMMC_ADDRESS_MASK U(0x0f)
+#define CONFIG_CDNS_DESC_COUNT 8
+
+void cdns_init(void);
+int cdns_send_cmd(struct mmc_cmd *cmd);
+int cdns_set_ios(unsigned int clk, unsigned int width);
+int cdns_prepare(int lba, uintptr_t buf, size_t size);
+int cdns_read(int lba, uintptr_t buf, size_t size);
+int cdns_write(int lba, uintptr_t buf, size_t size);
+
+const struct mmc_ops cdns_sdmmc_ops = {
+ .init = cdns_init,
+ .send_cmd = cdns_send_cmd,
+ .set_ios = cdns_set_ios,
+ .prepare = cdns_prepare,
+ .read = cdns_read,
+ .write = cdns_write,
+};
+
+struct cdns_sdmmc_params cdns_params;
+struct cdns_sdmmc_combo_phy sdmmc_combo_phy_reg;
+struct cdns_sdmmc_sdhc sdmmc_sdhc_reg;
+#ifdef CONFIG_DMA_ADDR_T_64BIT
+struct cdns_idmac_desc cdns_desc[CONFIG_CDNS_DESC_COUNT];
+#else
+struct cdns_idmac_desc cdns_desc[CONFIG_CDNS_DESC_COUNT] __aligned(32);
+#endif
+
+bool data_cmd;
+
+int cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res)
+{
+ /* Clock for sdmclk and sdclk */
+ uint32_t count = 0;
+ uint32_t data = 0;
+
+ /* Wait status command response ready */
+ do {
+ data = mmio_read_32(cdn_srs_res);
+ count++;
+ if (count >= timeout) {
+ return -ETIMEDOUT;
+ }
+ } while ((data & (1 << SDMMC_CDN_ICS)) == 0);
+
+ return 0;
+}
+
+int cdns_busy(void)
+{
+ unsigned int data;
+
+ data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS09);
+ return (data & STATUS_DATA_BUSY) ? CARD_BUSY : CARD_NOT_BUSY;
+}
+
+int cdns_vol_reset(void)
+{
+ /* Reset embedded card */
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), (7 << SDMMC_CDN_BVS) | (1 << SDMMC_CDN_BP));
+ udelay(250);
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), (7 << SDMMC_CDN_BVS) | (0 << SDMMC_CDN_BP));
+ udelay(500);
+
+ /* Turn on supply voltage */
+ /* BVS = 7, BP = 1, BP2 only in UHS2 mode */
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), (7 << SDMMC_CDN_BVS) | (1 << SDMMC_CDN_BP));
+ udelay(250);
+ return 0;
+}
+
+void cdns_set_sdmmc_var(struct cdns_sdmmc_combo_phy *combo_phy_reg,
+ struct cdns_sdmmc_sdhc *sdhc_reg)
+{
+ /* Values are taken by the reference of cadence IP documents */
+ combo_phy_reg->cp_clk_wr_delay = 0;
+ combo_phy_reg->cp_clk_wrdqs_delay = 0;
+ combo_phy_reg->cp_data_select_oe_end = 0;
+ combo_phy_reg->cp_dll_bypass_mode = 1;
+ combo_phy_reg->cp_dll_locked_mode = 0;
+ combo_phy_reg->cp_dll_start_point = 0;
+ combo_phy_reg->cp_gate_cfg_always_on = 1;
+ combo_phy_reg->cp_io_mask_always_on = 0;
+ combo_phy_reg->cp_io_mask_end = 0;
+ combo_phy_reg->cp_io_mask_start = 0;
+ combo_phy_reg->cp_rd_del_sel = 52;
+ combo_phy_reg->cp_read_dqs_cmd_delay = 0;
+ combo_phy_reg->cp_read_dqs_delay = 0;
+ combo_phy_reg->cp_sw_half_cycle_shift = 0;
+ combo_phy_reg->cp_sync_method = 1;
+ combo_phy_reg->cp_underrun_suppress = 1;
+ combo_phy_reg->cp_use_ext_lpbk_dqs = 1;
+ combo_phy_reg->cp_use_lpbk_dqs = 1;
+ combo_phy_reg->cp_use_phony_dqs = 1;
+ combo_phy_reg->cp_use_phony_dqs_cmd = 1;
+
+ sdhc_reg->sdhc_extended_rd_mode = 1;
+ sdhc_reg->sdhc_extended_wr_mode = 1;
+ sdhc_reg->sdhc_hcsdclkadj = 0;
+ sdhc_reg->sdhc_idelay_val = 0;
+ sdhc_reg->sdhc_rdcmd_en = 1;
+ sdhc_reg->sdhc_rddata_en = 1;
+ sdhc_reg->sdhc_rw_compensate = 9;
+ sdhc_reg->sdhc_sdcfsh = 0;
+ sdhc_reg->sdhc_sdcfsl = 1;
+ sdhc_reg->sdhc_wrcmd0_dly = 1;
+ sdhc_reg->sdhc_wrcmd0_sdclk_dly = 0;
+ sdhc_reg->sdhc_wrcmd1_dly = 0;
+ sdhc_reg->sdhc_wrcmd1_sdclk_dly = 0;
+ sdhc_reg->sdhc_wrdata0_dly = 1;
+ sdhc_reg->sdhc_wrdata0_sdclk_dly = 0;
+ sdhc_reg->sdhc_wrdata1_dly = 0;
+ sdhc_reg->sdhc_wrdata1_sdclk_dly = 0;
+}
+
+static int cdns_program_phy_reg(struct cdns_sdmmc_combo_phy *combo_phy_reg,
+ struct cdns_sdmmc_sdhc *sdhc_reg)
+{
+ uint32_t value = 0;
+ int ret = 0;
+
+ /* program PHY_DQS_TIMING_REG */
+ value = (CP_USE_EXT_LPBK_DQS(combo_phy_reg->cp_use_ext_lpbk_dqs)) |
+ (CP_USE_LPBK_DQS(combo_phy_reg->cp_use_lpbk_dqs)) |
+ (CP_USE_PHONY_DQS(combo_phy_reg->cp_use_phony_dqs)) |
+ (CP_USE_PHONY_DQS_CMD(combo_phy_reg->cp_use_phony_dqs_cmd));
+ ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04,
+ COMBO_PHY_REG + PHY_DQS_TIMING_REG, MMC_REG_BASE +
+ SDHC_CDNS_HRS05, value);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* program PHY_GATE_LPBK_CTRL_REG */
+ value = (CP_SYNC_METHOD(combo_phy_reg->cp_sync_method)) |
+ (CP_SW_HALF_CYCLE_SHIFT(combo_phy_reg->cp_sw_half_cycle_shift)) |
+ (CP_RD_DEL_SEL(combo_phy_reg->cp_rd_del_sel)) |
+ (CP_UNDERRUN_SUPPRESS(combo_phy_reg->cp_underrun_suppress)) |
+ (CP_GATE_CFG_ALWAYS_ON(combo_phy_reg->cp_gate_cfg_always_on));
+ ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04,
+ COMBO_PHY_REG + PHY_GATE_LPBK_CTRL_REG, MMC_REG_BASE +
+ SDHC_CDNS_HRS05, value);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* program PHY_DLL_MASTER_CTRL_REG */
+ value = (CP_DLL_BYPASS_MODE(combo_phy_reg->cp_dll_bypass_mode))
+ | (CP_DLL_START_POINT(combo_phy_reg->cp_dll_start_point));
+ ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04,
+ COMBO_PHY_REG + PHY_DLL_MASTER_CTRL_REG, MMC_REG_BASE
+ + SDHC_CDNS_HRS05, value);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* program PHY_DLL_SLAVE_CTRL_REG */
+ value = (CP_READ_DQS_CMD_DELAY(combo_phy_reg->cp_read_dqs_cmd_delay))
+ | (CP_CLK_WRDQS_DELAY(combo_phy_reg->cp_clk_wrdqs_delay))
+ | (CP_CLK_WR_DELAY(combo_phy_reg->cp_clk_wr_delay))
+ | (CP_READ_DQS_DELAY(combo_phy_reg->cp_read_dqs_delay));
+ ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04,
+ COMBO_PHY_REG + PHY_DLL_SLAVE_CTRL_REG, MMC_REG_BASE
+ + SDHC_CDNS_HRS05, value);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* program PHY_CTRL_REG */
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS04, COMBO_PHY_REG
+ + PHY_CTRL_REG);
+ value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS05);
+
+ /* phony_dqs_timing=0 */
+ value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS05, value);
+
+ /* switch off DLL_RESET */
+ do {
+ value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09);
+ value |= SDHC_PHY_SW_RESET;
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, value);
+ value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09);
+ /* polling PHY_INIT_COMPLETE */
+ } while ((value & SDHC_PHY_INIT_COMPLETE) != SDHC_PHY_INIT_COMPLETE);
+
+ /* program PHY_DQ_TIMING_REG */
+ combo_phy_reg->cp_io_mask_end = 0U;
+ value = (CP_IO_MASK_ALWAYS_ON(combo_phy_reg->cp_io_mask_always_on))
+ | (CP_IO_MASK_END(combo_phy_reg->cp_io_mask_end))
+ | (CP_IO_MASK_START(combo_phy_reg->cp_io_mask_start))
+ | (CP_DATA_SELECT_OE_END(combo_phy_reg->cp_data_select_oe_end));
+
+ ret = cdns_sdmmc_write_phy_reg(MMC_REG_BASE + SDHC_CDNS_HRS04,
+ COMBO_PHY_REG + PHY_DQ_TIMING_REG, MMC_REG_BASE
+ + SDHC_CDNS_HRS05, value);
+ if (ret != 0) {
+ return ret;
+ }
+ return 0;
+}
+
+int cdns_read(int lba, uintptr_t buf, size_t size)
+{
+ inv_dcache_range(buf, size);
+
+ return 0;
+}
+
+void cdns_init(void)
+{
+ /* Dummy function pointer for cdns_init. */
+}
+
+int cdns_prepare(int dma_start_addr, uintptr_t dma_buff, size_t size)
+{
+ data_cmd = true;
+ struct cdns_idmac_desc *desc;
+ uint32_t desc_cnt, i;
+ uint64_t desc_base;
+
+ assert(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) &&
+ (cdns_params.desc_size > 0) &&
+ ((MMC_REG_BASE & MMC_BLOCK_MASK) == 0) &&
+ ((cdns_params.desc_base & MMC_BLOCK_MASK) == 0) &&
+ ((cdns_params.desc_size & MMC_BLOCK_MASK) == 0));
+
+ flush_dcache_range(dma_buff, size);
+
+ desc_cnt = (size + (CDMMC_DMA_MAX_BUFFER_SIZE) - 1) / (CDMMC_DMA_MAX_BUFFER_SIZE);
+ assert(desc_cnt * sizeof(struct cdns_idmac_desc) < cdns_params.desc_size);
+
+ if (desc_cnt > CONFIG_CDNS_DESC_COUNT) {
+ ERROR("Requested data transfer length %ld is greater than configured length %d",
+ size, (CONFIG_CDNS_DESC_COUNT * CDMMC_DMA_MAX_BUFFER_SIZE));
+ return -EINVAL;
+ }
+
+ desc = (struct cdns_idmac_desc *)cdns_params.desc_base;
+ desc_base = (uint64_t)desc;
+ i = 0;
+
+ while ((i + 1) < desc_cnt) {
+ desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
+ desc->reserved = 0;
+ desc->len = MAX_64KB_PAGE;
+ desc->addr_lo = (dma_buff & UINT_MAX) + (CDMMC_DMA_MAX_BUFFER_SIZE * i);
+#if CONFIG_DMA_ADDR_T_64BIT == 1
+ desc->addr_hi = (dma_buff >> 32) & 0xffffffff;
+#endif
+ size -= CDMMC_DMA_MAX_BUFFER_SIZE;
+ desc++;
+ i++;
+ }
+
+ desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA |
+ ADMA_DESC_ATTR_END;
+ desc->reserved = 0;
+ desc->len = size;
+#if CONFIG_DMA_ADDR_T_64BIT == 1
+ desc->addr_lo = (dma_buff & UINT_MAX) + (CDMMC_DMA_MAX_BUFFER_SIZE * i);
+ desc->addr_hi = (dma_buff >> 32) & UINT_MAX;
+#else
+ desc->addr_lo = (dma_buff & UINT_MAX);
+#endif
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS22, (uint32_t)desc_base);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS23, (uint32_t)(desc_base >> 32));
+ flush_dcache_range(cdns_params.desc_base,
+ desc_cnt * CDMMC_DMA_MAX_BUFFER_SIZE);
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS01,
+ ((512 << BLOCK_SIZE) | ((size/512) << BLK_COUNT_CT) | SDMA_BUF));
+ return 0;
+}
+
+static void cdns_host_set_clk(int clk)
+{
+ uint32_t ret = 0;
+ uint32_t sdclkfsval = 0;
+ uint32_t dtcvval = DTCVVAL_DEFAULT_VAL;
+
+ sdclkfsval = (cdns_params.clk_rate / 2000) / clk;
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, 0);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) |
+ (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE));
+
+ ret = cdns_wait_ics(5000, MMC_REG_BASE + SDHC_CDNS_SRS11);
+ if (ret != 0U) {
+ ERROR("Waiting SDMMC_CDN_ICS timeout");
+ }
+
+ /* Enable DLL reset */
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) &
+ ~SDHC_DLL_RESET_MASK);
+ /* Set extended_wr_mode */
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, (mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09)
+ & SDHC_EXTENDED_WR_MODE_MASK) | (1 << EXTENDED_WR_MODE));
+ /* Release DLL reset */
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE
+ + SDHC_CDNS_HRS09) | 1);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE
+ + SDHC_CDNS_HRS09) | (3 << RDCMD_EN));
+
+ do {
+ mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09);
+ } while (~mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & (1 << 1));
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) |
+ (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE) | (1 << SDMMC_CDN_SDCE));
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS13, UINT_MAX);
+}
+
+int cdns_set_ios(unsigned int clk, unsigned int width)
+{
+
+ switch (width) {
+ case MMC_BUS_WIDTH_1:
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), LEDC_OFF);
+ break;
+ case MMC_BUS_WIDTH_4:
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), DTW_4BIT);
+ break;
+ case MMC_BUS_WIDTH_8:
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_SRS10), EDTW_8BIT);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ cdns_host_set_clk(clk);
+
+ return 0;
+}
+
+int cdns_sdmmc_write_sd_host_reg(uint32_t addr, uint32_t data)
+{
+ uint32_t value = 0;
+
+ value = mmio_read_32(addr);
+ value &= ~SDHC_REG_MASK;
+ value |= data;
+ mmio_write_32(addr, value);
+ value = mmio_read_32(addr);
+ if (value != data) {
+ ERROR("SD host address is not set properly\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+int cdns_write(int lba, uintptr_t buf, size_t size)
+{
+ return 0;
+}
+
+static int cdns_init_hrs_io(struct cdns_sdmmc_combo_phy *combo_phy_reg,
+ struct cdns_sdmmc_sdhc *sdhc_reg)
+{
+ uint32_t value = 0;
+ int ret = 0;
+
+ /* program HRS09, register 42 */
+ value = (SDHC_RDDATA_EN(sdhc_reg->sdhc_rddata_en))
+ | (SDHC_RDCMD_EN(sdhc_reg->sdhc_rdcmd_en))
+ | (SDHC_EXTENDED_WR_MODE(sdhc_reg->sdhc_extended_wr_mode))
+ | (SDHC_EXTENDED_RD_MODE(sdhc_reg->sdhc_extended_rd_mode));
+ ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS09, value);
+ if (ret != 0) {
+ ERROR("Program HRS09 failed");
+ return ret;
+ }
+
+ /* program HRS10, register 43 */
+ value = (SDHC_HCSDCLKADJ(sdhc_reg->sdhc_hcsdclkadj));
+ ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS10, value);
+ if (ret != 0) {
+ ERROR("Program HRS10 failed");
+ return ret;
+ }
+
+ /* program HRS16, register 48 */
+ value = (SDHC_WRDATA1_SDCLK_DLY(sdhc_reg->sdhc_wrdata1_sdclk_dly))
+ | (SDHC_WRDATA0_SDCLK_DLY(sdhc_reg->sdhc_wrdata0_sdclk_dly))
+ | (SDHC_WRCMD1_SDCLK_DLY(sdhc_reg->sdhc_wrcmd1_sdclk_dly))
+ | (SDHC_WRCMD0_SDCLK_DLY(sdhc_reg->sdhc_wrcmd0_sdclk_dly))
+ | (SDHC_WRDATA1_DLY(sdhc_reg->sdhc_wrdata1_dly))
+ | (SDHC_WRDATA0_DLY(sdhc_reg->sdhc_wrdata0_dly))
+ | (SDHC_WRCMD1_DLY(sdhc_reg->sdhc_wrcmd1_dly))
+ | (SDHC_WRCMD0_DLY(sdhc_reg->sdhc_wrcmd0_dly));
+ ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS16, value);
+ if (ret != 0) {
+ ERROR("Program HRS16 failed");
+ return ret;
+ }
+
+ /* program HRS07, register 40 */
+ value = (SDHC_RW_COMPENSATE(sdhc_reg->sdhc_rw_compensate))
+ | (SDHC_IDELAY_VAL(sdhc_reg->sdhc_idelay_val));
+ ret = cdns_sdmmc_write_sd_host_reg(MMC_REG_BASE + SDHC_CDNS_HRS07, value);
+ if (ret != 0) {
+ ERROR("Program HRS07 failed");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cdns_hc_set_clk(struct cdns_sdmmc_params *cdn_sdmmc_dev_mode_params)
+{
+ uint32_t ret = 0;
+ uint32_t dtcvval, sdclkfsval;
+
+ dtcvval = DTC_VAL;
+ sdclkfsval = 0;
+
+ if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_DS) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR12) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_SDR_BC)) {
+ sdclkfsval = 4;
+ } else if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_HS) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR25) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_DDR50) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_SDR)) {
+ sdclkfsval = 2;
+ } else if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR50) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_DDR) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_HS400) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_HS400es)) {
+ sdclkfsval = 1;
+ } else if ((cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == SD_UHS_SDR104) ||
+ (cdn_sdmmc_dev_mode_params->cdn_sdmmc_dev_mode == EMMC_HS200)) {
+ sdclkfsval = 0;
+ }
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, 0);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) |
+ (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE));
+ ret = cdns_wait_ics(5000, MMC_REG_BASE + SDHC_CDNS_SRS11);
+ if (ret != 0U) {
+ ERROR("Waiting SDMMC_CDN_ICS timeout");
+ return ret;
+ }
+
+ /* Enable DLL reset */
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_HRS09), mmio_read_32(MMC_REG_BASE
+ + SDHC_CDNS_HRS09) & ~SDHC_DLL_RESET_MASK);
+ /* Set extended_wr_mode */
+ mmio_write_32((MMC_REG_BASE + SDHC_CDNS_HRS09),
+ (mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & SDHC_EXTENDED_WR_MODE_MASK) |
+ (1 << EXTENDED_WR_MODE));
+ /* Release DLL reset */
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE
+ + SDHC_CDNS_HRS09) | 1);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, mmio_read_32(MMC_REG_BASE
+ + SDHC_CDNS_HRS09) | (3 << RDCMD_EN));
+ do {
+ mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09);
+ } while (~mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09) & (1 << 1));
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (dtcvval << SDMMC_CDN_DTCV) |
+ (sdclkfsval << SDMMC_CDN_SDCLKFS) | (1 << SDMMC_CDN_ICE) | (1 << SDMMC_CDN_SDCE));
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS13, UINT_MAX);
+ return 0;
+}
+
+int cdns_reset(void)
+{
+ uint32_t data = 0;
+ uint32_t count = 0;
+ uint32_t value = 0;
+
+ value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS11);
+ value &= ~(0xFFFF);
+ value |= 0x0;
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, value);
+ udelay(500);
+
+ /* Software reset */
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS00, 1);
+ /* Wait status command response ready */
+ do {
+ data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS00);
+ count++;
+ if (count >= 5000) {
+ return -ETIMEDOUT;
+ }
+ /* Wait for HRS00.SWR */
+ } while ((data & 1) == 1);
+
+ /* Step 1, switch on DLL_RESET */
+ value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_HRS09);
+ value &= ~SDHC_PHY_SW_RESET;
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_HRS09, value);
+
+ return 0;
+}
+
+int cdns_sd_host_init(struct cdns_sdmmc_combo_phy *mmc_combo_phy_reg,
+struct cdns_sdmmc_sdhc *mmc_sdhc_reg)
+{
+ int ret = 0;
+
+ ret = cdns_reset();
+ if (ret != 0) {
+ ERROR("Program phy reg init failed");
+ return ret;
+ }
+
+ ret = cdns_program_phy_reg(&sdmmc_combo_phy_reg, &sdmmc_sdhc_reg);
+ if (ret != 0) {
+ ERROR("Program phy reg init failed");
+ return ret;
+ }
+
+ ret = cdns_init_hrs_io(&sdmmc_combo_phy_reg, &sdmmc_sdhc_reg);
+ if (ret != 0) {
+ ERROR("Program init for HRS reg is failed");
+ return ret;
+ }
+
+ ret = cdns_sd_card_detect();
+ if (ret != 0) {
+ ERROR("SD card does not detect");
+ return ret;
+ }
+
+ ret = cdns_vol_reset();
+ if (ret != 0) {
+ ERROR("eMMC card reset failed");
+ return ret;
+ }
+
+ ret = cdns_hc_set_clk(&cdns_params);
+ if (ret != 0) {
+ ERROR("hc set clk failed");
+ return ret;
+ }
+
+ return 0;
+}
+
+void cdns_srs10_value_toggle(uint8_t write_val, uint8_t prev_val)
+{
+ uint32_t data_op = 0U;
+
+ data_op = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS10);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS10, (data_op & (prev_val << 0)));
+ mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS10);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS10, data_op | (write_val << 0));
+}
+
+void cdns_srs11_srs15_config(uint32_t srs11_val, uint32_t srs15_val)
+{
+ uint32_t data = 0U;
+
+ data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS11);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS11, (data | srs11_val));
+ data = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS15);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS15, (data | srs15_val));
+}
+
+int cdns_send_cmd(struct mmc_cmd *cmd)
+{
+ uint32_t op = 0, ret = 0;
+ uint8_t write_value = 0, prev_val = 0;
+ uint32_t value;
+ int32_t timeout;
+ uint32_t cmd_indx;
+ uint32_t status = 0, srs15_val = 0, srs11_val = 0;
+ uint32_t status_check = 0;
+
+ assert(cmd);
+ cmd_indx = (cmd->cmd_idx) << COM_IDX;
+
+ if (data_cmd) {
+ switch (cmd->cmd_idx) {
+ case SD_SWITCH:
+ op = DATA_PRESENT;
+ write_value = ADMA2_32 | DT_WIDTH;
+ prev_val = ADMA2_32 | DT_WIDTH;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ srs15_val = BIT_AD_64 | HV4E | V18SE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ break;
+
+ case SD_WRITE_SINGLE_BLOCK:
+ case SD_READ_SINGLE_BLOCK:
+ op = DATA_PRESENT;
+ write_value = ADMA2_32 | HS_EN | DT_WIDTH | LEDC;
+ prev_val = ADMA2_32 | HS_EN | DT_WIDTH;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = PVE | BIT_AD_64 | HV4E | SDR104_MODE | V18SE;
+ srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS00, SAAR);
+ break;
+
+ case SD_WRITE_MULTIPLE_BLOCK:
+ case SD_READ_MULTIPLE_BLOCK:
+ op = DATA_PRESENT | AUTO_CMD_EN | MULTI_BLK_READ;
+ write_value = ADMA2_32 | HS_EN | DT_WIDTH | LEDC;
+ prev_val = ADMA2_32 | HS_EN | DT_WIDTH;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = PVE | BIT_AD_64 | HV4E | SDR104_MODE | V18SE;
+ srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS00, SAAR);
+ break;
+
+ case SD_APP_SEND_SCR:
+ op = DATA_PRESENT;
+ write_value = ADMA2_32 | LEDC;
+ prev_val = LEDC;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = BIT_AD_64 | HV4E | V18SE;
+ srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ break;
+
+ case SD_SEND_IF_COND:
+ op = DATA_PRESENT | CMD_IDX_CHK_ENABLE;
+ write_value = LEDC;
+ prev_val = 0x0;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = HV4E;
+ srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ break;
+
+ default:
+ write_value = LEDC;
+ prev_val = 0x0;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ op = 0;
+ break;
+ }
+ } else {
+ switch (cmd->cmd_idx) {
+ case SD_GO_IDLE_STATE:
+ write_value = LEDC;
+ prev_val = 0x0;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = HV4E;
+ srs11_val = SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ break;
+
+ case SD_ALL_SEND_CID:
+ write_value = LEDC;
+ prev_val = 0x0;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = HV4E | V18SE;
+ srs11_val = SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ break;
+
+ case SD_SEND_IF_COND:
+ op = CMD_IDX_CHK_ENABLE;
+ write_value = LEDC;
+ prev_val = 0x0;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ srs15_val = HV4E;
+ srs11_val = READ_CLK | SDMMC_CDN_ICE | SDMMC_CDN_ICS | SDMMC_CDN_SDCE;
+ cdns_srs11_srs15_config(srs11_val, srs15_val);
+ break;
+
+ case SD_STOP_TRANSMISSION:
+ op = CMD_STOP_ABORT_CMD;
+ break;
+
+ case SD_SEND_STATUS:
+ break;
+
+ case 1:
+ cmd->cmd_arg = 0;
+ break;
+
+ case SD_SELECT_CARD:
+ op = MULTI_BLK_READ;
+ break;
+
+ case SD_APP_CMD:
+ default:
+ write_value = LEDC;
+ prev_val = 0x0;
+ cdns_srs10_value_toggle(write_value, prev_val);
+ op = 0;
+ break;
+ }
+ }
+
+ switch (cmd->resp_type) {
+ case MMC_RESPONSE_NONE:
+ op |= CMD_READ | MULTI_BLK_READ | DMA_ENABLED | BLK_CNT_EN;
+ break;
+
+ case MMC_RESPONSE_R2:
+ op |= CMD_READ | MULTI_BLK_READ | DMA_ENABLED | BLK_CNT_EN |
+ RES_TYPE_SEL_136 | CMD_CHECK_RESP_CRC;
+ break;
+
+ case MMC_RESPONSE_R3:
+ op |= CMD_READ | MULTI_BLK_READ | DMA_ENABLED | BLK_CNT_EN |
+ RES_TYPE_SEL_48;
+ break;
+
+ case MMC_RESPONSE_R1:
+ if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx
+ == SD_WRITE_MULTIPLE_BLOCK)) {
+ op |= DMA_ENABLED | BLK_CNT_EN | RES_TYPE_SEL_48
+ | CMD_CHECK_RESP_CRC | CMD_IDX_CHK_ENABLE;
+ } else {
+ op |= DMA_ENABLED | BLK_CNT_EN | CMD_READ | RES_TYPE_SEL_48
+ | CMD_CHECK_RESP_CRC | CMD_IDX_CHK_ENABLE;
+ }
+ break;
+
+ default:
+ op |= DMA_ENABLED | BLK_CNT_EN | CMD_READ | MULTI_BLK_READ |
+ RES_TYPE_SEL_48 | CMD_CHECK_RESP_CRC | CMD_IDX_CHK_ENABLE;
+ break;
+ }
+
+ timeout = TIMEOUT;
+ do {
+ udelay(100);
+ ret = cdns_busy();
+ if (--timeout <= 0) {
+ udelay(50);
+ panic();
+ }
+ } while (ret);
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS12, UINT_MAX);
+
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS02, cmd->cmd_arg);
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS14, 0x00000000);
+ if (cmd_indx == 1)
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS03, SDHC_CDNS_SRS03_VALUE);
+ else
+ mmio_write_32(MMC_REG_BASE + SDHC_CDNS_SRS03, op | cmd_indx);
+
+ timeout = TIMEOUT;
+ do {
+ udelay(500);
+ value = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS12);
+ } while (((value & (INT_CMD_DONE | ERROR_INT)) == 0) && (timeout-- > 0));
+
+ timeout = TIMEOUT;
+
+ if (data_cmd) {
+ data_cmd = false;
+ do {
+ udelay(250);
+ } while (((value & TRAN_COMP) == 0) && (timeout-- > 0));
+ }
+
+ status_check = value & SRS12_ERR_MASK;
+ if (status_check != 0U) {
+ ERROR("SD host controller send command failed, SRS12 = %x", status);
+ return -1;
+ }
+
+ if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) {
+ cmd->resp_data[0] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS04);
+ if (op & RES_TYPE_SEL_136) {
+ cmd->resp_data[1] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS05);
+ cmd->resp_data[2] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS06);
+ cmd->resp_data[3] = mmio_read_32(MMC_REG_BASE + SDHC_CDNS_SRS07);
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/cadence/nand/cdns_nand.c b/drivers/cadence/nand/cdns_nand.c
new file mode 100644
index 0000000000..20147d0752
--- /dev/null
+++ b/drivers/cadence/nand/cdns_nand.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2022-2023, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/cadence/cdns_nand.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <platform_def.h>
+
+/* NAND flash device information struct */
+static cnf_dev_info_t dev_info;
+
+/*
+ * Scratch buffers for read and write operations
+ * DMA transfer of Cadence NAND expects data 8 bytes aligned
+ * to be written to register
+ */
+static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE] __aligned(8);
+
+/* Wait for controller to be in idle state */
+static inline void cdns_nand_wait_idle(void)
+{
+ uint32_t reg = 0U;
+
+ do {
+ udelay(CNF_DEF_DELAY_US);
+ reg = mmio_read_32(CNF_CMDREG(CTRL_STATUS));
+ } while (CNF_GET_CTRL_BUSY(reg) != 0U);
+}
+
+/* Wait for given thread to be in ready state */
+static inline void cdns_nand_wait_thread_ready(uint8_t thread_id)
+{
+ uint32_t reg = 0U;
+
+ do {
+ udelay(CNF_DEF_DELAY_US);
+ reg = mmio_read_32(CNF_CMDREG(TRD_STATUS));
+ reg &= (1U << (uint32_t)thread_id);
+ } while (reg != 0U);
+}
+
+/* Check if the last operation/command in selected thread is completed */
+static int cdns_nand_last_opr_status(uint8_t thread_id)
+{
+ uint8_t nthreads = 0U;
+ uint32_t reg = 0U;
+
+ /* Get number of threads */
+ reg = mmio_read_32(CNF_CTRLPARAM(FEATURE));
+ nthreads = CNF_GET_NTHREADS(reg);
+
+ if (thread_id > nthreads) {
+ ERROR("%s: Invalid thread ID\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Select thread */
+ mmio_write_32(CNF_CMDREG(CMD_STAT_PTR), (uint32_t)thread_id);
+
+ uint32_t err_mask = CNF_ECMD | CNF_EECC | CNF_EDEV | CNF_EDQS | CNF_EFAIL |
+ CNF_EBUS | CNF_EDI | CNF_EPAR | CNF_ECTX | CNF_EPRO;
+
+ do {
+ udelay(CNF_DEF_DELAY_US * 2);
+ reg = mmio_read_32(CNF_CMDREG(CMD_STAT));
+ } while ((reg & CNF_CMPLT) == 0U);
+
+ /* last operation is completed, make sure no other error bits are set */
+ if ((reg & err_mask) == 1U) {
+ ERROR("%s, CMD_STATUS:0x%x\n", __func__, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* Set feature command */
+int cdns_nand_set_feature(uint8_t feat_addr, uint8_t feat_val, uint8_t thread_id)
+{
+ /* Wait for thread to be ready */
+ cdns_nand_wait_thread_ready(thread_id);
+
+ /* Set feature address */
+ mmio_write_32(CNF_CMDREG(CMD_REG1), (uint32_t)feat_addr);
+ /* Set feature volume */
+ mmio_write_32(CNF_CMDREG(CMD_REG2), (uint32_t)feat_val);
+
+ /* Set feature command */
+ uint32_t reg = (CNF_WORK_MODE_PIO << CNF_CMDREG0_CT);
+
+ reg |= (thread_id << CNF_CMDREG0_TRD);
+ reg |= (CNF_DEF_VOL_ID << CNF_CMDREG0_VOL);
+ reg |= (CNF_INT_DIS << CNF_CMDREG0_INTR);
+ reg |= (CNF_CT_SET_FEATURE << CNF_CMDREG0_CMD);
+ mmio_write_32(CNF_CMDREG(CMD_REG0), reg);
+
+ return cdns_nand_last_opr_status(thread_id);
+}
+
+/* Reset command to the selected device */
+int cdns_nand_reset(uint8_t thread_id)
+{
+ /* Operation is executed in selected thread */
+ cdns_nand_wait_thread_ready(thread_id);
+
+ /* Select memory */
+ mmio_write_32(CNF_CMDREG(CMD_REG4),
+ (CNF_DEF_DEVICE << CNF_CMDREG4_MEM));
+
+ /* Issue reset command */
+ uint32_t reg = (CNF_WORK_MODE_PIO << CNF_CMDREG0_CT);
+
+ reg |= (thread_id << CNF_CMDREG0_TRD);
+ reg |= (CNF_DEF_VOL_ID << CNF_CMDREG0_VOL);
+ reg |= (CNF_INT_DIS << CNF_CMDREG0_INTR);
+ reg |= (CNF_CT_RESET_ASYNC << CNF_CMDREG0_CMD);
+ mmio_write_32(CNF_CMDREG(CMD_REG0), reg);
+
+ return cdns_nand_last_opr_status(thread_id);
+}
+
+/* Set operation work mode */
+static void cdns_nand_set_opr_mode(uint8_t opr_mode)
+{
+ /* Wait for controller to be in idle state */
+ cdns_nand_wait_idle();
+
+ /* Reset DLL PHY */
+ uint32_t reg = mmio_read_32(CNF_MINICTRL(DLL_PHY_CTRL));
+
+ reg &= ~(1 << CNF_DLL_PHY_RST_N);
+ mmio_write_32(CNF_MINICTRL(DLL_PHY_CTRL), reg);
+
+ if (opr_mode == CNF_OPR_WORK_MODE_SDR) {
+ /* Combo PHY Control Timing Block register settings */
+ mmio_write_32(CP_CTB(CTRL_REG), CP_CTRL_REG_SDR);
+ mmio_write_32(CP_CTB(TSEL_REG), CP_TSEL_REG_SDR);
+
+ /* Combo PHY DLL register settings */
+ mmio_write_32(CP_DLL(DQ_TIMING_REG), CP_DQ_TIMING_REG_SDR);
+ mmio_write_32(CP_DLL(DQS_TIMING_REG), CP_DQS_TIMING_REG_SDR);
+ mmio_write_32(CP_DLL(GATE_LPBK_CTRL_REG), CP_GATE_LPBK_CTRL_REG_SDR);
+ mmio_write_32(CP_DLL(MASTER_CTRL_REG), CP_DLL_MASTER_CTRL_REG_SDR);
+
+ /* Async mode timing settings */
+ mmio_write_32(CNF_MINICTRL(ASYNC_TOGGLE_TIMINGS),
+ (2 << CNF_ASYNC_TIMINGS_TRH) |
+ (4 << CNF_ASYNC_TIMINGS_TRP) |
+ (2 << CNF_ASYNC_TIMINGS_TWH) |
+ (4 << CNF_ASYNC_TIMINGS_TWP));
+
+ /* Set extended read and write mode */
+ reg |= (1 << CNF_DLL_PHY_EXT_RD_MODE);
+ reg |= (1 << CNF_DLL_PHY_EXT_WR_MODE);
+
+ /* Set operation work mode in common settings */
+ mmio_clrsetbits_32(CNF_MINICTRL(CMN_SETTINGS),
+ CNF_CMN_SETTINGS_OPR_MASK,
+ CNF_OPR_WORK_MODE_SDR);
+ } else if (opr_mode == CNF_OPR_WORK_MODE_NVDDR) {
+ ; /* ToDo: add DDR mode settings also once available on SIMICS */
+ } else {
+ ;
+ }
+
+ reg |= (1 << CNF_DLL_PHY_RST_N);
+ mmio_write_32(CNF_MINICTRL(DLL_PHY_CTRL), reg);
+}
+
+/* Data transfer configuration */
+static void cdns_nand_transfer_config(void)
+{
+ /* Wait for controller to be in idle state */
+ cdns_nand_wait_idle();
+
+ /* Configure data transfer parameters */
+ mmio_write_32(CNF_CTRLCFG(TRANS_CFG0), 1);
+
+ /* ECC is disabled */
+ mmio_write_32(CNF_CTRLCFG(ECC_CFG0), 0);
+
+ /* DMA burst select */
+ mmio_write_32(CNF_CTRLCFG(DMA_SETTINGS),
+ (CNF_DMA_BURST_SIZE_MAX << CNF_DMA_SETTINGS_BURST) |
+ (1 << CNF_DMA_SETTINGS_OTE));
+
+ /* Enable pre-fetching for 1K */
+ mmio_write_32(CNF_CTRLCFG(FIFO_TLEVEL),
+ (CNF_DMA_PREFETCH_SIZE << CNF_FIFO_TLEVEL_POS) |
+ (CNF_DMA_PREFETCH_SIZE << CNF_FIFO_TLEVEL_DMA_SIZE));
+
+ /* Select access type */
+ mmio_write_32(CNF_CTRLCFG(MULTIPLANE_CFG), 0);
+ mmio_write_32(CNF_CTRLCFG(CACHE_CFG), 0);
+}
+
+/* Update the nand flash device info */
+static int cdns_nand_update_dev_info(void)
+{
+ uint32_t reg = 0U;
+
+ /* Read the device type and number of LUNs */
+ reg = mmio_read_32(CNF_CTRLPARAM(DEV_PARAMS0));
+ dev_info.type = CNF_GET_DEV_TYPE(reg);
+ if (dev_info.type == CNF_DT_UNKNOWN) {
+ ERROR("%s: device type unknown\n", __func__);
+ return -ENXIO;
+ }
+ dev_info.nluns = CNF_GET_NLUNS(reg);
+
+ /* Pages per block */
+ reg = mmio_read_32(CNF_CTRLCFG(DEV_LAYOUT));
+ dev_info.npages_per_block = CNF_GET_NPAGES_PER_BLOCK(reg);
+
+ /* Sector size and last sector size */
+ reg = mmio_read_32(CNF_CTRLCFG(TRANS_CFG1));
+ dev_info.sector_size = CNF_GET_SCTR_SIZE(reg);
+ dev_info.last_sector_size = CNF_GET_LAST_SCTR_SIZE(reg);
+
+ /* Page size and spare size */
+ reg = mmio_read_32(CNF_CTRLPARAM(DEV_AREA));
+ dev_info.page_size = CNF_GET_PAGE_SIZE(reg);
+ dev_info.spare_size = CNF_GET_SPARE_SIZE(reg);
+
+ /* Device blocks per LUN */
+ dev_info.nblocks_per_lun = mmio_read_32(CNF_CTRLPARAM(DEV_BLOCKS_PLUN));
+
+ /* Calculate block size and total device size */
+ dev_info.block_size = (dev_info.npages_per_block * dev_info.page_size);
+ dev_info.total_size = ((unsigned long long)dev_info.block_size *
+ (unsigned long long)dev_info.nblocks_per_lun *
+ dev_info.nluns);
+
+ VERBOSE("CNF params: page_size %d, spare_size %d, block_size %u, total_size %llu\n",
+ dev_info.page_size, dev_info.spare_size,
+ dev_info.block_size, dev_info.total_size);
+
+ return 0;
+}
+
+/* NAND Flash Controller/Host initialization */
+int cdns_nand_host_init(void)
+{
+ uint32_t reg = 0U;
+ int ret = 0;
+
+ do {
+ /* Read controller status register for init complete */
+ reg = mmio_read_32(CNF_CMDREG(CTRL_STATUS));
+ } while (CNF_GET_INIT_COMP(reg) == 0);
+
+ ret = cdns_nand_update_dev_info();
+ if (ret != 0) {
+ return ret;
+ }
+
+ INFO("CNF: device discovery process completed and device type %d\n",
+ dev_info.type);
+
+ /* Enable data integrity, enable CRC and parity */
+ reg = mmio_read_32(CNF_DI(CONTROL));
+ reg |= (1 << CNF_DI_PAR_EN);
+ reg |= (1 << CNF_DI_CRC_EN);
+ mmio_write_32(CNF_DI(CONTROL), reg);
+
+ /* Status polling mode, device control and status register */
+ cdns_nand_wait_idle();
+ reg = mmio_read_32(CNF_CTRLCFG(DEV_STAT));
+ reg = reg & ~1;
+ mmio_write_32(CNF_CTRLCFG(DEV_STAT), reg);
+
+ /* Set operation work mode */
+ cdns_nand_set_opr_mode(CNF_OPR_WORK_MODE_SDR);
+
+ /* Set data transfer configuration parameters */
+ cdns_nand_transfer_config();
+
+ return 0;
+}
+
+/* erase: Block erase command */
+int cdns_nand_erase(uint32_t offset, uint32_t size)
+{
+ /* Determine the starting block offset i.e row address */
+ uint32_t row_address = dev_info.npages_per_block * offset;
+
+ /* Wait for thread to be in ready state */
+ cdns_nand_wait_thread_ready(CNF_DEF_TRD);
+
+ /*Set row address */
+ mmio_write_32(CNF_CMDREG(CMD_REG1), row_address);
+
+ /* Operation bank number */
+ mmio_write_32(CNF_CMDREG(CMD_REG4), (CNF_DEF_DEVICE << CNF_CMDREG4_MEM));
+
+ /* Block erase command */
+ uint32_t reg = (CNF_WORK_MODE_PIO << CNF_CMDREG0_CT);
+
+ reg |= (CNF_DEF_TRD << CNF_CMDREG0_TRD);
+ reg |= (CNF_DEF_VOL_ID << CNF_CMDREG0_VOL);
+ reg |= (CNF_INT_DIS << CNF_CMDREG0_INTR);
+ reg |= (CNF_CT_ERASE << CNF_CMDREG0_CMD);
+ reg |= (((size-1) & 0xFF) << CNF_CMDREG0_CMD);
+ mmio_write_32(CNF_CMDREG(CMD_REG0), reg);
+
+ /* Wait for erase operation to complete */
+ return cdns_nand_last_opr_status(CNF_DEF_TRD);
+}
+
+/* io mtd functions */
+int cdns_nand_init_mtd(unsigned long long *size, unsigned int *erase_size)
+{
+ *size = dev_info.total_size;
+ *erase_size = dev_info.block_size;
+
+ return 0;
+}
+
+static uint32_t cdns_nand_get_row_address(uint32_t page, uint32_t block)
+{
+ uint32_t row_address = 0U;
+ uint32_t req_bits = 0U;
+
+ /* The device info is not populated yet. */
+ if (dev_info.npages_per_block == 0U)
+ return 0;
+
+ for (uint32_t i = 0U; i < sizeof(uint32_t) * 8; i++) {
+ if ((1U << i) & dev_info.npages_per_block)
+ req_bits = i;
+ }
+
+ row_address = ((page & GENMASK_32((req_bits - 1), 0)) |
+ (block << req_bits));
+
+ return row_address;
+}
+
+/* NAND Flash page read */
+static int cdns_nand_read_page(uint32_t block, uint32_t page, uintptr_t buffer)
+{
+
+ /* Wait for thread to be ready */
+ cdns_nand_wait_thread_ready(CNF_DEF_TRD);
+
+ /* Select device */
+ mmio_write_32(CNF_CMDREG(CMD_REG4),
+ (CNF_DEF_DEVICE << CNF_CMDREG4_MEM));
+
+ /* Set host memory address for DMA transfers */
+ mmio_write_32(CNF_CMDREG(CMD_REG2), (buffer & UINT32_MAX));
+ mmio_write_32(CNF_CMDREG(CMD_REG3), ((buffer >> 32) & UINT32_MAX));
+
+ /* Set row address */
+ mmio_write_32(CNF_CMDREG(CMD_REG1),
+ cdns_nand_get_row_address(page, block));
+
+ /* Page read command */
+ uint32_t reg = (CNF_WORK_MODE_PIO << CNF_CMDREG0_CT);
+
+ reg |= (CNF_DEF_TRD << CNF_CMDREG0_TRD);
+ reg |= (CNF_DEF_VOL_ID << CNF_CMDREG0_VOL);
+ reg |= (CNF_INT_DIS << CNF_CMDREG0_INTR);
+ reg |= (CNF_DMA_MASTER_SEL << CNF_CMDREG0_DMA);
+ reg |= (CNF_CT_PAGE_READ << CNF_CMDREG0_CMD);
+ reg |= (((CNF_READ_SINGLE_PAGE-1) & 0xFF) << CNF_CMDREG0_CMD);
+ mmio_write_32(CNF_CMDREG(CMD_REG0), reg);
+
+ /* Wait for read operation to complete */
+ if (cdns_nand_last_opr_status(CNF_DEF_TRD)) {
+ ERROR("%s: Page read failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int cdns_nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *out_length)
+{
+ uint32_t block = offset / dev_info.block_size;
+ uint32_t end_block = (offset + length - 1U) / dev_info.block_size;
+ uint32_t page_start = (offset % dev_info.block_size) / dev_info.page_size;
+ uint32_t start_offset = offset % dev_info.page_size;
+ uint32_t nb_pages = dev_info.block_size / dev_info.page_size;
+ uint32_t bytes_read = 0U;
+ uint32_t page = 0U;
+ int result = 0;
+
+ INFO("CNF: %s: block %u-%u, page_start %u, len %zu, offset %u\n",
+ __func__, block, end_block, page_start, length, offset);
+
+ if ((offset >= dev_info.total_size) ||
+ (offset + length-1 >= dev_info.total_size) ||
+ (length == 0U)) {
+ ERROR("CNF: Invalid read parameters\n");
+ return -EINVAL;
+ }
+
+ *out_length = 0UL;
+
+ while (block <= end_block) {
+ for (page = page_start; page < nb_pages; page++) {
+ if ((start_offset != 0U) || (length < dev_info.page_size)) {
+ /* Partial page read */
+ result = cdns_nand_read_page(block, page,
+ (uintptr_t)scratch_buff);
+ if (result != 0) {
+ return result;
+ }
+
+ bytes_read = MIN((size_t)(dev_info.page_size - start_offset),
+ length);
+
+ memcpy((uint8_t *)buffer, scratch_buff + start_offset,
+ bytes_read);
+ start_offset = 0U;
+ } else {
+ /* Full page read */
+ result = cdns_nand_read_page(block, page,
+ (uintptr_t)scratch_buff);
+ if (result != 0) {
+ return result;
+ }
+
+ bytes_read = dev_info.page_size;
+ memcpy((uint8_t *)buffer, scratch_buff, bytes_read);
+ }
+
+ length -= bytes_read;
+ buffer += bytes_read;
+ *out_length += bytes_read;
+
+ /* All the bytes have read */
+ if (length == 0U) {
+ break;
+ }
+
+ udelay(CNF_READ_INT_DELAY_US);
+ } /* for */
+
+ page_start = 0U;
+ block++;
+ } /* while */
+
+ return 0;
+}
diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S
index 4c1a80efc6..d2dd0a8e25 100644
--- a/drivers/cadence/uart/aarch64/cdns_console.S
+++ b/drivers/cadence/uart/aarch64/cdns_console.S
@@ -79,7 +79,7 @@ func console_cdns_register
mov x0, x6
mov x30, x7
- finish_console_register cdns putc=1, getc=1, flush=1
+ finish_console_register cdns putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
ret x7
@@ -197,7 +197,14 @@ func console_cdns_core_flush
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
- /* Placeholder */
+ /* Loop until the transmit FIFO is empty */
+check_txfifo_empty:
+ ldr w2, [x0, #R_UART_SR]
+ tbz w2, #UART_SR_INTR_TEMPTY_BIT, check_txfifo_empty
+ /* Wait until the Transmit is Inactive */
+check_tx_inactive_state:
+ ldr w2, [x0, #R_UART_SR]
+ tbnz w2, #UART_SR_INTR_TACTIVE_BIT, check_tx_inactive_state
ret
endfunc console_cdns_core_flush
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000000..4cbc0f70f4
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ * Author(s): Ludovic Barre, <ludovic.barre@st.com> for STMicroelectronics.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <drivers/clk.h>
+
+static const struct clk_ops *ops;
+
+int clk_enable(unsigned long id)
+{
+ assert((ops != NULL) && (ops->enable != NULL));
+
+ return ops->enable(id);
+}
+
+void clk_disable(unsigned long id)
+{
+ assert((ops != NULL) && (ops->disable != NULL));
+
+ ops->disable(id);
+}
+
+unsigned long clk_get_rate(unsigned long id)
+{
+ assert((ops != NULL) && (ops->get_rate != NULL));
+
+ return ops->get_rate(id);
+}
+
+int clk_get_parent(unsigned long id)
+{
+ assert((ops != NULL) && (ops->get_parent != NULL));
+
+ return ops->get_parent(id);
+}
+
+bool clk_is_enabled(unsigned long id)
+{
+ assert((ops != NULL) && (ops->is_enabled != NULL));
+
+ return ops->is_enabled(id);
+}
+
+/*
+ * Initialize the clk. The fields in the provided clk
+ * ops pointer must be valid.
+ */
+void clk_register(const struct clk_ops *ops_ptr)
+{
+ assert((ops_ptr != NULL) &&
+ (ops_ptr->enable != NULL) &&
+ (ops_ptr->disable != NULL) &&
+ (ops_ptr->get_rate != NULL) &&
+ (ops_ptr->get_parent != NULL) &&
+ (ops_ptr->is_enabled != NULL));
+
+ ops = ops_ptr;
+}
diff --git a/drivers/console/aarch32/skeleton_console.S b/drivers/console/aarch32/skeleton_console.S
index a9e13ec44c..05a5985084 100644
--- a/drivers/console/aarch32/skeleton_console.S
+++ b/drivers/console/aarch32/skeleton_console.S
@@ -63,7 +63,7 @@ func console_xxx_register
* If any of the argument is unspecified, then the corresponding
* entry in console_t is set to 0.
*/
- finish_console_register xxx putc=1, getc=1, flush=1
+ finish_console_register xxx putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
/* Jump here if hardware init fails or parameters are invalid. */
register_fail:
diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S
index 7ea2eec9fb..3310d2892f 100644
--- a/drivers/console/aarch64/skeleton_console.S
+++ b/drivers/console/aarch64/skeleton_console.S
@@ -63,7 +63,7 @@ func console_xxx_register
* If any of the argument is unspecified, then the corresponding
* entry in console_t is set to 0.
*/
- finish_console_register xxx putc=1, getc=1, flush=1
+ finish_console_register xxx putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
/* Jump here if hardware init fails or parameters are invalid. */
register_fail:
diff --git a/drivers/console/multi_console.c b/drivers/console/multi_console.c
index 08b8e9fb17..e962fff373 100644
--- a/drivers/console/multi_console.c
+++ b/drivers/console/multi_console.c
@@ -1,15 +1,17 @@
/*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
#include <drivers/console.h>
console_t *console_list;
-uint8_t console_state = CONSOLE_FLAG_BOOT;
+static uint8_t console_state = CONSOLE_FLAG_BOOT;
IMPORT_SYM(console_t *, __STACKS_START__, stacks_start)
IMPORT_SYM(console_t *, __STACKS_END__, stacks_end)
@@ -95,10 +97,18 @@ int console_putc(int c)
if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
err = ret;
}
-
return err;
}
+int putchar(int c)
+{
+ if (console_putc(c) == 0)
+ return c;
+ else
+ return EOF;
+}
+
+#if ENABLE_CONSOLE_GETC
int console_getc(void)
{
int err = ERROR_NO_VALID_CONSOLE;
@@ -118,6 +128,7 @@ int console_getc(void)
return err;
}
+#endif
void console_flush(void)
{
diff --git a/drivers/fwu/fwu.c b/drivers/fwu/fwu.c
new file mode 100644
index 0000000000..b6f06e0a7b
--- /dev/null
+++ b/drivers/fwu/fwu.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/tf_crc32.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/fwu/fwu.h>
+#include <drivers/fwu/fwu_metadata.h>
+#include <drivers/io/io_storage.h>
+
+#include <plat/common/platform.h>
+
+/*
+ * Assert that crc_32 is the first member of fwu_metadata structure.
+ * It avoids accessing data outside of the metadata structure during
+ * CRC32 computation if the crc_32 field gets moved due the structure
+ * member(s) addition in the future.
+ */
+CASSERT((offsetof(struct fwu_metadata, crc_32) == 0),
+ crc_32_must_be_first_member_of_structure);
+
+/*
+ * Ensure that the NR_OF_FW_BANKS selected by the platform is not
+ * zero and not greater than the maximum number of banks allowed
+ * by the specification.
+ */
+CASSERT((NR_OF_FW_BANKS > 0) && (NR_OF_FW_BANKS <= NR_OF_MAX_FW_BANKS),
+ assert_fwu_num_banks_invalid_value);
+
+#define FWU_METADATA_VERSION 2U
+#define FWU_FW_STORE_DESC_OFFSET 0x20U
+
+static struct fwu_metadata metadata;
+static bool is_metadata_initialized __unused;
+
+/*******************************************************************************
+ * Compute CRC32 of the FWU metadata, and check it against the CRC32 value
+ * present in the FWU metadata.
+ *
+ * return -1 on error, otherwise 0
+ ******************************************************************************/
+static int fwu_metadata_crc_check(void)
+{
+ unsigned char *data = (unsigned char *)&metadata;
+
+ uint32_t calc_crc = tf_crc32(0U, data + sizeof(metadata.crc_32),
+ (sizeof(metadata) -
+ sizeof(metadata.crc_32)));
+
+ if (metadata.crc_32 != calc_crc) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Check the sanity of FWU metadata.
+ *
+ * return -EINVAL on error, otherwise 0
+ ******************************************************************************/
+static int fwu_metadata_sanity_check(void)
+{
+ if (metadata.version != FWU_METADATA_VERSION) {
+ WARN("Incorrect FWU Metadata version of %u\n",
+ metadata.version);
+ return -EINVAL;
+ }
+
+ if (metadata.active_index >= NR_OF_FW_BANKS) {
+ WARN("Active Index value(%u) greater than the configured value(%d)",
+ metadata.active_index, NR_OF_FW_BANKS);
+ return -EINVAL;
+ }
+
+ if (metadata.previous_active_index >= NR_OF_FW_BANKS) {
+ WARN("Previous Active Index value(%u) greater than the configured value(%d)",
+ metadata.previous_active_index, NR_OF_FW_BANKS);
+ return -EINVAL;
+ }
+
+#if PSA_FWU_METADATA_FW_STORE_DESC
+ if (metadata.fw_desc.num_banks != NR_OF_FW_BANKS) {
+ WARN("Number of Banks(%u) in FWU Metadata different from the configured value(%d)",
+ metadata.fw_desc.num_banks, NR_OF_FW_BANKS);
+ return -EINVAL;
+ }
+
+ if (metadata.fw_desc.num_images != NR_OF_IMAGES_IN_FW_BANK) {
+ WARN("Number of Images(%u) in FWU Metadata different from the configured value(%d)",
+ metadata.fw_desc.num_images, NR_OF_IMAGES_IN_FW_BANK);
+ return -EINVAL;
+ }
+
+ if (metadata.desc_offset != FWU_FW_STORE_DESC_OFFSET) {
+ WARN("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n",
+ metadata.desc_offset);
+ return -EINVAL;
+ }
+#else
+ if (metadata.desc_offset != 0U) {
+ WARN("Descriptor offset has non zero value of 0x%x\n",
+ metadata.desc_offset);
+ return -EINVAL;
+ }
+#endif
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Verify and load specified FWU metadata image to local FWU metadata structure.
+ *
+ * @image_id: FWU metadata image id (either FWU_METADATA_IMAGE_ID or
+ * BKUP_FWU_METADATA_IMAGE_ID)
+ *
+ * return a negative value on error, otherwise 0
+ ******************************************************************************/
+static int fwu_metadata_load(unsigned int image_id)
+{
+ int result;
+ uintptr_t dev_handle, image_handle, image_spec;
+ size_t bytes_read;
+
+ assert((image_id == FWU_METADATA_IMAGE_ID) ||
+ (image_id == BKUP_FWU_METADATA_IMAGE_ID));
+
+ result = plat_fwu_set_metadata_image_source(image_id,
+ &dev_handle,
+ &image_spec);
+ if (result != 0) {
+ WARN("Failed to set reference to image id=%u (%i)\n",
+ image_id, result);
+ return result;
+ }
+
+ result = io_open(dev_handle, image_spec, &image_handle);
+ if (result != 0) {
+ WARN("Failed to load image id id=%u (%i)\n",
+ image_id, result);
+ return result;
+ }
+
+ result = io_read(image_handle, (uintptr_t)&metadata,
+ sizeof(struct fwu_metadata), &bytes_read);
+
+ if (result != 0) {
+ WARN("Failed to read image id=%u (%i)\n", image_id, result);
+ goto exit;
+ }
+
+ if (sizeof(struct fwu_metadata) != bytes_read) {
+ /* return -1 in case of partial/no read */
+ result = -1;
+ WARN("Read bytes (%zu) instead of expected (%zu) bytes\n",
+ bytes_read, sizeof(struct fwu_metadata));
+ goto exit;
+ }
+
+ /* sanity check on loaded parameters */
+ result = fwu_metadata_sanity_check();
+ if (result != 0) {
+ WARN("Sanity %s\n", "check failed on FWU metadata");
+ goto exit;
+ }
+
+ /* CRC check on loaded parameters */
+ result = fwu_metadata_crc_check();
+ if (result != 0) {
+ WARN("CRC %s\n", "check failed on FWU metadata");
+ }
+
+exit:
+ (void)io_close(image_handle);
+
+ return result;
+}
+
+/*******************************************************************************
+ * Check for an alternate bank for the platform to boot from. This function will
+ * mostly be called whenever the count of the number of times a platform boots
+ * in the Trial State exceeds a pre-set limit.
+ * The function first checks if the platform can boot from the previously active
+ * bank. If not, it tries to find another bank in the accepted state.
+ * And finally, if both the checks fail, as a last resort, it tries to find
+ * a valid bank.
+ *
+ * Returns the index of a bank to boot, else returns invalid index
+ * INVALID_BOOT_IDX.
+ ******************************************************************************/
+uint32_t fwu_get_alternate_boot_bank(void)
+{
+ uint32_t i;
+
+ /* First check if the previously active bank can be used */
+ if (metadata.bank_state[metadata.previous_active_index] ==
+ FWU_BANK_STATE_ACCEPTED) {
+ return metadata.previous_active_index;
+ }
+
+ /* Now check for any other bank in the accepted state */
+ for (i = 0U; i < NR_OF_FW_BANKS; i++) {
+ if (i == metadata.active_index ||
+ i == metadata.previous_active_index) {
+ continue;
+ }
+
+ if (metadata.bank_state[i] == FWU_BANK_STATE_ACCEPTED) {
+ return i;
+ }
+ }
+
+ /*
+ * No accepted bank found. Now try booting from a valid bank.
+ * Give priority to the previous active bank.
+ */
+ if (metadata.bank_state[metadata.previous_active_index] ==
+ FWU_BANK_STATE_VALID) {
+ return metadata.previous_active_index;
+ }
+
+ for (i = 0U; i < NR_OF_FW_BANKS; i++) {
+ if (i == metadata.active_index ||
+ i == metadata.previous_active_index) {
+ continue;
+ }
+
+ if (metadata.bank_state[i] == FWU_BANK_STATE_VALID) {
+ return i;
+ }
+ }
+
+ return INVALID_BOOT_IDX;
+}
+
+/*******************************************************************************
+ * The platform can be in one of Valid, Invalid or Accepted states.
+ *
+ * Invalid - One or more images in the bank are corrupted, or partially
+ * overwritten. The bank is not to be used for booting.
+ *
+ * Valid - All images of the bank are valid but at least one image has not
+ * been accepted. This implies that the platform is in Trial State.
+ *
+ * Accepted - All images of the bank are valid and accepted.
+ *
+ * Returns the state of the current active bank
+ ******************************************************************************/
+uint32_t fwu_get_active_bank_state(void)
+{
+ assert(is_metadata_initialized);
+
+ return metadata.bank_state[metadata.active_index];
+}
+
+const struct fwu_metadata *fwu_get_metadata(void)
+{
+ assert(is_metadata_initialized);
+
+ return &metadata;
+}
+
+/*******************************************************************************
+ * Load verified copy of FWU metadata image kept in the platform NV storage
+ * into local FWU metadata structure.
+ * Also, update platform I/O policies with the offset address and length of
+ * firmware-updated images kept in the platform NV storage.
+ ******************************************************************************/
+void fwu_init(void)
+{
+ /* Load FWU metadata which will be used to load the images in the
+ * active bank as per PSA FWU specification
+ */
+ int result = fwu_metadata_load(FWU_METADATA_IMAGE_ID);
+
+ if (result != 0) {
+ WARN("loading of FWU-Metadata failed, "
+ "using Bkup-FWU-Metadata\n");
+
+ result = fwu_metadata_load(BKUP_FWU_METADATA_IMAGE_ID);
+ if (result != 0) {
+ ERROR("loading of Bkup-FWU-Metadata failed\n");
+ panic();
+ }
+ }
+
+ is_metadata_initialized = true;
+
+ plat_fwu_set_images_source(&metadata);
+}
diff --git a/drivers/fwu/fwu.mk b/drivers/fwu/fwu.mk
new file mode 100644
index 0000000000..f4452e03b8
--- /dev/null
+++ b/drivers/fwu/fwu.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+FWU_SRC_DIR := drivers/fwu/
+
+FWU_SRCS := ${FWU_SRC_DIR}fwu.c
+
+BL2_SOURCES += ${FWU_SRCS}
diff --git a/drivers/imx/usdhc/imx_usdhc.c b/drivers/imx/usdhc/imx_usdhc.c
index 07f55b7843..49dfc076dc 100644
--- a/drivers/imx/usdhc/imx_usdhc.c
+++ b/drivers/imx/usdhc/imx_usdhc.c
@@ -136,7 +136,8 @@ static int imx_usdhc_send_cmd(struct mmc_cmd *cmd)
break;
case MMC_CMD(18):
multiple = 1;
- /* fall thru for read op */
+ /* for read op */
+ /* fallthrough */
case MMC_CMD(17):
case MMC_CMD(8):
mixctl |= MIXCTRL_DTDSEL;
@@ -144,7 +145,8 @@ static int imx_usdhc_send_cmd(struct mmc_cmd *cmd)
break;
case MMC_CMD(25):
multiple = 1;
- /* fall thru for data op flag */
+ /* for data op flag */
+ /* fallthrough */
case MMC_CMD(24):
data = 1;
break;
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
index 5d45c2f176..b5e0e5f722 100644
--- a/drivers/io/io_block.c
+++ b/drivers/io/io_block.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -271,7 +271,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
block_size = cur->dev_spec->block_size;
assert((length <= cur->size) &&
(length > 0U) &&
- (ops->read != 0));
+ (ops->read != NULL));
/*
* We don't know the number of bytes that we are going
@@ -383,8 +383,8 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
block_size = cur->dev_spec->block_size;
assert((length <= cur->size) &&
(length > 0U) &&
- (ops->read != 0) &&
- (ops->write != 0));
+ (ops->read != NULL) &&
+ (ops->write != NULL));
/*
* We don't know the number of bytes that we are going
diff --git a/drivers/io/io_dummy.c b/drivers/io/io_dummy.c
deleted file mode 100644
index 4f0cda6daf..0000000000
--- a/drivers/io/io_dummy.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <string.h>
-
-#include <common/debug.h>
-#include <drivers/io/io_driver.h>
-#include <drivers/io/io_dummy.h>
-#include <drivers/io/io_storage.h>
-
-struct file_state {
- int in_use;
- size_t size;
-};
-
-static struct file_state current_file = {0};
-
-/* Identify the device type as dummy */
-static io_type_t device_type_dummy(void)
-{
- return IO_TYPE_DUMMY;
-}
-
-/* Dummy device functions */
-static int dummy_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
-static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
- io_entity_t *entity);
-static int dummy_block_len(io_entity_t *entity, size_t *length);
-static int dummy_block_read(io_entity_t *entity, uintptr_t buffer,
- size_t length, size_t *length_read);
-static int dummy_block_close(io_entity_t *entity);
-static int dummy_dev_close(io_dev_info_t *dev_info);
-
-
-static const io_dev_connector_t dummy_dev_connector = {
- .dev_open = dummy_dev_open
-};
-
-
-static const io_dev_funcs_t dummy_dev_funcs = {
- .type = device_type_dummy,
- .open = dummy_block_open,
- .seek = NULL,
- .size = dummy_block_len,
- .read = dummy_block_read,
- .write = NULL,
- .close = dummy_block_close,
- .dev_init = NULL,
- .dev_close = dummy_dev_close,
-};
-
-
-static const io_dev_info_t dummy_dev_info = {
- .funcs = &dummy_dev_funcs,
- .info = (uintptr_t)NULL
-};
-
-
-/* Open a connection to the dummy device */
-static int dummy_dev_open(const uintptr_t dev_spec __attribute__((unused)),
- io_dev_info_t **dev_info)
-{
- assert(dev_info != NULL);
- *dev_info = (io_dev_info_t *)&dummy_dev_info;
-
- return 0;
-}
-
-
-/* Close a connection to the dummy device */
-static int dummy_dev_close(io_dev_info_t *dev_info)
-{
- return 0;
-}
-
-
-/* Open a file on the dummy device */
-static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
- io_entity_t *entity)
-{
- int result;
- const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
-
- if (current_file.in_use == 0) {
- assert(block_spec != NULL);
- assert(entity != NULL);
-
- current_file.in_use = 1;
- current_file.size = block_spec->length;
- entity->info = (uintptr_t)&current_file;
- result = 0;
- } else {
- WARN("A Dummy device is already active. Close first.\n");
- result = -ENOMEM;
- }
-
- return result;
-}
-
-
-/* Return the size of a file on the dummy device */
-static int dummy_block_len(io_entity_t *entity, size_t *length)
-{
- assert(entity != NULL);
- assert(length != NULL);
-
- *length = ((struct file_state *)entity->info)->size;
-
- return 0;
-}
-
-
-/* Read data from a file on the dummy device */
-static int dummy_block_read(io_entity_t *entity, uintptr_t buffer,
- size_t length, size_t *length_read)
-{
- assert(length_read != NULL);
-
- *length_read = length;
-
- return 0;
-}
-
-
-/* Close a file on the dummy device */
-static int dummy_block_close(io_entity_t *entity)
-{
- assert(entity != NULL);
-
- entity->info = 0;
- current_file.in_use = 0;
-
- return 0;
-}
-
-
-/* Exported functions */
-
-/* Register the dummy driver with the IO abstraction */
-int register_io_dev_dummy(const io_dev_connector_t **dev_con)
-{
- int result;
-
- assert(dev_con != NULL);
-
- result = io_register_device(&dummy_dev_info);
- if (result == 0)
- *dev_con = &dummy_dev_connector;
-
- return result;
-}
diff --git a/drivers/io/io_mtd.c b/drivers/io/io_mtd.c
index 7575fa2503..5d86592db9 100644
--- a/drivers/io/io_mtd.c
+++ b/drivers/io/io_mtd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,18 +8,19 @@
#include <errno.h>
#include <string.h>
-#include <platform_def.h>
-
#include <common/debug.h>
#include <drivers/io/io_driver.h>
#include <drivers/io/io_mtd.h>
#include <lib/utils.h>
+#include <platform_def.h>
+
typedef struct {
io_mtd_dev_spec_t *dev_spec;
uintptr_t base;
- unsigned long long offset; /* Offset in bytes */
- unsigned long long size; /* Size of device in bytes */
+ unsigned long long pos; /* Offset in bytes */
+ unsigned long long size; /* Size of device in bytes */
+ unsigned long long extra_offset; /* Extra offset in bytes */
} mtd_dev_state_t;
io_type_t device_type_mtd(void);
@@ -110,16 +111,47 @@ static int free_dev_info(io_dev_info_t *dev_info)
return 0;
}
+static int mtd_add_extra_offset(mtd_dev_state_t *cur, size_t *extra_offset)
+{
+ io_mtd_ops_t *ops = &cur->dev_spec->ops;
+ int ret;
+
+ if (ops->seek == NULL) {
+ return 0;
+ }
+
+ ret = ops->seek(cur->base, cur->pos, extra_offset);
+ if (ret != 0) {
+ ERROR("%s: Seek error %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity)
{
mtd_dev_state_t *cur;
+ io_block_spec_t *region;
+ size_t extra_offset = 0U;
+ int ret;
assert((dev_info->info != 0UL) && (entity->info == 0UL));
+ region = (io_block_spec_t *)spec;
cur = (mtd_dev_state_t *)dev_info->info;
entity->info = (uintptr_t)cur;
- cur->offset = 0U;
+ cur->base = region->offset;
+ cur->pos = 0U;
+ cur->extra_offset = 0U;
+
+ ret = mtd_add_extra_offset(cur, &extra_offset);
+ if (ret != 0) {
+ return ret;
+ }
+
+ cur->base += extra_offset;
return 0;
}
@@ -128,6 +160,8 @@ static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
{
mtd_dev_state_t *cur;
+ size_t extra_offset = 0U;
+ int ret;
assert((entity->info != (uintptr_t)NULL) && (offset >= 0));
@@ -140,22 +174,29 @@ static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
return -EINVAL;
}
- cur->offset = offset;
+ cur->pos = offset;
break;
case IO_SEEK_CUR:
- if (((cur->offset + (unsigned long long)offset) >=
+ if (((cur->base + cur->pos + (unsigned long long)offset) >=
cur->size) ||
- ((cur->offset + (unsigned long long)offset) <
- cur->offset)) {
+ ((cur->base + cur->pos + (unsigned long long)offset) <
+ cur->base + cur->pos)) {
return -EINVAL;
}
- cur->offset += (unsigned long long)offset;
+ cur->pos += (unsigned long long)offset;
break;
default:
return -EINVAL;
}
+ ret = mtd_add_extra_offset(cur, &extra_offset);
+ if (ret != 0) {
+ return ret;
+ }
+
+ cur->extra_offset = extra_offset;
+
return 0;
}
@@ -173,19 +214,20 @@ static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
ops = &cur->dev_spec->ops;
assert(ops->read != NULL);
- VERBOSE("Read at %llx into %lx, length %zi\n",
- cur->offset, buffer, length);
- if ((cur->offset + length) > cur->dev_spec->device_size) {
+ VERBOSE("Read at %llx into %lx, length %zu\n",
+ cur->base + cur->pos, buffer, length);
+ if ((cur->base + cur->pos + length) > cur->dev_spec->device_size) {
return -EINVAL;
}
- ret = ops->read(cur->offset, buffer, length, out_length);
+ ret = ops->read(cur->base + cur->pos + cur->extra_offset, buffer,
+ length, out_length);
if (ret < 0) {
return ret;
}
assert(*out_length == length);
- cur->offset += *out_length;
+ cur->pos += *out_length;
return 0;
}
diff --git a/drivers/marvell/amb_adec.c b/drivers/marvell/amb_adec.c
index 1f671058d5..d78fa25174 100644
--- a/drivers/marvell/amb_adec.c
+++ b/drivers/marvell/amb_adec.c
@@ -7,6 +7,9 @@
/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
+#include <inttypes.h>
+#include <stdint.h>
+
#include <common/debug.h>
#include <lib/mmio.h>
@@ -44,10 +47,10 @@ static void amb_check_win(struct addr_map_win *win, uint32_t win_num)
/* make sure the base address is in 16-bit range */
if (win->base_addr > AMB_BASE_ADDR_MASK) {
- WARN("Window %d: base address is too big 0x%llx\n",
+ WARN("Window %d: base address is too big 0x%" PRIx64 "\n",
win_num, win->base_addr);
win->base_addr = AMB_BASE_ADDR_MASK;
- WARN("Set the base address to 0x%llx\n", win->base_addr);
+ WARN("Set the base address to 0x%" PRIx64 "\n", win->base_addr);
}
base_addr = win->base_addr << AMB_BASE_OFFSET;
@@ -57,15 +60,15 @@ static void amb_check_win(struct addr_map_win *win, uint32_t win_num)
win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M);
WARN("Window %d: base address unaligned to 0x%x\n",
win_num, AMB_WIN_ALIGNMENT_1M);
- WARN("Align up the base address to 0x%llx\n", win->base_addr);
+ WARN("Align up the base address to 0x%" PRIx64 "\n", win->base_addr);
}
/* size parameter validity check */
if (!IS_POWER_OF_2(win->win_size)) {
- WARN("Window %d: window size is not power of 2 (0x%llx)\n",
+ WARN("Window %d: window size is not power of 2 (0x%" PRIx64 ")\n",
win_num, win->win_size);
win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size);
- WARN("Rounding size to 0x%llx\n", win->win_size);
+ WARN("Rounding size to 0x%" PRIx64 "\n", win->win_size);
}
}
diff --git a/drivers/marvell/ccu.c b/drivers/marvell/ccu.c
index b4251f49bd..c206f11684 100644
--- a/drivers/marvell/ccu.c
+++ b/drivers/marvell/ccu.c
@@ -7,6 +7,9 @@
/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+#include <inttypes.h>
+#include <stdint.h>
+
#include <common/debug.h>
#include <drivers/marvell/ccu.h>
#include <lib/mmio.h>
@@ -84,7 +87,7 @@ static void dump_ccu(int ap_index)
win_id));
start = ((uint64_t)alr << ADDRESS_SHIFT);
end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
- printf("\tccu%d %02x 0x%016llx 0x%016llx\n",
+ printf("\tccu%d %02x 0x%016" PRIx64 " 0x%016" PRIx64 "\n",
win_id, target_id, start, end);
}
}
@@ -99,14 +102,14 @@ void ccu_win_check(struct addr_map_win *win)
/* check if address is aligned to 1M */
if (IS_NOT_ALIGN(win->base_addr, CCU_WIN_ALIGNMENT)) {
win->base_addr = ALIGN_UP(win->base_addr, CCU_WIN_ALIGNMENT);
- NOTICE("%s: Align up the base address to 0x%llx\n",
+ NOTICE("%s: Align up the base address to 0x%" PRIx64 "\n",
__func__, win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, CCU_WIN_ALIGNMENT)) {
win->win_size = ALIGN_UP(win->win_size, CCU_WIN_ALIGNMENT);
- NOTICE("%s: Aligning size to 0x%llx\n",
+ NOTICE("%s: Aligning size to 0x%" PRIx64 "\n",
__func__, win->win_size);
}
}
diff --git a/drivers/marvell/comphy/comphy-cp110.h b/drivers/marvell/comphy/comphy-cp110.h
index 9b10619ed0..af5c715182 100644
--- a/drivers/marvell/comphy/comphy-cp110.h
+++ b/drivers/marvell/comphy/comphy-cp110.h
@@ -54,7 +54,7 @@
#define COMMON_SELECTOR_PIPE_COMPHY_USBH 0x1
#define COMMON_SELECTOR_PIPE_COMPHY_USBD 0x2
-/* SGMII/HS-SGMII/SFI/RXAUI */
+/* SGMII/Base-X/SFI/RXAUI */
#define COMMON_SELECTOR_COMPHY0_1_2_NETWORK 0x1
#define COMMON_SELECTOR_COMPHY3_RXAUI 0x1
#define COMMON_SELECTOR_COMPHY3_SGMII 0x2
diff --git a/drivers/marvell/comphy/phy-comphy-3700.c b/drivers/marvell/comphy/phy-comphy-3700.c
index 7377e5e3d9..1a97753f37 100644
--- a/drivers/marvell/comphy/phy-comphy-3700.c
+++ b/drivers/marvell/comphy/phy-comphy-3700.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018-2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
@@ -118,7 +118,7 @@ static uint16_t sgmii_phy_init[512] = {
};
/* PHY selector configures with corresponding modes */
-static void mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index,
+static int mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index,
uint32_t comphy_mode)
{
uint32_t reg;
@@ -135,7 +135,7 @@ static void mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index,
break;
case (COMPHY_SGMII_MODE):
- case (COMPHY_HS_SGMII_MODE):
+ case (COMPHY_2500BASEX_MODE):
if (comphy_index == COMPHY_LANE0)
reg &= ~COMPHY_SELECTOR_USB3_GBE1_SEL_BIT;
else if (comphy_index == COMPHY_LANE1)
@@ -168,9 +168,10 @@ static void mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index,
}
mmio_write_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG, reg);
- return;
+ return 0;
error:
ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
+ return -EINVAL;
}
/*
@@ -183,7 +184,7 @@ error:
* with COMPHY_USB3D_MODE or COMPHY_USB3H_MODE. (The usb3 phy initialization
* code does not differentiate between these modes.)
* Also it returns COMPHY_SGMII_MODE even if the phy was configures with
- * COMPHY_HS_SGMII_MODE. (The sgmii phy initialization code does differentiate
+ * COMPHY_2500BASEX_MODE. (The sgmii phy initialization code does differentiate
* between these modes, but it is irrelevant when powering the phy off.)
*/
static int mvebu_a3700_comphy_get_mode(uint8_t comphy_index)
@@ -214,7 +215,7 @@ static int mvebu_a3700_comphy_get_mode(uint8_t comphy_index)
/* It is only used for SATA and USB3 on comphy lane2. */
static void comphy_set_indirect(uintptr_t addr, uint32_t offset, uint16_t data,
- uint16_t mask, int mode)
+ uint16_t mask, bool is_sata)
{
/*
* When Lane 2 PHY is for USB3, access the PHY registers
@@ -224,27 +225,38 @@ static void comphy_set_indirect(uintptr_t addr, uint32_t offset, uint16_t data,
* within the SATA Host Controller registers, Lane 2 base register
* offset is 0x200
*/
- if (mode == COMPHY_UNUSED)
- return;
-
- if (mode == COMPHY_SATA_MODE)
+ if (is_sata) {
mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET, offset);
- else
+ } else {
mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET,
offset + USB3PHY_LANE2_REG_BASE_OFFSET);
+ }
reg_set(addr + COMPHY_LANE2_INDIR_DATA_OFFSET, data, mask);
}
-/* It is only used USB3 direct access not on comphy lane2. */
+/* It is only used for SATA on comphy lane2. */
+static void comphy_sata_set_indirect(uintptr_t addr, uint32_t reg_offset,
+ uint16_t data, uint16_t mask)
+{
+ comphy_set_indirect(addr, reg_offset, data, mask, true);
+}
+
+/* It is only used for USB3 indirect access on comphy lane2. */
+static void comphy_usb3_set_indirect(uintptr_t addr, uint32_t reg_offset,
+ uint16_t data, uint16_t mask)
+{
+ comphy_set_indirect(addr, reg_offset, data, mask, false);
+}
+
+/* It is only used for USB3 direct access not on comphy lane2. */
static void comphy_usb3_set_direct(uintptr_t addr, uint32_t reg_offset,
- uint16_t data, uint16_t mask, int mode)
+ uint16_t data, uint16_t mask)
{
reg_set16((reg_offset * PHY_SHFT(USB3) + addr), data, mask);
}
-static void comphy_sgmii_phy_init(uint32_t comphy_index, uint32_t mode,
- uintptr_t sd_ip_addr)
+static void comphy_sgmii_phy_init(uintptr_t sd_ip_addr, bool is_1gbps)
{
const int fix_arr_sz = ARRAY_SIZE(sgmii_phy_init_fix);
int addr, fix_idx;
@@ -259,8 +271,7 @@ static void comphy_sgmii_phy_init(uint32_t comphy_index, uint32_t mode,
* comparison to 3.125 Gbps values. These register values are
* stored in "sgmii_phy_init_fix" array.
*/
- if ((mode != COMPHY_SGMII_MODE) &&
- (sgmii_phy_init_fix[fix_idx].addr == addr)) {
+ if (!is_1gbps && sgmii_phy_init_fix[fix_idx].addr == addr) {
/* Use new value */
val = sgmii_phy_init_fix[fix_idx].value;
if (fix_idx < fix_arr_sz)
@@ -276,21 +287,22 @@ static void comphy_sgmii_phy_init(uint32_t comphy_index, uint32_t mode,
static int mvebu_a3700_comphy_sata_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
- int ret = 0;
+ int ret;
uint32_t offset, data = 0, ref_clk;
uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
- int mode = COMPHY_GET_MODE(comphy_mode);
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
debug_enter();
/* Configure phy selector for SATA */
- mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
/* Clear phy isolation mode to make it work in normal mode */
- offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
- comphy_set_indirect(comphy_indir_regs, offset, 0, PHY_ISOLATE_MODE,
- mode);
+ offset = COMPHY_ISOLATION_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, 0, PHY_ISOLATE_MODE);
/* 0. Check the Polarity invert bits */
if (invert & COMPHY_POLARITY_TXD_INVERT)
@@ -298,33 +310,33 @@ static int mvebu_a3700_comphy_sata_power_on(uint8_t comphy_index,
if (invert & COMPHY_POLARITY_RXD_INVERT)
data |= RXD_INVERT_BIT;
- offset = COMPHY_SYNC_PATTERN_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
- comphy_set_indirect(comphy_indir_regs, offset, data, TXD_INVERT_BIT |
- RXD_INVERT_BIT, mode);
+ offset = COMPHY_SYNC_PATTERN + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, data, TXD_INVERT_BIT |
+ RXD_INVERT_BIT);
/* 1. Select 40-bit data width width */
- offset = COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET;
- comphy_set_indirect(comphy_indir_regs, offset, DATA_WIDTH_40BIT,
- SEL_DATA_WIDTH_MASK, mode);
+ offset = COMPHY_DIG_LOOPBACK_EN + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, DATA_WIDTH_40BIT,
+ SEL_DATA_WIDTH_MASK);
/* 2. Select reference clock(25M) and PHY mode (SATA) */
offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
if (get_ref_clk() == 40)
- ref_clk = REF_CLOCK_SPEED_40M;
+ ref_clk = REF_FREF_SEL_SERDES_40MHZ;
else
- ref_clk = REF_CLOCK_SPEED_25M;
+ ref_clk = REF_FREF_SEL_SERDES_25MHZ;
- comphy_set_indirect(comphy_indir_regs, offset, ref_clk | PHY_MODE_SATA,
- REF_FREF_SEL_MASK | PHY_MODE_MASK, mode);
+ comphy_sata_set_indirect(comphy_indir_regs, offset, ref_clk | PHY_MODE_SATA,
+ REF_FREF_SEL_MASK | PHY_MODE_MASK);
/* 3. Use maximum PLL rate (no power save) */
offset = COMPHY_KVCO_CAL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
- comphy_set_indirect(comphy_indir_regs, offset, USE_MAX_PLL_RATE_BIT,
- USE_MAX_PLL_RATE_BIT, mode);
+ comphy_sata_set_indirect(comphy_indir_regs, offset, USE_MAX_PLL_RATE_BIT,
+ USE_MAX_PLL_RATE_BIT);
/* 4. Reset reserved bit */
- comphy_set_indirect(comphy_indir_regs, COMPHY_RESERVED_REG, 0,
- PHYCTRL_FRM_PIN_BIT, mode);
+ comphy_sata_set_indirect(comphy_indir_regs, COMPHY_RESERVED_REG, 0,
+ PHYCTRL_FRM_PIN_BIT);
/* 5. Set vendor-specific configuration (It is done in sata driver) */
/* XXX: in U-Boot below sequence was executed in this place, in Linux
@@ -340,23 +352,27 @@ static int mvebu_a3700_comphy_sata_power_on(uint8_t comphy_index,
/* Polling status */
mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET,
- COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET);
+ COMPHY_DIG_LOOPBACK_EN + SATAPHY_LANE2_REG_BASE_OFFSET);
ret = polling_with_timeout(comphy_indir_regs +
COMPHY_LANE2_INDIR_DATA_OFFSET,
PLL_READY_TX_BIT, PLL_READY_TX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
+ if (ret) {
+ return -ETIMEDOUT;
+ }
debug_exit();
- return ret;
+ return 0;
}
static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
- int ret = 0;
- uint32_t mask, data, offset;
+ int ret;
+ uint32_t mask, data;
+ uintptr_t offset;
uintptr_t sd_ip_addr;
int mode = COMPHY_GET_MODE(comphy_mode);
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
@@ -364,7 +380,10 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
debug_enter();
/* Set selector */
- mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
/* Serdes IP Base address
* COMPHY Lane0 -- USB3/GBE1
@@ -382,8 +401,8 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
* PHY TXP/TXN output to idle state during PHY initialization
* 3. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0.
*/
- data = PIN_PU_IVEREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT;
- mask = PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT |
+ data = PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT;
+ mask = data | PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT |
PIN_PU_TX_BIT;
offset = MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index);
reg_set(offset, data, mask);
@@ -401,10 +420,10 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
/* SGMII 1G, SerDes speed 1.25G */
data |= SD_SPEED_1_25_G << GEN_RX_SEL_OFFSET;
data |= SD_SPEED_1_25_G << GEN_TX_SEL_OFFSET;
- } else if (mode == COMPHY_HS_SGMII_MODE) {
- /* HS SGMII (2.5G), SerDes speed 3.125G */
- data |= SD_SPEED_2_5_G << GEN_RX_SEL_OFFSET;
- data |= SD_SPEED_2_5_G << GEN_TX_SEL_OFFSET;
+ } else if (mode == COMPHY_2500BASEX_MODE) {
+ /* 2500Base-X, SerDes speed 3.125G */
+ data |= SD_SPEED_3_125_G << GEN_RX_SEL_OFFSET;
+ data |= SD_SPEED_3_125_G << GEN_TX_SEL_OFFSET;
} else {
/* Other rates are not supported */
ERROR("unsupported SGMII speed on comphy lane%d\n",
@@ -431,16 +450,16 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
*/
data = 0;
mask = PHY_REF_CLK_SEL;
- reg_set16(SGMIIPHY_ADDR(COMPHY_MISC_REG0_ADDR, sd_ip_addr), data, mask);
+ reg_set16(SGMIIPHY_ADDR(COMPHY_MISC_CTRL0, sd_ip_addr), data, mask);
/*
* 9. Set correct reference clock frequency in COMPHY register
* REF_FREF_SEL.
*/
if (get_ref_clk() == 40)
- data = REF_CLOCK_SPEED_50M;
+ data = REF_FREF_SEL_SERDES_50MHZ;
else
- data = REF_CLOCK_SPEED_25M;
+ data = REF_FREF_SEL_SERDES_25MHZ;
mask = REF_FREF_SEL_MASK;
reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask);
@@ -458,7 +477,8 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
*/
data = DATA_WIDTH_10BIT;
mask = SEL_DATA_WIDTH_MASK;
- reg_set16(SGMIIPHY_ADDR(COMPHY_LOOPBACK_REG0, sd_ip_addr), data, mask);
+ reg_set16(SGMIIPHY_ADDR(COMPHY_DIG_LOOPBACK_EN, sd_ip_addr),
+ data, mask);
/*
* 12. As long as DFE function needs to be enabled in any mode,
@@ -479,9 +499,9 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
* 25 MHz the default values stored in PHY registers are OK.
*/
debug("Running C-DPI phy init %s mode\n",
- mode == COMPHY_HS_SGMII_MODE ? "2G5" : "1G");
+ mode == COMPHY_2500BASEX_MODE ? "2G5" : "1G");
if (get_ref_clk() == 40)
- comphy_sgmii_phy_init(comphy_index, mode, sd_ip_addr);
+ comphy_sgmii_phy_init(sd_ip_addr, mode != COMPHY_2500BASEX_MODE);
/*
* 14. [Simulation Only] should not be used for real chip.
@@ -504,7 +524,7 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
if (invert & COMPHY_POLARITY_RXD_INVERT)
data |= RXD_INVERT_BIT;
mask = TXD_INVERT_BIT | RXD_INVERT_BIT;
- reg_set16(SGMIIPHY_ADDR(COMPHY_SYNC_PATTERN_REG, sd_ip_addr), data, mask);
+ reg_set16(SGMIIPHY_ADDR(COMPHY_SYNC_PATTERN, sd_ip_addr), data, mask);
/*
* 17. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 to
@@ -525,8 +545,10 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
- if (ret)
+ if (ret) {
ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index);
+ return -ETIMEDOUT;
+ }
/*
* 19. Set COMPHY input port PIN_TX_IDLE=0
@@ -549,26 +571,29 @@ static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
- if (ret)
+ if (ret) {
ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index);
-
+ return -ETIMEDOUT;
+ }
ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
COMPHY_PHY_STATUS_OFFSET(comphy_index),
PHY_RX_INIT_DONE_BIT, PHY_RX_INIT_DONE_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
- if (ret)
+ if (ret) {
ERROR("Failed to init RX of SGMII PHY %d\n", comphy_index);
+ return -ETIMEDOUT;
+ }
debug_exit();
- return ret;
+ return 0;
}
static int mvebu_a3700_comphy_sgmii_power_off(uint8_t comphy_index)
{
- int ret = 0;
- uint32_t mask, data, offset;
+ uintptr_t offset;
+ uint32_t mask, data;
debug_enter();
@@ -579,28 +604,31 @@ static int mvebu_a3700_comphy_sgmii_power_off(uint8_t comphy_index)
debug_exit();
- return ret;
+ return 0;
}
static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
- int ret = 0;
+ int ret;
uintptr_t reg_base = 0;
- uint32_t mask, data, addr, cfg, ref_clk;
+ uintptr_t addr;
+ uint32_t mask, data, cfg, ref_clk;
void (*usb3_reg_set)(uintptr_t addr, uint32_t reg_offset, uint16_t data,
- uint16_t mask, int mode);
- int mode = COMPHY_GET_MODE(comphy_mode);
+ uint16_t mask);
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
debug_enter();
/* Set phy seclector */
- mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
/* Set usb3 reg access func, Lane2 is indirect access */
if (comphy_index == COMPHY_LANE2) {
- usb3_reg_set = &comphy_set_indirect;
+ usb3_reg_set = &comphy_usb3_set_indirect;
reg_base = COMPHY_INDIRECT_REG;
} else {
/* Get the direct access register resource and map */
@@ -618,68 +646,68 @@ static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
*/
mask = PRD_TXDEEMPH0_MASK | PRD_TXMARGIN_MASK | PRD_TXSWING_MASK |
CFG_TX_ALIGN_POS_MASK;
- usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG0_ADDR, PRD_TXDEEMPH0_MASK,
- mask, mode);
+ usb3_reg_set(reg_base, COMPHY_LANE_CFG0, PRD_TXDEEMPH0_MASK, mask);
/*
* 2. Set BIT0: enable transmitter in high impedance mode
* Set BIT[3:4]: delay 2 clock cycles for HiZ off latency
* Set BIT6: Tx detect Rx at HiZ mode
* Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db
- * together with bit 0 of COMPHY_REG_LANE_CFG0_ADDR register
+ * together with bit 0 of COMPHY_LANE_CFG0 register
*/
mask = PRD_TXDEEMPH1_MASK | TX_DET_RX_MODE | GEN2_TX_DATA_DLY_MASK |
TX_ELEC_IDLE_MODE_EN;
data = TX_DET_RX_MODE | GEN2_TX_DATA_DLY_DEFT | TX_ELEC_IDLE_MODE_EN;
- usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG1_ADDR, data, mask, mode);
+ usb3_reg_set(reg_base, COMPHY_LANE_CFG1, data, mask);
/*
* 3. Set Spread Spectrum Clock Enabled
*/
- usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG4_ADDR,
- SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN, mode);
+ usb3_reg_set(reg_base, COMPHY_LANE_CFG4,
+ SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN);
/*
* 4. Set Override Margining Controls From the MAC:
* Use margining signals from lane configuration
*/
- usb3_reg_set(reg_base, COMPHY_REG_TEST_MODE_CTRL_ADDR,
- MODE_MARGIN_OVERRIDE, REG_16_BIT_MASK, mode);
+ usb3_reg_set(reg_base, COMPHY_TEST_MODE_CTRL,
+ MODE_MARGIN_OVERRIDE, REG_16_BIT_MASK);
/*
* 5. Set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles
* set Mode Clock Source = PCLK is generated from REFCLK
*/
- usb3_reg_set(reg_base, COMPHY_REG_GLOB_CLK_SRC_LO_ADDR, 0x0,
- (MODE_CLK_SRC | BUNDLE_PERIOD_SEL | BUNDLE_PERIOD_SCALE |
- BUNDLE_SAMPLE_CTRL | PLL_READY_DLY), mode);
+ usb3_reg_set(reg_base, COMPHY_CLK_SRC_LO, 0x0,
+ (MODE_CLK_SRC | BUNDLE_PERIOD_SEL |
+ BUNDLE_PERIOD_SCALE_MASK | BUNDLE_SAMPLE_CTRL |
+ PLL_READY_DLY_MASK));
/*
* 6. Set G2 Spread Spectrum Clock Amplitude at 4K
*/
- usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_2,
- G2_TX_SSC_AMP_VALUE_20, G2_TX_SSC_AMP_MASK, mode);
+ usb3_reg_set(reg_base, COMPHY_GEN2_SET2,
+ GS2_TX_SSC_AMP_VALUE_20, GS2_TX_SSC_AMP_MASK);
/*
* 7. Unset G3 Spread Spectrum Clock Amplitude
* set G3 TX and RX Register Master Current Select
*/
- mask = G3_TX_SSC_AMP_MASK | G3_VREG_RXTX_MAS_ISET_MASK |
- RSVD_PH03FH_6_0_MASK;
- usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_3,
- G3_VREG_RXTX_MAS_ISET_60U, mask, mode);
+ mask = GS2_TX_SSC_AMP_MASK | GS2_VREG_RXTX_MAS_ISET_MASK |
+ GS2_RSVD_6_0_MASK;
+ usb3_reg_set(reg_base, COMPHY_GEN3_SET2,
+ GS2_VREG_RXTX_MAS_ISET_60U, mask);
/*
* 8. Check crystal jumper setting and program the Power and PLL Control
* accordingly Change RX wait
*/
if (get_ref_clk() == 40) {
- ref_clk = REF_CLOCK_SPEED_40M;
+ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ;
cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT;
} else {
/* 25 MHz */
- ref_clk = USB3_REF_CLOCK_SPEED_25M;
+ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ;
cfg = CFG_PM_RXDLOZ_WAIT_7_UNIT;
}
@@ -688,39 +716,37 @@ static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
REF_FREF_SEL_MASK;
data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
PU_TX_INTP_BIT | PU_DFE_BIT | PHY_MODE_USB3 | ref_clk;
- usb3_reg_set(reg_base, COMPHY_POWER_PLL_CTRL, data, mask, mode);
+ usb3_reg_set(reg_base, COMPHY_POWER_PLL_CTRL, data, mask);
mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK |
CFG_PM_RXDLOZ_WAIT_MASK;
data = CFG_PM_RXDEN_WAIT_1_UNIT | cfg;
- usb3_reg_set(reg_base, COMPHY_REG_PWR_MGM_TIM1_ADDR, data, mask, mode);
+ usb3_reg_set(reg_base, COMPHY_PWR_MGM_TIM1, data, mask);
/*
* 9. Enable idle sync
*/
- data = UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN;
- usb3_reg_set(reg_base, COMPHY_REG_UNIT_CTRL_ADDR, data, REG_16_BIT_MASK,
- mode);
+ data = IDLE_SYNC_EN_DEFAULT_VALUE | IDLE_SYNC_EN;
+ usb3_reg_set(reg_base, COMPHY_IDLE_SYNC_EN, data, REG_16_BIT_MASK);
/*
* 10. Enable the output of 500M clock
*/
- data = MISC_REG0_DEFAULT_VALUE | CLK500M_EN;
- usb3_reg_set(reg_base, COMPHY_MISC_REG0_ADDR, data, REG_16_BIT_MASK,
- mode);
+ data = MISC_CTRL0_DEFAULT_VALUE | CLK500M_EN;
+ usb3_reg_set(reg_base, COMPHY_MISC_CTRL0, data, REG_16_BIT_MASK);
/*
* 11. Set 20-bit data width
*/
- usb3_reg_set(reg_base, COMPHY_LOOPBACK_REG0, DATA_WIDTH_20BIT,
- REG_16_BIT_MASK, mode);
+ usb3_reg_set(reg_base, COMPHY_DIG_LOOPBACK_EN, DATA_WIDTH_20BIT,
+ REG_16_BIT_MASK);
/*
* 12. Override Speed_PLL value and use MAC PLL
*/
usb3_reg_set(reg_base, COMPHY_KVCO_CAL_CTRL,
(SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT),
- REG_16_BIT_MASK, mode);
+ REG_16_BIT_MASK);
/*
* 13. Check the Polarity invert bit
@@ -733,33 +759,31 @@ static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
data |= RXD_INVERT_BIT;
}
mask = TXD_INVERT_BIT | RXD_INVERT_BIT;
- usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, data, mask, mode);
+ usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN, data, mask);
/*
* 14. Set max speed generation to USB3.0 5Gbps
*/
- usb3_reg_set(reg_base, COMPHY_SYNC_MASK_GEN_REG, PHY_GEN_USB3_5G,
- PHY_GEN_MAX_MASK, mode);
+ usb3_reg_set(reg_base, COMPHY_SYNC_MASK_GEN, PHY_GEN_MAX_USB3_5G,
+ PHY_GEN_MAX_MASK);
/*
* 15. Set capacitor value for FFE gain peaking to 0xF
*/
- usb3_reg_set(reg_base, COMPHY_REG_GEN3_SETTINGS_3,
- COMPHY_GEN_FFE_CAP_SEL_VALUE, COMPHY_GEN_FFE_CAP_SEL_MASK,
- mode);
+ usb3_reg_set(reg_base, COMPHY_GEN2_SET3,
+ GS3_FFE_CAP_SEL_VALUE, GS3_FFE_CAP_SEL_MASK);
/*
* 16. Release SW reset
*/
data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4;
- usb3_reg_set(reg_base, COMPHY_REG_GLOB_PHY_CTRL0_ADDR, data,
- REG_16_BIT_MASK, mode);
+ usb3_reg_set(reg_base, COMPHY_RST_CLK_CTRL, data, REG_16_BIT_MASK);
/* Wait for > 55 us to allow PCLK be enabled */
udelay(PLL_SET_DELAY_US);
if (comphy_index == COMPHY_LANE2) {
- data = COMPHY_REG_LANE_STATUS1_ADDR + USB3PHY_LANE2_REG_BASE_OFFSET;
+ data = COMPHY_LANE_STAT1 + USB3PHY_LANE2_REG_BASE_OFFSET;
mmio_write_32(reg_base + COMPHY_LANE2_INDIR_ADDR_OFFSET,
data);
@@ -767,16 +791,18 @@ static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
ret = polling_with_timeout(addr, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
COMPHY_PLL_TIMEOUT, REG_32BIT);
} else {
- ret = polling_with_timeout(LANE_STATUS1_ADDR(USB3) + reg_base,
+ ret = polling_with_timeout(LANE_STAT1_ADDR(USB3) + reg_base,
TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
COMPHY_PLL_TIMEOUT, REG_16BIT);
}
- if (ret)
+ if (ret) {
ERROR("Failed to lock USB3 PLL\n");
+ return -ETIMEDOUT;
+ }
debug_exit();
- return ret;
+ return 0;
}
static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
@@ -789,16 +815,22 @@ static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
debug_enter();
+ /* Configure phy selector for PCIe */
+ ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+ if (ret) {
+ return ret;
+ }
+
/* 1. Enable max PLL. */
reg_set16(LANE_CFG1_ADDR(PCIE) + COMPHY_SD_ADDR,
USE_MAX_PLL_RATE_EN, USE_MAX_PLL_RATE_EN);
/* 2. Select 20 bit SERDES interface. */
- reg_set16(GLOB_CLK_SRC_LO_ADDR(PCIE) + COMPHY_SD_ADDR,
+ reg_set16(CLK_SRC_LO_ADDR(PCIE) + COMPHY_SD_ADDR,
CFG_SEL_20B, CFG_SEL_20B);
/* 3. Force to use reg setting for PCIe mode */
- reg_set16(MISC_REG1_ADDR(PCIE) + COMPHY_SD_ADDR,
+ reg_set16(MISC_CTRL1_ADDR(PCIE) + COMPHY_SD_ADDR,
SEL_BITS_PCIE_FORCE, SEL_BITS_PCIE_FORCE);
/* 4. Change RX wait */
@@ -808,12 +840,12 @@ static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
CFG_PM_RXDLOZ_WAIT_MASK));
/* 5. Enable idle sync */
- reg_set16(UNIT_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
- UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN, REG_16_BIT_MASK);
+ reg_set16(IDLE_SYNC_EN_ADDR(PCIE) + COMPHY_SD_ADDR,
+ IDLE_SYNC_EN_DEFAULT_VALUE | IDLE_SYNC_EN, REG_16_BIT_MASK);
/* 6. Enable the output of 100M/125M/500M clock */
- reg_set16(MISC_REG0_ADDR(PCIE) + COMPHY_SD_ADDR,
- MISC_REG0_DEFAULT_VALUE | CLK500M_EN | TXDCLK_2X_SEL | CLK100M_125M_EN,
+ reg_set16(MISC_CTRL0_ADDR(PCIE) + COMPHY_SD_ADDR,
+ MISC_CTRL0_DEFAULT_VALUE | CLK500M_EN | TXDCLK_2X_SEL | CLK100M_125M_EN,
REG_16_BIT_MASK);
/*
@@ -827,9 +859,9 @@ static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
*/
if (get_ref_clk() == 40)
- ref_clk = REF_CLOCK_SPEED_40M;
+ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ;
else
- ref_clk = PCIE_REF_CLOCK_SPEED_25M;
+ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ;
reg_set16(PWR_PLL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
(PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
@@ -849,25 +881,27 @@ static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
data |= RXD_INVERT_BIT;
}
mask = TXD_INVERT_BIT | RXD_INVERT_BIT;
- reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR, data, mask);
+ reg_set16(SYNC_PATTERN_ADDR(PCIE) + COMPHY_SD_ADDR, data, mask);
/* 11. Release SW reset */
- reg_set16(GLOB_PHY_CTRL0_ADDR(PCIE) + COMPHY_SD_ADDR,
- MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32,
- SOFT_RESET | MODE_REFDIV);
+ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32;
+ mask = data | SOFT_RESET | MODE_REFDIV_MASK;
+ reg_set16(RST_CLK_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR, data, mask);
/* Wait for > 55 us to allow PCLK be enabled */
udelay(PLL_SET_DELAY_US);
- ret = polling_with_timeout(LANE_STATUS1_ADDR(PCIE) + COMPHY_SD_ADDR,
+ ret = polling_with_timeout(LANE_STAT1_ADDR(PCIE) + COMPHY_SD_ADDR,
TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
COMPHY_PLL_TIMEOUT, REG_16BIT);
- if (ret)
+ if (ret) {
ERROR("Failed to lock PCIE PLL\n");
+ return -ETIMEDOUT;
+ }
debug_exit();
- return ret;
+ return 0;
}
int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode)
@@ -883,7 +917,7 @@ int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode)
comphy_mode);
break;
case(COMPHY_SGMII_MODE):
- case(COMPHY_HS_SGMII_MODE):
+ case(COMPHY_2500BASEX_MODE):
ret = mvebu_a3700_comphy_sgmii_power_on(comphy_index,
comphy_mode);
break;
@@ -919,23 +953,22 @@ static int mvebu_a3700_comphy_usb3_power_off(void)
return 0;
}
-static int mvebu_a3700_comphy_sata_power_off(uint32_t comphy_mode)
+static int mvebu_a3700_comphy_sata_power_off(void)
{
uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
- int mode = COMPHY_GET_MODE(comphy_mode);
uint32_t offset;
debug_enter();
/* Set phy isolation mode */
- offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
- comphy_set_indirect(comphy_indir_regs, offset, PHY_ISOLATE_MODE,
- PHY_ISOLATE_MODE, mode);
+ offset = COMPHY_ISOLATION_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+ comphy_sata_set_indirect(comphy_indir_regs, offset, PHY_ISOLATE_MODE,
+ PHY_ISOLATE_MODE);
/* Power off PLL, Tx, Rx */
offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
- comphy_set_indirect(comphy_indir_regs, offset, 0,
- PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT, mode);
+ comphy_sata_set_indirect(comphy_indir_regs, offset, 0,
+ PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT);
debug_exit();
@@ -960,7 +993,7 @@ int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode)
switch (mode) {
case(COMPHY_SGMII_MODE):
- case(COMPHY_HS_SGMII_MODE):
+ case(COMPHY_2500BASEX_MODE):
err = mvebu_a3700_comphy_sgmii_power_off(comphy_index);
break;
case (COMPHY_USB3_MODE):
@@ -968,7 +1001,7 @@ int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode)
err = mvebu_a3700_comphy_usb3_power_off();
break;
case (COMPHY_SATA_MODE):
- err = mvebu_a3700_comphy_sata_power_off(comphy_mode);
+ err = mvebu_a3700_comphy_sata_power_off();
break;
default:
@@ -992,7 +1025,7 @@ static int mvebu_a3700_comphy_sata_is_pll_locked(void)
/* Polling status */
mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET,
- COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET);
+ COMPHY_DIG_LOOPBACK_EN + SATAPHY_LANE2_REG_BASE_OFFSET);
addr = comphy_indir_regs + COMPHY_LANE2_INDIR_DATA_OFFSET;
data = polling_with_timeout(addr, PLL_READY_TX_BIT, PLL_READY_TX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
diff --git a/drivers/marvell/comphy/phy-comphy-3700.h b/drivers/marvell/comphy/phy-comphy-3700.h
index 94056f18d7..ed07624822 100644
--- a/drivers/marvell/comphy/phy-comphy-3700.h
+++ b/drivers/marvell/comphy/phy-comphy-3700.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018-2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
@@ -13,11 +13,11 @@
#define REG_16_BIT_MASK 0xFFFF
#define COMPHY_SELECTOR_PHY_REG 0xFC
-/* bit0: 0: Lane0 is GBE0; 1: Lane1 is PCIE */
+/* bit0: 0: Lane1 is GbE0; 1: Lane1 is PCIE */
#define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT BIT(0)
-/* bit4: 0: Lane1 is GBE1; 1: Lane1 is USB3 */
+/* bit4: 0: Lane0 is GbE1; 1: Lane0 is USB3 */
#define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT BIT(4)
-/* bit8: 0: Lane1 is USB, Lane2 is SATA; 1: Lane2 is USB3 */
+/* bit8: 0: Lane0 is USB3 instead of GbE1, Lane2 is SATA; 1: Lane2 is USB3 */
#define COMPHY_SELECTOR_USB3_PHY_SEL_BIT BIT(8)
/* SATA PHY register offset */
@@ -53,12 +53,11 @@ enum {
#define PLL_LOCK_BIT BIT(8)
#define REF_FREF_SEL_OFFSET 0
#define REF_FREF_SEL_MASK (0x1F << REF_FREF_SEL_OFFSET)
-#define REF_CLOCK_SPEED_25M (0x1 << REF_FREF_SEL_OFFSET)
-#define REF_CLOCK_SPEED_30M (0x2 << REF_FREF_SEL_OFFSET)
-#define PCIE_REF_CLOCK_SPEED_25M REF_CLOCK_SPEED_30M
-#define USB3_REF_CLOCK_SPEED_25M REF_CLOCK_SPEED_30M
-#define REF_CLOCK_SPEED_40M (0x3 << REF_FREF_SEL_OFFSET)
-#define REF_CLOCK_SPEED_50M (0x4 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_SERDES_25MHZ (0x1 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_SERDES_40MHZ (0x3 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_SERDES_50MHZ (0x4 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_PCIE_USB3_25MHZ (0x2 << REF_FREF_SEL_OFFSET)
+#define REF_FREF_SEL_PCIE_USB3_40MHZ (0x3 << REF_FREF_SEL_OFFSET)
#define PHY_MODE_OFFSET 5
#define PHY_MODE_MASK (7 << PHY_MODE_OFFSET)
#define PHY_MODE_SATA (0x0 << PHY_MODE_OFFSET)
@@ -73,11 +72,9 @@ enum {
#define SPEED_PLL_MASK (0x3F << SPEED_PLL_OFFSET)
#define SPEED_PLL_VALUE_16 (0x10 << SPEED_PLL_OFFSET)
-#define COMPHY_RESERVED_REG 0x0E
-#define PHYCTRL_FRM_PIN_BIT BIT(13)
-
-#define COMPHY_LOOPBACK_REG0 0x23
-#define DIG_LB_EN_ADDR(unit) (COMPHY_LOOPBACK_REG0 * PHY_SHFT(unit))
+#define COMPHY_DIG_LOOPBACK_EN 0x23
+#define DIG_LOOPBACK_EN_ADDR(unit) (COMPHY_DIG_LOOPBACK_EN * \
+ PHY_SHFT(unit))
#define SEL_DATA_WIDTH_OFFSET 10
#define SEL_DATA_WIDTH_MASK (0x3 << SEL_DATA_WIDTH_OFFSET)
#define DATA_WIDTH_10BIT (0x0 << SEL_DATA_WIDTH_OFFSET)
@@ -85,80 +82,71 @@ enum {
#define DATA_WIDTH_40BIT (0x2 << SEL_DATA_WIDTH_OFFSET)
#define PLL_READY_TX_BIT BIT(4)
-#define COMPHY_SYNC_PATTERN_REG 0x24
-#define SYNC_PATTERN_REG_ADDR(unit) (COMPHY_SYNC_PATTERN_REG * \
- PHY_SHFT(unit))
+#define COMPHY_SYNC_PATTERN 0x24
+#define SYNC_PATTERN_ADDR(unit) (COMPHY_SYNC_PATTERN * PHY_SHFT(unit))
#define TXD_INVERT_BIT BIT(10)
#define RXD_INVERT_BIT BIT(11)
-#define COMPHY_SYNC_MASK_GEN_REG 0x25
+#define COMPHY_SYNC_MASK_GEN 0x25
#define PHY_GEN_MAX_OFFSET 10
#define PHY_GEN_MAX_MASK (3 << PHY_GEN_MAX_OFFSET)
-#define PHY_GEN_USB3_5G (1 << PHY_GEN_MAX_OFFSET)
+#define PHY_GEN_MAX_USB3_5G (1 << PHY_GEN_MAX_OFFSET)
-#define COMPHY_ISOLATION_CTRL_REG 0x26
-#define ISOLATION_CTRL_REG_ADDR(unit) (COMPHY_ISOLATION_CTRL_REG * \
- PHY_SHFT(unit))
+#define COMPHY_ISOLATION_CTRL 0x26
+#define ISOLATION_CTRL_ADDR(unit) (COMPHY_ISOLATION_REG * PHY_SHFT(unit))
#define PHY_ISOLATE_MODE BIT(15)
-#define COMPHY_MISC_REG0_ADDR 0x4F
-#define MISC_REG0_ADDR(unit) (COMPHY_MISC_REG0_ADDR * PHY_SHFT(unit))
+#define COMPHY_GEN2_SET2 0x3e
+#define GEN2_SET2_ADDR(unit) (COMPHY_GEN2_SET2 * PHY_SHFT(unit))
+#define GS2_TX_SSC_AMP_VALUE_20 BIT(14)
+#define GS2_TX_SSC_AMP_OFF 9
+#define GS2_TX_SSC_AMP_LEN 7
+#define GS2_TX_SSC_AMP_MASK (((1 << GS2_TX_SSC_AMP_LEN) - 1) << \
+ GS2_TX_SSC_AMP_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_OFF 7
+#define GS2_VREG_RXTX_MAS_ISET_60U (0 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_80U (1 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_100U (2 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_120U (3 << GS2_VREG_RXTX_MAS_ISET_OFF)
+#define GS2_VREG_RXTX_MAS_ISET_MASK (BIT(7) | BIT(8))
+#define GS2_RSVD_6_0_OFF 0
+#define GS2_RSVD_6_0_LEN 7
+#define GS2_RSVD_6_0_MASK (((1 << GS2_RSVD_6_0_LEN) - 1) << \
+ GS2_RSVD_6_0_OFF)
+
+#define COMPHY_GEN3_SET2 0x3f
+#define GEN3_SET2_ADDR(unit) (COMPHY_GEN3_SET2 * PHY_SHFT(unit))
+
+#define COMPHY_IDLE_SYNC_EN 0x48
+#define IDLE_SYNC_EN_ADDR(unit) (COMPHY_IDLE_SYNC_EN * PHY_SHFT(unit))
+#define IDLE_SYNC_EN BIT(12)
+#define IDLE_SYNC_EN_DEFAULT_VALUE 0x60
+
+#define COMPHY_MISC_CTRL0 0x4F
+#define MISC_CTRL0_ADDR(unit) (COMPHY_MISC_CTRL0 * PHY_SHFT(unit))
#define CLK100M_125M_EN BIT(4)
#define TXDCLK_2X_SEL BIT(6)
#define CLK500M_EN BIT(7)
#define PHY_REF_CLK_SEL BIT(10)
-#define MISC_REG0_DEFAULT_VALUE 0xA00D
-
-#define COMPHY_REG_GEN2_SET_2 0x3e
-#define GEN2_SETTING_2_ADDR(unit) (COMPHY_REG_GEN2_SET_2 * PHY_SHFT(unit))
-#define G2_TX_SSC_AMP_VALUE_20 BIT(14)
-#define G2_TX_SSC_AMP_OFF 9
-#define G2_TX_SSC_AMP_LEN 7
-#define G2_TX_SSC_AMP_MASK (((1 << G2_TX_SSC_AMP_LEN) - 1) << \
- G2_TX_SSC_AMP_OFF)
-
-#define COMPHY_REG_GEN2_SET_3 0x3f
-#define GEN2_SETTING_3_ADDR(unit) (COMPHY_REG_GEN2_SET_3 * PHY_SHFT(unit))
-#define G3_TX_SSC_AMP_OFF 9
-#define G3_TX_SSC_AMP_LEN 7
-#define G3_TX_SSC_AMP_MASK (((1 << G2_TX_SSC_AMP_LEN) - 1) << \
- G2_TX_SSC_AMP_OFF)
-#define G3_VREG_RXTX_MAS_ISET_OFF 7
-#define G3_VREG_RXTX_MAS_ISET_60U (0 << G3_VREG_RXTX_MAS_ISET_OFF)
-#define G3_VREG_RXTX_MAS_ISET_80U (1 << G3_VREG_RXTX_MAS_ISET_OFF)
-#define G3_VREG_RXTX_MAS_ISET_100U (2 << G3_VREG_RXTX_MAS_ISET_OFF)
-#define G3_VREG_RXTX_MAS_ISET_120U (3 << G3_VREG_RXTX_MAS_ISET_OFF)
-#define G3_VREG_RXTX_MAS_ISET_MASK (BIT(7) | BIT(8))
-#define RSVD_PH03FH_6_0_OFF 0
-#define RSVD_PH03FH_6_0_LEN 7
-#define RSVD_PH03FH_6_0_MASK (((1 << RSVD_PH03FH_6_0_LEN) - 1) << \
- RSVD_PH03FH_6_0_OFF)
-
-#define COMPHY_REG_UNIT_CTRL_ADDR 0x48
-#define UNIT_CTRL_ADDR(unit) (COMPHY_REG_UNIT_CTRL_ADDR * \
- PHY_SHFT(unit))
-#define IDLE_SYNC_EN BIT(12)
-#define UNIT_CTRL_DEFAULT_VALUE 0x60
+#define MISC_CTRL0_DEFAULT_VALUE 0xA00D
-#define COMPHY_MISC_REG1_ADDR 0x73
-#define MISC_REG1_ADDR(unit) (COMPHY_MISC_REG1_ADDR * PHY_SHFT(unit))
+#define COMPHY_MISC_CTRL1 0x73
+#define MISC_CTRL1_ADDR(unit) (COMPHY_MISC_CTRL1 * PHY_SHFT(unit))
#define SEL_BITS_PCIE_FORCE BIT(15)
-#define COMPHY_REG_GEN3_SETTINGS_3 0x112
-#define COMPHY_GEN_FFE_CAP_SEL_MASK 0xF
-#define COMPHY_GEN_FFE_CAP_SEL_VALUE 0xF
+#define COMPHY_GEN2_SET3 0x112
+#define GS3_FFE_CAP_SEL_MASK 0xF
+#define GS3_FFE_CAP_SEL_VALUE 0xF
-#define COMPHY_REG_LANE_CFG0_ADDR 0x180
-#define LANE_CFG0_ADDR(unit) (COMPHY_REG_LANE_CFG0_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_LANE_CFG0 0x180
+#define LANE_CFG0_ADDR(unit) (COMPHY_LANE_CFG0 * PHY_SHFT(unit))
#define PRD_TXDEEMPH0_MASK BIT(0)
#define PRD_TXMARGIN_MASK (BIT(1) | BIT(2) | BIT(3))
#define PRD_TXSWING_MASK BIT(4)
#define CFG_TX_ALIGN_POS_MASK (BIT(5) | BIT(6) | BIT(7) | BIT(8))
-#define COMPHY_REG_LANE_CFG1_ADDR 0x181
-#define LANE_CFG1_ADDR(unit) (COMPHY_REG_LANE_CFG1_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_LANE_CFG1 0x181
+#define LANE_CFG1_ADDR(unit) (COMPHY_LANE_CFG1 * PHY_SHFT(unit))
#define PRD_TXDEEMPH1_MASK BIT(15)
#define USE_MAX_PLL_RATE_EN BIT(9)
#define TX_DET_RX_MODE BIT(6)
@@ -166,21 +154,17 @@ enum {
#define GEN2_TX_DATA_DLY_DEFT (2 << 3)
#define TX_ELEC_IDLE_MODE_EN BIT(0)
-#define COMPHY_REG_LANE_STATUS1_ADDR 0x183
-#define LANE_STATUS1_ADDR(unit) (COMPHY_REG_LANE_STATUS1_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_LANE_STAT1 0x183
+#define LANE_STAT1_ADDR(unit) (COMPHY_LANE_STAT1 * PHY_SHFT(unit))
#define TXDCLK_PCLK_EN BIT(0)
-#define COMPHY_REG_LANE_CFG4_ADDR 0x188
-#define LANE_CFG4_ADDR(unit) (COMPHY_REG_LANE_CFG4_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_LANE_CFG4 0x188
+#define LANE_CFG4_ADDR(unit) (COMPHY_LANE_CFG4 * PHY_SHFT(unit))
#define SPREAD_SPECTRUM_CLK_EN BIT(7)
-#define COMPHY_REG_GLOB_PHY_CTRL0_ADDR 0x1C1
-#define GLOB_PHY_CTRL0_ADDR(unit) (COMPHY_REG_GLOB_PHY_CTRL0_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_RST_CLK_CTRL 0x1C1
+#define RST_CLK_CTRL_ADDR(unit) (COMPHY_RST_CLK_CTRL * PHY_SHFT(unit))
#define SOFT_RESET BIT(0)
-#define MODE_REFDIV 0x30
#define MODE_CORE_CLK_FREQ_SEL BIT(9)
#define MODE_PIPE_WIDTH_32 BIT(3)
#define MODE_REFDIV_OFFSET 4
@@ -188,24 +172,21 @@ enum {
#define MODE_REFDIV_MASK (0x3 << MODE_REFDIV_OFFSET)
#define MODE_REFDIV_BY_4 (0x2 << MODE_REFDIV_OFFSET)
-#define COMPHY_REG_TEST_MODE_CTRL_ADDR 0x1C2
-#define TEST_MODE_CTRL_ADDR(unit) (COMPHY_REG_TEST_MODE_CTRL_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_TEST_MODE_CTRL 0x1C2
+#define TEST_MODE_CTRL_ADDR(unit) (COMPHY_TEST_MODE_CTRL * PHY_SHFT(unit))
#define MODE_MARGIN_OVERRIDE BIT(2)
-#define COMPHY_REG_GLOB_CLK_SRC_LO_ADDR 0x1C3
-#define GLOB_CLK_SRC_LO_ADDR(unit) (COMPHY_REG_GLOB_CLK_SRC_LO_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_CLK_SRC_LO 0x1C3
+#define CLK_SRC_LO_ADDR(unit) (COMPHY_CLK_SRC_LO * PHY_SHFT(unit))
#define MODE_CLK_SRC BIT(0)
#define BUNDLE_PERIOD_SEL BIT(1)
-#define BUNDLE_PERIOD_SCALE (BIT(2) | BIT(3))
+#define BUNDLE_PERIOD_SCALE_MASK (BIT(2) | BIT(3))
#define BUNDLE_SAMPLE_CTRL BIT(4)
-#define PLL_READY_DLY (BIT(5) | BIT(6) | BIT(7))
+#define PLL_READY_DLY_MASK (BIT(5) | BIT(6) | BIT(7))
#define CFG_SEL_20B BIT(15)
-#define COMPHY_REG_PWR_MGM_TIM1_ADDR 0x1D0
-#define PWR_MGM_TIM1_ADDR(unit) (COMPHY_REG_PWR_MGM_TIM1_ADDR * \
- PHY_SHFT(unit))
+#define COMPHY_PWR_MGM_TIM1 0x1D0
+#define PWR_MGM_TIM1_ADDR(unit) (COMPHY_PWR_MGM_TIM1 * PHY_SHFT(unit))
#define CFG_PM_OSCCLK_WAIT_OFF 12
#define CFG_PM_OSCCLK_WAIT_LEN 4
#define CFG_PM_OSCCLK_WAIT_MASK (((1 << CFG_PM_OSCCLK_WAIT_LEN) - 1) \
@@ -222,9 +203,18 @@ enum {
#define CFG_PM_RXDLOZ_WAIT_7_UNIT (7 << CFG_PM_RXDLOZ_WAIT_OFF)
#define CFG_PM_RXDLOZ_WAIT_12_UNIT (0xC << CFG_PM_RXDLOZ_WAIT_OFF)
+/*
+ * This register is not from PHY lane register space. It only exists in the
+ * indirect register space, before the actual PHY lane 2 registers. So the
+ * offset is absolute, not relative to SATAPHY_LANE2_REG_BASE_OFFSET.
+ * It is used only for SATA PHY initialization.
+ */
+#define COMPHY_RESERVED_REG 0x0E
+#define PHYCTRL_FRM_PIN_BIT BIT(13)
+
/* SGMII */
#define COMPHY_PHY_CFG1_OFFSET(lane) ((1 - (lane)) * 0x28)
-#define PIN_PU_IVEREF_BIT BIT(1)
+#define PIN_PU_IVREF_BIT BIT(1)
#define PIN_RESET_CORE_BIT BIT(11)
#define PIN_RESET_COMPHY_BIT BIT(12)
#define PIN_PU_PLL_BIT BIT(16)
@@ -237,11 +227,11 @@ enum {
#define GEN_TX_SEL_MASK (0xF << GEN_TX_SEL_OFFSET)
#define PHY_RX_INIT_BIT BIT(30)
#define SD_SPEED_1_25_G 0x6
-#define SD_SPEED_2_5_G 0x8
+#define SD_SPEED_3_125_G 0x8
/* COMPHY status reg:
- * lane0: PCIe/GbE0 PHY Status 1
- * lane1: USB3/GbE1 PHY Status 1
+ * lane0: USB3/GbE1 PHY Status 1
+ * lane1: PCIe/GbE0 PHY Status 1
*/
#define COMPHY_PHY_STATUS_OFFSET(lane) (0x18 + (1 - (lane)) * 0x28)
#define PHY_RX_INIT_DONE_BIT BIT(0)
diff --git a/drivers/marvell/comphy/phy-comphy-common.h b/drivers/marvell/comphy/phy-comphy-common.h
index e3b430a914..ba5d255e88 100644
--- a/drivers/marvell/comphy/phy-comphy-common.h
+++ b/drivers/marvell/comphy/phy-comphy-common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018-2021 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
@@ -87,7 +87,7 @@
#define COMPHY_SATA_MODE 0x1
#define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */
-#define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */
+#define COMPHY_2500BASEX_MODE 0x3 /* 2500Base-X */
#define COMPHY_USB3H_MODE 0x4
#define COMPHY_USB3D_MODE 0x5
#define COMPHY_PCIE_MODE 0x6
@@ -147,7 +147,7 @@ static inline void reg_set(uintptr_t addr, uint32_t data, uint32_t mask)
debug("<atf>: WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ",
addr, data, mask);
debug("old value = 0x%x ==> ", mmio_read_32(addr));
- mmio_clrsetbits_32(addr, mask, data);
+ mmio_clrsetbits_32(addr, mask, data & mask);
debug("new val 0x%x\n", mmio_read_32(addr));
}
@@ -159,7 +159,7 @@ static inline void __unused reg_set16(uintptr_t addr, uint16_t data,
debug("<atf>: WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ",
addr, data, mask);
debug("old value = 0x%x ==> ", mmio_read_16(addr));
- mmio_clrsetbits_16(addr, mask, data);
+ mmio_clrsetbits_16(addr, mask, data & mask);
debug("new val 0x%x\n", mmio_read_16(addr));
}
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.c b/drivers/marvell/comphy/phy-comphy-cp110.c
index 86f4c77c5e..e256fa7f4e 100644
--- a/drivers/marvell/comphy/phy-comphy-cp110.c
+++ b/drivers/marvell/comphy/phy-comphy-cp110.c
@@ -8,6 +8,8 @@
/* Marvell CP110 SoC COMPHY unit driver */
#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
@@ -30,7 +32,7 @@
/* COMPHY speed macro */
#define COMPHY_SPEED_1_25G 0 /* SGMII 1G */
#define COMPHY_SPEED_2_5G 1
-#define COMPHY_SPEED_3_125G 2 /* SGMII 2.5G */
+#define COMPHY_SPEED_3_125G 2 /* 2500Base-X */
#define COMPHY_SPEED_5G 3
#define COMPHY_SPEED_5_15625G 4 /* XFI 5G */
#define COMPHY_SPEED_6G 5
@@ -102,7 +104,7 @@ static void mvebu_cp110_get_ap_and_cp_nr(uint8_t *ap_nr, uint8_t *cp_nr,
*cp_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(*ap_nr)) /
MVEBU_CP_OFFSET);
- debug("cp_base 0x%llx, ap_io_base 0x%lx, cp_offset 0x%lx\n",
+ debug("cp_base 0x%" PRIx64 ", ap_io_base 0x%lx, cp_offset 0x%lx\n",
comphy_base, (unsigned long)MVEBU_AP_IO_BASE(*ap_nr),
(unsigned long)MVEBU_CP_OFFSET);
}
@@ -191,7 +193,7 @@ static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base,
case(3):
/* For comphy 3:
* 0x1 = RXAUI_Lane1
- * 0x2 = SGMII/HS-SGMII Port1
+ * 0x2 = SGMII/Base-X Port1
*/
if (mode == COMPHY_RXAUI_MODE)
reg |= COMMON_SELECTOR_COMPHY3_RXAUI <<
@@ -202,20 +204,20 @@ static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base,
break;
case(4):
/* For comphy 4:
- * 0x1 = SGMII/HS-SGMII Port1, XFI1/SFI1
- * 0x2 = SGMII/HS-SGMII Port0: XFI0/SFI0, RXAUI_Lane0
+ * 0x1 = SGMII/Base-X Port1, XFI1/SFI1
+ * 0x2 = SGMII/Base-X Port0: XFI0/SFI0, RXAUI_Lane0
*
- * We want to check if SGMII1/HS_SGMII1 is the
+ * We want to check if SGMII1 is the
* requested mode in order to determine which value
* should be set (all other modes use the same value)
* so we need to strip the mode, and check the ID
- * because we might handle SGMII0/HS_SGMII0 too.
+ * because we might handle SGMII0 too.
*/
/* TODO: need to distinguish between CP110 and CP115
* as SFI1/XFI1 available only for CP115.
*/
if ((mode == COMPHY_SGMII_MODE ||
- mode == COMPHY_HS_SGMII_MODE ||
+ mode == COMPHY_2500BASEX_MODE ||
mode == COMPHY_SFI_MODE ||
mode == COMPHY_XFI_MODE ||
mode == COMPHY_AP_MODE)
@@ -228,7 +230,7 @@ static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base,
break;
case(5):
/* For comphy 5:
- * 0x1 = SGMII/HS-SGMII Port2
+ * 0x1 = SGMII/Base-X Port2
* 0x2 = RXAUI Lane1
*/
if (mode == COMPHY_RXAUI_MODE)
@@ -713,7 +715,7 @@ static int mvebu_cp110_comphy_sgmii_power_on(uint64_t comphy_base,
data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
} else if (sgmii_speed == COMPHY_SPEED_3_125G) {
- /* HS SGMII (2.5G), SerDes speed 3.125G */
+ /* 2500Base-X, SerDes speed 3.125G */
data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
} else {
@@ -1730,11 +1732,13 @@ static int mvebu_cp110_comphy_pcie_power_on(uint64_t comphy_base,
HPIPE_LANE_STATUS1_REG;
data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
mask = data;
- ret = polling_with_timeout(addr, data, mask,
+ data = polling_with_timeout(addr, data, mask,
PLL_LOCK_TIMEOUT,
REG_32BIT);
- if (ret)
+ if (data) {
ERROR("Failed to lock PCIE PLL\n");
+ ret = -ETIMEDOUT;
+ }
}
}
@@ -2049,7 +2053,7 @@ static int mvebu_cp110_comphy_usb3_power_on(uint64_t comphy_base,
mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK;
data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET;
reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
- /* Confifure SSC amplitude */
+ /* Configure SSC amplitude */
mask = HPIPE_G2_TX_SSC_AMP_MASK;
data = 0x1f << HPIPE_G2_TX_SSC_AMP_OFFSET;
reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
@@ -2343,7 +2347,7 @@ int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base,
switch (mode) {
case (COMPHY_SGMII_MODE):
- case (COMPHY_HS_SGMII_MODE):
+ case (COMPHY_2500BASEX_MODE):
case (COMPHY_XFI_MODE):
case (COMPHY_SFI_MODE):
case (COMPHY_RXAUI_MODE):
@@ -2378,7 +2382,7 @@ int mvebu_cp110_comphy_power_on(uint64_t comphy_base,
comphy_mode);
break;
case(COMPHY_SGMII_MODE):
- case(COMPHY_HS_SGMII_MODE):
+ case(COMPHY_2500BASEX_MODE):
err = mvebu_cp110_comphy_sgmii_power_on(comphy_base,
comphy_index,
comphy_mode);
diff --git a/drivers/marvell/gwin.c b/drivers/marvell/gwin.c
index 9d94308365..40f8c93109 100644
--- a/drivers/marvell/gwin.c
+++ b/drivers/marvell/gwin.c
@@ -7,6 +7,9 @@
/* GWIN unit device driver for Marvell AP810 SoC */
+#include <inttypes.h>
+#include <stdint.h>
+
#include <common/debug.h>
#include <drivers/marvell/gwin.h>
#include <lib/mmio.h>
@@ -49,14 +52,14 @@ static void gwin_check(struct addr_map_win *win)
/* The base is always 64M aligned */
if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) {
win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1);
- NOTICE("%s: Align the base address to 0x%llx\n",
+ NOTICE("%s: Align the base address to 0x%" PRIx64 "\n",
__func__, win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) {
win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M);
- NOTICE("%s: Aligning window size to 0x%llx\n",
+ NOTICE("%s: Aligning window size to 0x%" PRIx64 "\n",
__func__, win->win_size);
}
}
@@ -167,7 +170,7 @@ static void dump_gwin(int ap_index)
alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num));
ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
- printf("\tgwin %d 0x%016llx 0x%016llx\n",
+ printf("\tgwin %d 0x%016" PRIx64 " 0x%016" PRIx64 "\n",
(cr >> 8) & 0xF, alr, ahr);
}
}
@@ -210,7 +213,7 @@ int init_gwin(int ap_index)
* remote AP should be accompanied with proper configuration to
* GWIN registers group and therefore the GWIN Miss feature
* should be set into Bypass mode, need to make sure all GWIN regions
- * are defined correctly that will assure no GWIN miss occurrance
+ * are defined correctly that will assure no GWIN miss occurrence
* JIRA-AURORA2-1630
*/
INFO("Update GWIN miss bypass\n");
diff --git a/drivers/marvell/io_win.c b/drivers/marvell/io_win.c
index c4257fa7c1..124382ad93 100644
--- a/drivers/marvell/io_win.c
+++ b/drivers/marvell/io_win.c
@@ -7,6 +7,9 @@
/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+#include <inttypes.h>
+#include <stdint.h>
+
#include <common/debug.h>
#include <drivers/marvell/io_win.h>
#include <lib/mmio.h>
@@ -44,14 +47,14 @@ static void io_win_check(struct addr_map_win *win)
/* check if address is aligned to 1M */
if (IS_NOT_ALIGN(win->base_addr, IO_WIN_ALIGNMENT_1M)) {
win->base_addr = ALIGN_UP(win->base_addr, IO_WIN_ALIGNMENT_1M);
- NOTICE("%s: Align up the base address to 0x%llx\n",
+ NOTICE("%s: Align up the base address to 0x%" PRIx64 "\n",
__func__, win->base_addr);
}
/* size parameter validity check */
if (IS_NOT_ALIGN(win->win_size, IO_WIN_ALIGNMENT_1M)) {
win->win_size = ALIGN_UP(win->win_size, IO_WIN_ALIGNMENT_1M);
- NOTICE("%s: Aligning size to 0x%llx\n",
+ NOTICE("%s: Aligning size to 0x%" PRIx64 "\n",
__func__, win->win_size);
}
}
@@ -170,7 +173,7 @@ static void dump_io_win(int ap_index)
win_id));
start = ((uint64_t)alr << ADDRESS_SHIFT);
end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
- printf("\tio-win %d 0x%016llx 0x%016llx\n",
+ printf("\tio-win %d 0x%016" PRIx64 " 0x%016" PRIx64 "\n",
trgt_id, start, end);
}
}
diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c
index 29088aa92f..1f3939560d 100644
--- a/drivers/marvell/iob.c
+++ b/drivers/marvell/iob.c
@@ -7,6 +7,9 @@
/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
+#include <inttypes.h>
+#include <stdint.h>
+
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/marvell/iob.h>
@@ -57,7 +60,7 @@ static void iob_win_check(struct addr_map_win *win, uint32_t win_num)
win->base_addr = ALIGN_UP(win->base_addr, IOB_WIN_ALIGNMENT);
ERROR("Window %d: base address unaligned to 0x%x\n",
win_num, IOB_WIN_ALIGNMENT);
- printf("Align up the base address to 0x%llx\n",
+ printf("Align up the base address to 0x%" PRIx64 "\n",
win->base_addr);
}
@@ -66,7 +69,7 @@ static void iob_win_check(struct addr_map_win *win, uint32_t win_num)
win->win_size = ALIGN_UP(win->win_size, IOB_WIN_ALIGNMENT);
ERROR("Window %d: window size unaligned to 0x%x\n", win_num,
IOB_WIN_ALIGNMENT);
- printf("Aligning size to 0x%llx\n", win->win_size);
+ printf("Aligning size to 0x%" PRIx64 "\n", win->win_size);
}
}
@@ -130,7 +133,7 @@ static void dump_iob(void)
*/
end = start + (16 << 20);
}
- printf("iob %02d %s 0x%016llx 0x%016llx\n",
+ printf("iob %02d %s 0x%016" PRIx64 " 0x%016" PRIx64 "\n",
win_id, iob_target_name[target_id],
start, end);
}
diff --git a/drivers/marvell/mc_trustzone/mc_trustzone.c b/drivers/marvell/mc_trustzone/mc_trustzone.c
index 52b3006769..648bd0e984 100644
--- a/drivers/marvell/mc_trustzone/mc_trustzone.c
+++ b/drivers/marvell/mc_trustzone/mc_trustzone.c
@@ -5,6 +5,9 @@
* https://spdx.org/licenses
*/
+#include <inttypes.h>
+#include <stdint.h>
+
#include <common/debug.h>
#include <drivers/marvell/addr_map.h>
#include <lib/mmio.h>
@@ -39,7 +42,7 @@ void tz_enable_win(int ap_index, const struct addr_map_win *win, int win_id)
/* map the window size to trustzone register convention */
tz_size = fls(TZ_SIZE(win->win_size));
- VERBOSE("%s: window size = 0x%llx maps to tz_size %d\n",
+ VERBOSE("%s: window size = 0x%" PRIx64 " maps to tz_size %d\n",
__func__, win->win_size, tz_size);
if (tz_size < 0 || tz_size > 31) {
ERROR("Using not allowed size for MC TrustZone window %d!\n",
@@ -49,7 +52,7 @@ void tz_enable_win(int ap_index, const struct addr_map_win *win, int win_id)
if (base & 0xfff) {
base = base & ~0xfff;
- WARN("Attempt to open MC TZ win. at 0x%llx, truncate to 0x%x\n",
+ WARN("Attempt to open MC TZ win. at 0x%" PRIx64 ", truncate to 0x%x\n",
win->base_addr, base);
}
diff --git a/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c b/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c
index 98e1896872..9352437771 100644
--- a/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c
+++ b/drivers/marvell/mg_conf_cm3/mg_conf_cm3.c
@@ -55,7 +55,7 @@ int mg_image_load(uintptr_t src_addr, uint32_t size, int cp_index)
/* Don't release MG CM3 from reset - it will be done by next step
* bootloader (e.g. U-Boot), when appriopriate device-tree setup (which
- * has enabeld 802.3. auto-neg) will be choosen.
+ * has enabeld 802.3. auto-neg) will be chosen.
*/
return 0;
diff --git a/drivers/marvell/uart/a3700_console.S b/drivers/marvell/uart/a3700_console.S
index 218fd861ce..a1eacbc438 100644
--- a/drivers/marvell/uart/a3700_console.S
+++ b/drivers/marvell/uart/a3700_console.S
@@ -34,7 +34,7 @@
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success
- * Clobber list : x1, x2, x3
+ * Clobber list : x1, x2, x3, x4
* -----------------------------------------------
*/
func console_a3700_core_init
@@ -44,24 +44,11 @@ func console_a3700_core_init
cbz w1, init_fail
cbz w2, init_fail
- /* Program the baudrate */
- /* Divisor = Round(Uartclock / (16 * baudrate)) */
- lsl w2, w2, #4
- add w1, w1, w2, lsr #1
- udiv w2, w1, w2
- and w2, w2, #0x3ff /* clear all other bits to use default clock */
-
- str w2, [x0, #UART_BAUD_REG]/* set baud rate divisor */
-
- /* Set UART to default 16X scheme */
- mov w3, #0
- str w3, [x0, #UART_POSSR_REG]
-
/*
* Wait for the TX (THR and TSR) to be empty. If wait for 3ms, the TX FIFO is
* still not empty, TX FIFO will reset by all means.
*/
- mov w1, #30 /* max time out 30 * 100 us */
+ mov w4, #30 /* max time out 30 * 100 us */
2:
/* Check whether TX (THR and TSR) is empty */
ldr w3, [x0, #UART_STATUS_REG]
@@ -70,30 +57,51 @@ func console_a3700_core_init
b.ne 4f
/* Delay */
- mov w2, #60000 /* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */
+ mov w3, #60000 /* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */
3:
- sub w2, w2, #1
- cmp w2, #0
+ sub w3, w3, #1
+ cmp w3, #0
b.ne 3b
/* Check whether wait timeout expired */
- sub w1, w1, #1
- cmp w1, #0
+ sub w4, w4, #1
+ cmp w4, #0
b.ne 2b
4:
+ /* Reset UART via North Bridge Peripheral */
+ mov_imm x4, MVEBU_NB_RESET_REG
+ ldr w3, [x4]
+ bic w3, w3, #MVEBU_NB_RESET_UART_N
+ str w3, [x4]
+ orr w3, w3, #MVEBU_NB_RESET_UART_N
+ str w3, [x4]
+
/* Reset FIFO */
mov w3, #UART_CTRL_RXFIFO_RESET
orr w3, w3, #UART_CTRL_TXFIFO_RESET
str w3, [x0, #UART_CTRL_REG]
/* Delay */
- mov w2, #2000
+ mov w3, #2000
1:
- sub w2, w2, #1
- cmp w2, #0
+ sub w3, w3, #1
+ cmp w3, #0
b.ne 1b
+ /* Program the baudrate */
+ /* Divisor = Round(Uartclock / (16 * baudrate)) */
+ lsl w2, w2, #4
+ add w1, w1, w2, lsr #1
+ udiv w2, w1, w2
+ and w2, w2, #0x3ff /* clear all other bits to use default clock */
+
+ str w2, [x0, #UART_BAUD_REG]/* set baud rate divisor */
+
+ /* Set UART to default 16X scheme */
+ mov w3, #0
+ str w3, [x0, #UART_POSSR_REG]
+
/* No Parity, 1 Stop */
mov w3, #0
str w3, [x0, #UART_CTRL_REG]
@@ -118,7 +126,7 @@ endfunc console_a3700_core_init
* w2 - Baud rate
* x3 - pointer to empty console_t struct
* Out: return 1 on success, 0 on error
- * Clobber list : x0, x1, x2, x6, x7, x14
+ * Clobber list : x0, x1, x2, x3, x4, x6, x7, x14
* -----------------------------------------------
*/
func console_a3700_register
@@ -132,7 +140,7 @@ func console_a3700_register
mov x0, x6
mov x30, x7
- finish_console_register a3700, putc=1, getc=1, flush=1
+ finish_console_register a3700, putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
ret x7
diff --git a/drivers/measured_boot/event_log.c b/drivers/measured_boot/event_log.c
deleted file mode 100644
index 727bdf5f37..0000000000
--- a/drivers/measured_boot/event_log.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <arch_helpers.h>
-
-#include <common/bl_common.h>
-#include <common/debug.h>
-#include <drivers/auth/crypto_mod.h>
-#include <drivers/measured_boot/event_log.h>
-#include <mbedtls/md.h>
-
-#include <plat/common/platform.h>
-
-/* Event Log data */
-static uint8_t event_log[EVENT_LOG_SIZE];
-
-/* End of Event Log */
-#define EVENT_LOG_END ((uintptr_t)event_log + sizeof(event_log) - 1U)
-
-CASSERT(sizeof(event_log) >= LOG_MIN_SIZE, assert_event_log_size);
-
-/* Pointer in event_log[] */
-static uint8_t *log_ptr = event_log;
-
-/* Pointer to measured_boot_data_t */
-const static measured_boot_data_t *plat_data_ptr;
-
-static uintptr_t tos_fw_config_base;
-static uintptr_t nt_fw_config_base;
-
-/* TCG_EfiSpecIdEvent */
-static const id_event_headers_t id_event_header = {
- .header = {
- .pcr_index = PCR_0,
- .event_type = EV_NO_ACTION,
- .digest = {0},
- .event_size = (uint32_t)(sizeof(id_event_struct_t) +
- (sizeof(id_event_algorithm_size_t) *
- HASH_ALG_COUNT))
- },
-
- .struct_header = {
- .signature = TCG_ID_EVENT_SIGNATURE_03,
- .platform_class = PLATFORM_CLASS_CLIENT,
- .spec_version_minor = TCG_SPEC_VERSION_MINOR_TPM2,
- .spec_version_major = TCG_SPEC_VERSION_MAJOR_TPM2,
- .spec_errata = TCG_SPEC_ERRATA_TPM2,
- .uintn_size = (uint8_t)(sizeof(unsigned int) /
- sizeof(uint32_t)),
- .number_of_algorithms = HASH_ALG_COUNT
- }
-};
-
-static const event2_header_t locality_event_header = {
- /*
- * All EV_NO_ACTION events SHALL set
- * TCG_PCR_EVENT2.pcrIndex = 0, unless otherwise specified
- */
- .pcr_index = PCR_0,
-
- /*
- * All EV_NO_ACTION events SHALL set
- * TCG_PCR_EVENT2.eventType = 03h
- */
- .event_type = EV_NO_ACTION,
-
- /*
- * All EV_NO_ACTION events SHALL set
- * TCG_PCR_EVENT2.digests to all
- * 0x00's for each allocated Hash algorithm
- */
- .digests = {
- .count = HASH_ALG_COUNT
- }
-};
-
-/* Platform's table with platform specific image IDs, names and PCRs */
-static const image_data_t plat_images_data[] = {
- { BL2_IMAGE_ID, BL2_STRING, PCR_0 }, /* Reserved for BL2 */
- { INVALID_ID, NULL, (unsigned int)(-1) } /* Terminator */
-};
-
-static const measured_boot_data_t plat_measured_boot_data = {
- plat_images_data,
- NULL, /* platform_set_nt_fw_info */
- NULL /* platform_set_tos_fw_info */
-};
-
-/*
- * Function retuns pointer to platform's measured_boot_data_t structure
- *
- * Must be overridden in the platform code
- */
-#pragma weak plat_get_measured_boot_data
-
-const measured_boot_data_t *plat_get_measured_boot_data(void)
-{
- return &plat_measured_boot_data;
-}
-
-/*
- * Add TCG_PCR_EVENT2 event
- *
- * @param[in] hash Pointer to hash data of TCG_DIGEST_SIZE bytes
- * @param[in] image_ptr Pointer to image_data_t structure
- * @return:
- * 0 = success
- * < 0 = error code
- */
-static int add_event2(const uint8_t *hash, const image_data_t *image_ptr)
-{
- void *ptr = log_ptr;
- uint32_t name_len;
- uint32_t size_of_event;
-
- assert(image_ptr != NULL);
- assert(image_ptr->name != NULL);
-
- name_len = (uint32_t)strlen(image_ptr->name) + 1U;
- size_of_event = name_len + (uint32_t)EVENT2_HDR_SIZE;
-
- /* Check for space in Event Log buffer */
- if (((uintptr_t)ptr + size_of_event) > EVENT_LOG_END) {
- ERROR("%s(): Event Log is short of memory", __func__);
- return -ENOMEM;
- }
-
- /*
- * As per TCG specifications, firmware components that are measured
- * into PCR[0] must be logged in the event log using the event type
- * EV_POST_CODE.
- */
- /* TCG_PCR_EVENT2.PCRIndex */
- ((event2_header_t *)ptr)->pcr_index = image_ptr->pcr;
-
- /* TCG_PCR_EVENT2.EventType */
- ((event2_header_t *)ptr)->event_type = EV_POST_CODE;
-
- /* TCG_PCR_EVENT2.Digests.Count */
- ptr = (uint8_t *)ptr + offsetof(event2_header_t, digests);
- ((tpml_digest_values *)ptr)->count = HASH_ALG_COUNT;
-
- /* TCG_PCR_EVENT2.Digests[] */
- ptr = (uint8_t *)((uintptr_t)ptr +
- offsetof(tpml_digest_values, digests));
-
- /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
- ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
-
- /* TCG_PCR_EVENT2.Digests[].Digest[] */
- ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
-
- /* Check for space in Event Log buffer */
- if (((uintptr_t)ptr + TCG_DIGEST_SIZE) > EVENT_LOG_END) {
- ERROR("%s(): Event Log is short of memory", __func__);
- return -ENOMEM;
- }
-
- if (hash == NULL) {
- /* Get BL2 hash from DTB */
- bl2_plat_get_hash(ptr);
- } else {
- /* Copy digest */
- (void)memcpy(ptr, (const void *)hash, TCG_DIGEST_SIZE);
- }
-
- /* TCG_PCR_EVENT2.EventSize */
- ptr = (uint8_t *)((uintptr_t)ptr + TCG_DIGEST_SIZE);
- ((event2_data_t *)ptr)->event_size = name_len;
-
- /* Copy event data to TCG_PCR_EVENT2.Event */
- (void)memcpy((void *)(((event2_data_t *)ptr)->event),
- (const void *)image_ptr->name, name_len);
-
- /* End of event data */
- log_ptr = (uint8_t *)((uintptr_t)ptr +
- offsetof(event2_data_t, event) + name_len);
-
- return 0;
-}
-
-/*
- * Init Event Log
- *
- * Initialises Event Log by writing Specification ID and
- * Startup Locality events.
- */
-void event_log_init(void)
-{
- const char locality_signature[] = TCG_STARTUP_LOCALITY_SIGNATURE;
- const uint8_t *start_ptr;
- void *ptr = event_log;
-
- /* Get pointer to platform's measured_boot_data_t structure */
- plat_data_ptr = plat_get_measured_boot_data();
-
- /*
- * Add Specification ID Event first
- *
- * Copy TCG_EfiSpecIDEventStruct structure header
- */
- (void)memcpy(ptr, (const void *)&id_event_header,
- sizeof(id_event_header));
- ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_header));
-
- /* TCG_EfiSpecIdEventAlgorithmSize structure */
- ((id_event_algorithm_size_t *)ptr)->algorithm_id = TPM_ALG_ID;
- ((id_event_algorithm_size_t *)ptr)->digest_size = TCG_DIGEST_SIZE;
- ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_algorithm_size_t));
-
- /*
- * TCG_EfiSpecIDEventStruct.vendorInfoSize
- * No vendor data
- */
- ((id_event_struct_data_t *)ptr)->vendor_info_size = 0;
- ptr = (uint8_t *)((uintptr_t)ptr +
- offsetof(id_event_struct_data_t, vendor_info));
- if ((uintptr_t)ptr != ((uintptr_t)event_log + ID_EVENT_SIZE)) {
- panic();
- }
-
- start_ptr = (uint8_t *)ptr;
-
- /*
- * The Startup Locality event should be placed in the log before
- * any event which extends PCR[0].
- *
- * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
- */
-
- /* Copy Startup Locality Event Header */
- (void)memcpy(ptr, (const void *)&locality_event_header,
- sizeof(locality_event_header));
- ptr = (uint8_t *)((uintptr_t)ptr + sizeof(locality_event_header));
-
- /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
- ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
-
- /* TCG_PCR_EVENT2.Digests[].Digest[] */
- (void)memset(&((tpmt_ha *)ptr)->digest, 0, TPM_ALG_ID);
- ptr = (uint8_t *)((uintptr_t)ptr +
- offsetof(tpmt_ha, digest) + TCG_DIGEST_SIZE);
-
- /* TCG_PCR_EVENT2.EventSize */
- ((event2_data_t *)ptr)->event_size =
- (uint32_t)sizeof(startup_locality_event_t);
- ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
-
- /* TCG_EfiStartupLocalityEvent.Signature */
- (void)memcpy(ptr, (const void *)locality_signature,
- sizeof(TCG_STARTUP_LOCALITY_SIGNATURE));
-
- /*
- * TCG_EfiStartupLocalityEvent.StartupLocality = 0:
- * the platform's boot firmware
- */
- ((startup_locality_event_t *)ptr)->startup_locality = 0U;
- ptr = (uint8_t *)((uintptr_t)ptr + sizeof(startup_locality_event_t));
- if ((uintptr_t)ptr != ((uintptr_t)start_ptr + LOC_EVENT_SIZE)) {
- panic();
- }
-
- log_ptr = (uint8_t *)ptr;
-
- /* Add BL2 event */
- if (add_event2(NULL, plat_data_ptr->images_data) != 0) {
- panic();
- }
-}
-
-/*
- * Calculate and write hash of image, configuration data, etc.
- * to Event Log.
- *
- * @param[in] data_base Address of data
- * @param[in] data_size Size of data
- * @param[in] data_id Data ID
- * @return:
- * 0 = success
- * < 0 = error
- */
-int tpm_record_measurement(uintptr_t data_base, uint32_t data_size,
- uint32_t data_id)
-{
- const image_data_t *data_ptr = plat_data_ptr->images_data;
- unsigned char hash_data[MBEDTLS_MD_MAX_SIZE];
- int rc;
-
- /* Check if image_id is supported */
- while (data_ptr->id != data_id) {
- if ((data_ptr++)->id == INVALID_ID) {
- ERROR("%s(): image_id %u not supported\n",
- __func__, data_id);
- return -EINVAL;
- }
- }
-
- if (data_id == TOS_FW_CONFIG_ID) {
- tos_fw_config_base = data_base;
- } else if (data_id == NT_FW_CONFIG_ID) {
- nt_fw_config_base = data_base;
- } else {
- /* No action */
- }
-
- /* Calculate hash */
- rc = crypto_mod_calc_hash((unsigned int)MBEDTLS_MD_ID,
- (void *)data_base, data_size, hash_data);
- if (rc != 0) {
- return rc;
- }
-
- return add_event2(hash_data, data_ptr);
-}
-
-/*
- * Finalise Event Log
- *
- * @param[out] log_addr Pointer to return Event Log address
- * @param[out] log_size Pointer to return Event Log size
- * @return:
- * 0 = success
- * < 0 = error code
- */
-int event_log_finalise(uint8_t **log_addr, size_t *log_size)
-{
- /* Event Log size */
- size_t num_bytes = (uintptr_t)log_ptr - (uintptr_t)event_log;
- int rc;
-
- assert(log_addr != NULL);
- assert(log_size != NULL);
-
- if (nt_fw_config_base == 0UL) {
- ERROR("%s(): %s_FW_CONFIG not loaded\n", __func__, "NT");
- return -ENOENT;
- }
-
- /*
- * Set Event Log data in NT_FW_CONFIG and
- * get Event Log address in Non-Secure memory
- */
- if (plat_data_ptr->set_nt_fw_info != NULL) {
-
- /* Event Log address in Non-Secure memory */
- uintptr_t ns_log_addr;
-
- rc = plat_data_ptr->set_nt_fw_info(
- nt_fw_config_base,
-#ifdef SPD_opteed
- (uintptr_t)event_log,
-#endif
- num_bytes, &ns_log_addr);
- if (rc != 0) {
- ERROR("%s(): Unable to update %s_FW_CONFIG\n",
- __func__, "NT");
- return rc;
- }
-
- /* Copy Event Log to Non-secure memory */
- (void)memcpy((void *)ns_log_addr, (const void *)event_log,
- num_bytes);
-
- /* Ensure that the Event Log is visible in Non-secure memory */
- flush_dcache_range(ns_log_addr, num_bytes);
-
- /* Return Event Log address in Non-Secure memory */
- *log_addr = (uint8_t *)ns_log_addr;
-
- } else {
- INFO("%s(): set_%s_fw_info not set\n", __func__, "nt");
-
- /* Return Event Log address in Secure memory */
- *log_addr = event_log;
- }
-
- if (tos_fw_config_base != 0UL) {
- if (plat_data_ptr->set_tos_fw_info != NULL) {
-
- /* Set Event Log data in TOS_FW_CONFIG */
- rc = plat_data_ptr->set_tos_fw_info(
- tos_fw_config_base,
- (uintptr_t)event_log,
- num_bytes);
- if (rc != 0) {
- ERROR("%s(): Unable to update %s_FW_CONFIG\n",
- __func__, "TOS");
- return rc;
- }
- } else {
- INFO("%s(): set_%s_fw_info not set\n", __func__, "tos");
- }
- } else {
- INFO("%s(): %s_FW_CONFIG not loaded\n", __func__, "TOS");
- }
-
- /* Ensure that the Event Log is visible in Secure memory */
- flush_dcache_range((uintptr_t)event_log, num_bytes);
-
- /* Return Event Log size */
- *log_size = num_bytes;
-
- return 0;
-}
diff --git a/drivers/measured_boot/event_log/event_log.c b/drivers/measured_boot/event_log/event_log.c
new file mode 100644
index 0000000000..6f2898df61
--- /dev/null
+++ b/drivers/measured_boot/event_log/event_log.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <arch_helpers.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+
+#if TPM_ALG_ID == TPM_ALG_SHA512
+#define CRYPTO_MD_ID CRYPTO_MD_SHA512
+#elif TPM_ALG_ID == TPM_ALG_SHA384
+#define CRYPTO_MD_ID CRYPTO_MD_SHA384
+#elif TPM_ALG_ID == TPM_ALG_SHA256
+#define CRYPTO_MD_ID CRYPTO_MD_SHA256
+#else
+# error Invalid TPM algorithm.
+#endif /* TPM_ALG_ID */
+
+/* Running Event Log Pointer */
+static uint8_t *log_ptr;
+
+/* Pointer to the first byte past end of the Event Log buffer */
+static uintptr_t log_end;
+
+/* TCG_EfiSpecIdEvent */
+static const id_event_headers_t id_event_header = {
+ .header = {
+ .pcr_index = PCR_0,
+ .event_type = EV_NO_ACTION,
+ .digest = {0},
+ .event_size = (uint32_t)(sizeof(id_event_struct_t) +
+ (sizeof(id_event_algorithm_size_t) *
+ HASH_ALG_COUNT))
+ },
+
+ .struct_header = {
+ .signature = TCG_ID_EVENT_SIGNATURE_03,
+ .platform_class = PLATFORM_CLASS_CLIENT,
+ .spec_version_minor = TCG_SPEC_VERSION_MINOR_TPM2,
+ .spec_version_major = TCG_SPEC_VERSION_MAJOR_TPM2,
+ .spec_errata = TCG_SPEC_ERRATA_TPM2,
+ .uintn_size = (uint8_t)(sizeof(unsigned int) /
+ sizeof(uint32_t)),
+ .number_of_algorithms = HASH_ALG_COUNT
+ }
+};
+
+static const event2_header_t locality_event_header = {
+ /*
+ * All EV_NO_ACTION events SHALL set
+ * TCG_PCR_EVENT2.pcrIndex = 0, unless otherwise specified
+ */
+ .pcr_index = PCR_0,
+
+ /*
+ * All EV_NO_ACTION events SHALL set
+ * TCG_PCR_EVENT2.eventType = 03h
+ */
+ .event_type = EV_NO_ACTION,
+
+ /*
+ * All EV_NO_ACTION events SHALL set TCG_PCR_EVENT2.digests to all
+ * 0x00's for each allocated Hash algorithm
+ */
+ .digests = {
+ .count = HASH_ALG_COUNT
+ }
+};
+
+/*
+ * Record a measurement as a TCG_PCR_EVENT2 event
+ *
+ * @param[in] hash Pointer to hash data of TCG_DIGEST_SIZE bytes
+ * @param[in] event_type Type of Event, Various Event Types are
+ * mentioned in tcg.h header
+ * @param[in] metadata_ptr Pointer to event_log_metadata_t structure
+ *
+ * There must be room for storing this new event into the event log buffer.
+ */
+void event_log_record(const uint8_t *hash, uint32_t event_type,
+ const event_log_metadata_t *metadata_ptr)
+{
+ void *ptr = log_ptr;
+ uint32_t name_len = 0U;
+
+ assert(hash != NULL);
+ assert(metadata_ptr != NULL);
+ /* event_log_buf_init() must have been called prior to this. */
+ assert(log_ptr != NULL);
+
+ if (metadata_ptr->name != NULL) {
+ name_len = (uint32_t)strlen(metadata_ptr->name) + 1U;
+ }
+
+ /* Check for space in Event Log buffer */
+ assert(((uintptr_t)ptr + (uint32_t)EVENT2_HDR_SIZE + name_len) <
+ log_end);
+
+ /*
+ * As per TCG specifications, firmware components that are measured
+ * into PCR[0] must be logged in the event log using the event type
+ * EV_POST_CODE.
+ */
+ /* TCG_PCR_EVENT2.PCRIndex */
+ ((event2_header_t *)ptr)->pcr_index = metadata_ptr->pcr;
+
+ /* TCG_PCR_EVENT2.EventType */
+ ((event2_header_t *)ptr)->event_type = event_type;
+
+ /* TCG_PCR_EVENT2.Digests.Count */
+ ptr = (uint8_t *)ptr + offsetof(event2_header_t, digests);
+ ((tpml_digest_values *)ptr)->count = HASH_ALG_COUNT;
+
+ /* TCG_PCR_EVENT2.Digests[] */
+ ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(tpml_digest_values, digests));
+
+ /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+ ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+ /* TCG_PCR_EVENT2.Digests[].Digest[] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
+
+ /* Copy digest */
+ (void)memcpy(ptr, (const void *)hash, TCG_DIGEST_SIZE);
+
+ /* TCG_PCR_EVENT2.EventSize */
+ ptr = (uint8_t *)((uintptr_t)ptr + TCG_DIGEST_SIZE);
+ ((event2_data_t *)ptr)->event_size = name_len;
+
+ /* Copy event data to TCG_PCR_EVENT2.Event */
+ if (metadata_ptr->name != NULL) {
+ (void)memcpy((void *)(((event2_data_t *)ptr)->event),
+ (const void *)metadata_ptr->name, name_len);
+ }
+
+ /* End of event data */
+ log_ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(event2_data_t, event) + name_len);
+}
+
+void event_log_buf_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+ assert(event_log_start != NULL);
+ assert(event_log_finish > event_log_start);
+
+ log_ptr = event_log_start;
+ log_end = (uintptr_t)event_log_finish;
+}
+
+/*
+ * Initialise Event Log global variables, used during the recording
+ * of various payload measurements into the Event Log buffer
+ *
+ * @param[in] event_log_start Base address of Event Log buffer
+ * @param[in] event_log_finish End address of Event Log buffer,
+ * it is a first byte past end of the
+ * buffer
+ */
+void event_log_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+ event_log_buf_init(event_log_start, event_log_finish);
+}
+
+void event_log_write_specid_event(void)
+{
+ void *ptr = log_ptr;
+
+ /* event_log_buf_init() must have been called prior to this. */
+ assert(log_ptr != NULL);
+ assert(((uintptr_t)log_ptr + ID_EVENT_SIZE) < log_end);
+
+ /*
+ * Add Specification ID Event first
+ *
+ * Copy TCG_EfiSpecIDEventStruct structure header
+ */
+ (void)memcpy(ptr, (const void *)&id_event_header,
+ sizeof(id_event_header));
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_header));
+
+ /* TCG_EfiSpecIdEventAlgorithmSize structure */
+ ((id_event_algorithm_size_t *)ptr)->algorithm_id = TPM_ALG_ID;
+ ((id_event_algorithm_size_t *)ptr)->digest_size = TCG_DIGEST_SIZE;
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_algorithm_size_t));
+
+ /*
+ * TCG_EfiSpecIDEventStruct.vendorInfoSize
+ * No vendor data
+ */
+ ((id_event_struct_data_t *)ptr)->vendor_info_size = 0;
+ log_ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(id_event_struct_data_t, vendor_info));
+}
+
+/*
+ * Initialises Event Log by writing Specification ID and
+ * Startup Locality events
+ */
+void event_log_write_header(void)
+{
+ const char locality_signature[] = TCG_STARTUP_LOCALITY_SIGNATURE;
+ void *ptr;
+
+ event_log_write_specid_event();
+
+ ptr = log_ptr;
+ assert(((uintptr_t)log_ptr + LOC_EVENT_SIZE) < log_end);
+
+ /*
+ * The Startup Locality event should be placed in the log before
+ * any event which extends PCR[0].
+ *
+ * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
+ */
+
+ /* Copy Startup Locality Event Header */
+ (void)memcpy(ptr, (const void *)&locality_event_header,
+ sizeof(locality_event_header));
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(locality_event_header));
+
+ /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+ ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+ /* TCG_PCR_EVENT2.Digests[].Digest[] */
+ (void)memset(&((tpmt_ha *)ptr)->digest, 0, TCG_DIGEST_SIZE);
+ ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(tpmt_ha, digest) + TCG_DIGEST_SIZE);
+
+ /* TCG_PCR_EVENT2.EventSize */
+ ((event2_data_t *)ptr)->event_size =
+ (uint32_t)sizeof(startup_locality_event_t);
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
+
+ /* TCG_EfiStartupLocalityEvent.Signature */
+ (void)memcpy(ptr, (const void *)locality_signature,
+ sizeof(TCG_STARTUP_LOCALITY_SIGNATURE));
+
+ /*
+ * TCG_EfiStartupLocalityEvent.StartupLocality = 0:
+ * the platform's boot firmware
+ */
+ ((startup_locality_event_t *)ptr)->startup_locality = 0U;
+ log_ptr = (uint8_t *)((uintptr_t)ptr + sizeof(startup_locality_event_t));
+}
+
+int event_log_measure(uintptr_t data_base, uint32_t data_size,
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE])
+{
+ /* Calculate hash */
+ return crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)data_base, data_size, hash_data);
+}
+
+/*
+ * Calculate and write hash of image, configuration data, etc.
+ * to Event Log.
+ *
+ * @param[in] data_base Address of data
+ * @param[in] data_size Size of data
+ * @param[in] data_id Data ID
+ * @param[in] metadata_ptr Event Log metadata
+ * @return:
+ * 0 = success
+ * < 0 = error
+ */
+int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id,
+ const event_log_metadata_t *metadata_ptr)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+
+ assert(metadata_ptr != NULL);
+
+ /* Get the metadata associated with this image. */
+ while ((metadata_ptr->id != EVLOG_INVALID_ID) &&
+ (metadata_ptr->id != data_id)) {
+ metadata_ptr++;
+ }
+ assert(metadata_ptr->id != EVLOG_INVALID_ID);
+
+ /* Measure the payload with algorithm selected by EventLog driver */
+ rc = event_log_measure(data_base, data_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+
+ return 0;
+}
+
+/*
+ * Get current Event Log buffer size i.e. used space of Event Log buffer
+ *
+ * @param[in] event_log_start Base Pointer to Event Log buffer
+ *
+ * @return: current Size of Event Log buffer
+ */
+size_t event_log_get_cur_size(uint8_t *event_log_start)
+{
+ assert(event_log_start != NULL);
+ assert(log_ptr >= event_log_start);
+
+ return (size_t)((uintptr_t)log_ptr - (uintptr_t)event_log_start);
+}
diff --git a/drivers/measured_boot/event_log/event_log.mk b/drivers/measured_boot/event_log/event_log.mk
new file mode 100644
index 0000000000..5ea4c554a0
--- /dev/null
+++ b/drivers/measured_boot/event_log/event_log.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Default log level to dump the event log (LOG_LEVEL_INFO)
+EVENT_LOG_LEVEL ?= 40
+
+# Measured Boot hash algorithm.
+# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
+ifdef TPM_HASH_ALG
+ $(warning "TPM_HASH_ALG is deprecated. Please use MBOOT_EL_HASH_ALG instead.")
+ MBOOT_EL_HASH_ALG := ${TPM_HASH_ALG}
+else
+ MBOOT_EL_HASH_ALG := sha256
+endif
+
+ifeq (${MBOOT_EL_HASH_ALG}, sha512)
+ TPM_ALG_ID := TPM_ALG_SHA512
+ TCG_DIGEST_SIZE := 64U
+else ifeq (${MBOOT_EL_HASH_ALG}, sha384)
+ TPM_ALG_ID := TPM_ALG_SHA384
+ TCG_DIGEST_SIZE := 48U
+else
+ TPM_ALG_ID := TPM_ALG_SHA256
+ TCG_DIGEST_SIZE := 32U
+endif #MBOOT_EL_HASH_ALG
+
+# Set definitions for Measured Boot driver.
+$(eval $(call add_defines,\
+ $(sort \
+ TPM_ALG_ID \
+ TCG_DIGEST_SIZE \
+ EVENT_LOG_LEVEL \
+)))
+
+EVENT_LOG_SRC_DIR := drivers/measured_boot/event_log/
+
+EVENT_LOG_SOURCES := ${EVENT_LOG_SRC_DIR}event_log.c \
+ ${EVENT_LOG_SRC_DIR}event_print.c
diff --git a/drivers/measured_boot/event_print.c b/drivers/measured_boot/event_log/event_print.c
index 84ed4b1cb5..e2ba1744d1 100644
--- a/drivers/measured_boot/event_print.c
+++ b/drivers/measured_boot/event_log/event_print.c
@@ -8,7 +8,7 @@
#include <string.h>
#include <common/debug.h>
-#include <drivers/measured_boot/event_log.h>
+#include <drivers/measured_boot/event_log/event_log.h>
#if LOG_LEVEL >= EVENT_LOG_LEVEL
diff --git a/drivers/measured_boot/measured_boot.c b/drivers/measured_boot/measured_boot.c
deleted file mode 100644
index 37fddfbdcf..0000000000
--- a/drivers/measured_boot/measured_boot.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-
-#include <common/debug.h>
-#include <drivers/measured_boot/measured_boot.h>
-
-/*
- * Init Measured Boot driver
- *
- * Initialises Event Log.
- */
-void measured_boot_init(void)
-{
- event_log_init();
-}
-
-/*
- * Finish Measured Boot driver
- *
- * Finalises Event Log and dumps the records to the debug console.
- */
-void measured_boot_finish(void)
-{
- uint8_t *log_addr;
- size_t log_size;
- int rc;
-
- rc = event_log_finalise(&log_addr, &log_size);
- if (rc != 0) {
- panic();
- }
-
- dump_event_log(log_addr, log_size);
-}
diff --git a/drivers/measured_boot/measured_boot.mk b/drivers/measured_boot/measured_boot.mk
deleted file mode 100644
index 497fdbaaee..0000000000
--- a/drivers/measured_boot/measured_boot.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# Copyright (c) 2020, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-# Default log level to dump the event log (LOG_LEVEL_INFO)
-EVENT_LOG_LEVEL ?= 40
-
-# TPM hash algorithm
-TPM_HASH_ALG := sha256
-
-ifeq (${TPM_HASH_ALG}, sha512)
- MBEDTLS_MD_ID := MBEDTLS_MD_SHA512
- TPM_ALG_ID := TPM_ALG_SHA512
- TCG_DIGEST_SIZE := 64U
-else ifeq (${TPM_HASH_ALG}, sha384)
- MBEDTLS_MD_ID := MBEDTLS_MD_SHA384
- TPM_ALG_ID := TPM_ALG_SHA384
- TCG_DIGEST_SIZE := 48U
-else
- MBEDTLS_MD_ID := MBEDTLS_MD_SHA256
- TPM_ALG_ID := TPM_ALG_SHA256
- TCG_DIGEST_SIZE := 32U
-endif
-
-# Event Log length in bytes
-EVENT_LOG_SIZE := 1024
-
-# Set definitions for mbed TLS library and Measured Boot driver
-$(eval $(call add_defines,\
- $(sort \
- MBEDTLS_MD_ID \
- TPM_ALG_ID \
- TCG_DIGEST_SIZE \
- EVENT_LOG_SIZE \
- EVENT_LOG_LEVEL \
-)))
-
-ifeq (${HASH_ALG}, sha256)
-ifneq (${TPM_HASH_ALG}, sha256)
-$(eval $(call add_define,MBEDTLS_SHA512_C))
-endif
-endif
-
-MEASURED_BOOT_SRC_DIR := drivers/measured_boot/
-
-MEASURED_BOOT_SOURCES := ${MEASURED_BOOT_SRC_DIR}measured_boot.c \
- ${MEASURED_BOOT_SRC_DIR}event_log.c \
- ${MEASURED_BOOT_SRC_DIR}event_print.c
-
-BL2_SOURCES += ${MEASURED_BOOT_SOURCES}
diff --git a/drivers/measured_boot/rss/dice_prot_env.c b/drivers/measured_boot/rss/dice_prot_env.c
new file mode 100644
index 0000000000..81a21d1647
--- /dev/null
+++ b/drivers/measured_boot/rss/dice_prot_env.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <psa/crypto_types.h>
+#include <psa/crypto_values.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/rss/dice_prot_env.h>
+#include <lib/cassert.h>
+#include <lib/psa/dice_protection_environment.h>
+
+#include <platform_def.h>
+
+#define DPE_ALG_SHA512 0
+#define DPE_ALG_SHA384 1
+#define DPE_ALG_SHA256 2
+
+#if DPE_ALG_ID == DPE_ALG_SHA512
+#define CRYPTO_MD_ID CRYPTO_MD_SHA512
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_512
+#elif DPE_ALG_ID == DPE_ALG_SHA384
+#define CRYPTO_MD_ID CRYPTO_MD_SHA384
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_384
+#elif DPE_ALG_ID == DPE_ALG_SHA256
+#define CRYPTO_MD_ID CRYPTO_MD_SHA256
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_256
+#else
+# error Invalid DPE hash algorithm.
+#endif /* DPE_ALG_ID */
+
+/* Ensure that computed hash values fits into the DiceInputValues structure */
+CASSERT(DICE_HASH_SIZE >= DPE_DIGEST_SIZE,
+ assert_digest_size_bigger_than_allocated_buffer);
+
+static int initial_context_handle;
+
+static void map_metadata_to_dice_inputs(struct dpe_metadata *metadata,
+ DiceInputValues *dice_inputs)
+{
+ /* Hash of the content certificate signing key (public part) */
+ memcpy(dice_inputs->authority_hash, metadata->signer_id,
+ DPE_DIGEST_SIZE);
+
+ /* SW type string identifier */
+ assert(metadata->sw_type_size < DICE_CODE_DESCRIPTOR_MAX_SIZE);
+ dice_inputs->code_descriptor = metadata->sw_type;
+ dice_inputs->code_descriptor_size = metadata->sw_type_size;
+}
+
+void dpe_init(struct dpe_metadata *metadata)
+{
+ assert(metadata != NULL);
+
+ /* Init the non-const members of the metadata structure */
+ while (metadata->id != DPE_INVALID_ID) {
+ /* Terminating 0 character is not needed due to CBOR encoding */
+ metadata->sw_type_size =
+ strlen((const char *)&metadata->sw_type);
+ metadata++;
+ }
+
+ plat_dpe_get_context_handle(&initial_context_handle);
+}
+
+int dpe_measure_and_record(struct dpe_metadata *metadata,
+ uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id)
+{
+ static int current_context_handle;
+ DiceInputValues dice_inputs = { 0 };
+ int new_parent_context_handle;
+ int new_context_handle;
+ dpe_error_t ret;
+ int rc;
+
+ assert(metadata != NULL);
+
+ /* Get the metadata associated with this image. */
+ while ((metadata->id != DPE_INVALID_ID) && (metadata->id != data_id)) {
+ metadata++;
+ }
+
+ /* If image is not present in metadata array then skip */
+ if (metadata->id == DPE_INVALID_ID) {
+ return 0;
+ }
+
+ /* Calculate hash */
+ rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)data_base, data_size,
+ dice_inputs.code_hash);
+ if (rc != 0) {
+ return rc;
+ }
+
+ map_metadata_to_dice_inputs(metadata, &dice_inputs);
+
+ /* Only at the first call */
+ if (current_context_handle == 0) {
+ current_context_handle = initial_context_handle;
+ }
+
+ VERBOSE("Calling dpe_derive_context, image_id: %d\n", metadata->id);
+ ret = dpe_derive_context(current_context_handle,
+ metadata->cert_id,
+ metadata->retain_parent_context,
+ metadata->allow_new_context_to_derive,
+ metadata->create_certificate,
+ &dice_inputs,
+ 0, /* target_locality */
+ false, /* return_certificate */
+ true, /* allow_new_context_to_export */
+ false, /* export_cdi */
+ &new_context_handle,
+ &new_parent_context_handle,
+ NULL, 0, NULL, /* new_certificate_* */
+ NULL, 0, NULL); /* exported_cdi_* */
+ if (ret == DPE_NO_ERROR) {
+ current_context_handle = new_parent_context_handle;
+ if (metadata->allow_new_context_to_derive == true) {
+ /* Share new_context_handle with child component:
+ * e.g: BL2, BL33.
+ */
+ VERBOSE("Share new_context_handle with child: 0x%x\n",
+ new_context_handle);
+ plat_dpe_share_context_handle(&new_context_handle);
+ }
+ } else {
+ ERROR("dpe_derive_context failed: %d\n", ret);
+ }
+
+ return (ret == DPE_NO_ERROR) ? 0 : -1;
+}
+
+int dpe_set_signer_id(struct dpe_metadata *metadata,
+ const void *pk_oid,
+ const void *pk_ptr,
+ size_t pk_len)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+ bool hash_calc_done = false;
+
+ assert(metadata != NULL);
+
+ /*
+ * Do an exhaustive search over the platform metadata to find
+ * all images whose key OID matches the one passed in argument.
+ *
+ * Note that it is not an error if do not get any matches.
+ * The platform may decide not to measure all of the images
+ * in the system.
+ */
+ while (metadata->id != DPE_INVALID_ID) {
+ /* Get the metadata associated with this key-oid */
+ if (metadata->pk_oid == pk_oid) {
+ if (hash_calc_done == false) {
+ /* Calculate public key hash */
+ rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)pk_ptr,
+ pk_len, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ hash_calc_done = true;
+ }
+
+ /*
+ * Fill the signer-ID field with the newly/already
+ * computed hash of the public key and update its
+ * signer ID size field with compile-time decided
+ * digest size.
+ */
+ (void)memcpy(metadata->signer_id,
+ hash_data,
+ DPE_DIGEST_SIZE);
+ metadata->signer_id_size = DPE_DIGEST_SIZE;
+ }
+
+ metadata++;
+ }
+
+ return 0;
+}
diff --git a/drivers/measured_boot/rss/dice_prot_env.mk b/drivers/measured_boot/rss/dice_prot_env.mk
new file mode 100644
index 0000000000..c5a35e0313
--- /dev/null
+++ b/drivers/measured_boot/rss/dice_prot_env.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Hash algorithm for DICE Protection Environment
+# SHA-256 (or stronger) is required.
+DPE_HASH_ALG := sha256
+
+ifeq (${DPE_HASH_ALG}, sha512)
+ DPE_ALG_ID := DPE_ALG_SHA512
+ DPE_DIGEST_SIZE := 64U
+else ifeq (${DPE_HASH_ALG}, sha384)
+ DPE_ALG_ID := DPE_ALG_SHA384
+ DPE_DIGEST_SIZE := 48U
+else
+ DPE_ALG_ID := DPE_ALG_SHA256
+ DPE_DIGEST_SIZE := 32U
+endif #DPE_HASH_ALG
+
+# Set definitions for DICE Protection Environment
+$(eval $(call add_defines,\
+ $(sort \
+ DPE_ALG_ID \
+ DPE_DIGEST_SIZE \
+)))
+
+DPE_SOURCES += drivers/measured_boot/rss/dice_prot_env.c
diff --git a/drivers/measured_boot/rss/qcbor.mk b/drivers/measured_boot/rss/qcbor.mk
new file mode 100644
index 0000000000..2146e5d2ec
--- /dev/null
+++ b/drivers/measured_boot/rss/qcbor.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TF-A was tested with v1.2 version of QCBOR
+
+ifeq (${QCBOR_DIR},)
+ $(error Error: QCBOR_DIR not set)
+endif
+
+QCBOR_SOURCES += ${QCBOR_DIR}/src/qcbor_encode.c \
+ ${QCBOR_DIR}/src/qcbor_decode.c \
+ ${QCBOR_DIR}/src/UsefulBuf.c
+
+QCBOR_INCLUDES += ${QCBOR_DIR}/inc
+
+# Floating point numbers are not used, so disable the support.
+# This reduces the library size as well.
+$(eval $(call add_define,QCBOR_DISABLE_FLOAT_HW_USE))
+$(eval $(call add_define,USEFULBUF_DISABLE_ALL_FLOAT))
+$(eval $(call add_define,QCBOR_DISABLE_PREFERRED_FLOAT))
diff --git a/drivers/measured_boot/rss/rss_measured_boot.c b/drivers/measured_boot/rss/rss_measured_boot.c
new file mode 100644
index 0000000000..c44ec73960
--- /dev/null
+++ b/drivers/measured_boot/rss/rss_measured_boot.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/rss/rss_measured_boot.h>
+#include <lib/psa/measured_boot.h>
+#include <psa/crypto_types.h>
+#include <psa/crypto_values.h>
+#include <psa/error.h>
+
+#define MBOOT_ALG_SHA512 0
+#define MBOOT_ALG_SHA384 1
+#define MBOOT_ALG_SHA256 2
+
+#if MBOOT_ALG_ID == MBOOT_ALG_SHA512
+#define CRYPTO_MD_ID CRYPTO_MD_SHA512
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_512
+#elif MBOOT_ALG_ID == MBOOT_ALG_SHA384
+#define CRYPTO_MD_ID CRYPTO_MD_SHA384
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_384
+#elif MBOOT_ALG_ID == MBOOT_ALG_SHA256
+#define CRYPTO_MD_ID CRYPTO_MD_SHA256
+#define PSA_CRYPTO_MD_ID PSA_ALG_SHA_256
+#else
+# error Invalid Measured Boot algorithm.
+#endif /* MBOOT_ALG_ID */
+
+#if ENABLE_ASSERTIONS
+static bool null_arr(const uint8_t *signer_id, size_t signer_id_size)
+{
+ for (size_t i = 0U; i < signer_id_size; i++) {
+ if (signer_id[i] != 0U) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif /* ENABLE_ASSERTIONS */
+
+/* Functions' declarations */
+void rss_measured_boot_init(struct rss_mboot_metadata *metadata_ptr)
+{
+ assert(metadata_ptr != NULL);
+
+ /* Init the non-const members of the metadata structure */
+ while (metadata_ptr->id != RSS_MBOOT_INVALID_ID) {
+ assert(null_arr(metadata_ptr->signer_id, MBOOT_DIGEST_SIZE));
+ metadata_ptr->sw_type_size =
+ strlen((const char *)&metadata_ptr->sw_type) + 1;
+ metadata_ptr++;
+ }
+}
+
+int rss_mboot_measure_and_record(struct rss_mboot_metadata *metadata_ptr,
+ uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+ psa_status_t ret;
+
+ assert(metadata_ptr != NULL);
+
+ /* Get the metadata associated with this image. */
+ while ((metadata_ptr->id != RSS_MBOOT_INVALID_ID) &&
+ (metadata_ptr->id != data_id)) {
+ metadata_ptr++;
+ }
+
+ /* If image is not present in metadata array then skip */
+ if (metadata_ptr->id == RSS_MBOOT_INVALID_ID) {
+ return 0;
+ }
+
+ /* Calculate hash */
+ rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)data_base, data_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ ret = rss_measured_boot_extend_measurement(
+ metadata_ptr->slot,
+ metadata_ptr->signer_id,
+ metadata_ptr->signer_id_size,
+ metadata_ptr->version,
+ metadata_ptr->version_size,
+ PSA_CRYPTO_MD_ID,
+ metadata_ptr->sw_type,
+ metadata_ptr->sw_type_size,
+ hash_data,
+ MBOOT_DIGEST_SIZE,
+ metadata_ptr->lock_measurement);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ return 0;
+}
+
+int rss_mboot_set_signer_id(struct rss_mboot_metadata *metadata_ptr,
+ const void *pk_oid,
+ const void *pk_ptr,
+ size_t pk_len)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+ bool hash_calc_done = false;
+
+ assert(metadata_ptr != NULL);
+
+ /*
+ * Do an exhaustive search over the platform metadata to find
+ * all images whose key OID matches the one passed in argument.
+ *
+ * Note that it is not an error if do not get any matches.
+ * The platform may decide not to measure all of the images
+ * in the system.
+ */
+ while (metadata_ptr->id != RSS_MBOOT_INVALID_ID) {
+ /* Get the metadata associated with this key-oid */
+ if (metadata_ptr->pk_oid == pk_oid) {
+ if (hash_calc_done == false) {
+ /* Calculate public key hash */
+ rc = crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)pk_ptr,
+ pk_len, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ hash_calc_done = true;
+ }
+
+ /*
+ * Fill the signer-ID field with the newly/already
+ * computed hash of the public key and update its
+ * signer ID size field with compile-time decided
+ * digest size.
+ */
+ (void)memcpy(metadata_ptr->signer_id,
+ hash_data,
+ MBOOT_DIGEST_SIZE);
+ metadata_ptr->signer_id_size = MBOOT_DIGEST_SIZE;
+ }
+
+ metadata_ptr++;
+ }
+
+ return 0;
+}
diff --git a/drivers/measured_boot/rss/rss_measured_boot.mk b/drivers/measured_boot/rss/rss_measured_boot.mk
new file mode 100644
index 0000000000..18ee836184
--- /dev/null
+++ b/drivers/measured_boot/rss/rss_measured_boot.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Hash algorithm for measured boot
+# SHA-256 (or stronger) is required.
+MBOOT_RSS_HASH_ALG := sha256
+
+ifeq (${MBOOT_RSS_HASH_ALG}, sha512)
+ MBOOT_ALG_ID := MBOOT_ALG_SHA512
+ MBOOT_DIGEST_SIZE := 64U
+else ifeq (${MBOOT_RSS_HASH_ALG}, sha384)
+ MBOOT_ALG_ID := MBOOT_ALG_SHA384
+ MBOOT_DIGEST_SIZE := 48U
+else
+ MBOOT_ALG_ID := MBOOT_ALG_SHA256
+ MBOOT_DIGEST_SIZE := 32U
+endif #MBOOT_RSS_HASH_ALG
+
+# Set definitions for Measured Boot driver.
+$(eval $(call add_defines,\
+ $(sort \
+ MBOOT_ALG_ID \
+ MBOOT_DIGEST_SIZE \
+ MBOOT_RSS_BACKEND \
+)))
+
+MEASURED_BOOT_SRC_DIR := drivers/measured_boot/rss/
+
+MEASURED_BOOT_SOURCES += ${MEASURED_BOOT_SRC_DIR}rss_measured_boot.c
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index c327e71d20..b51e744364 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -16,6 +16,7 @@
#include <drivers/delay_timer.h>
#include <drivers/mmc.h>
#include <lib/utils.h>
+#include <plat/common/common_def.h>
#define MMC_DEFAULT_MAX_RETRIES 5
#define SEND_OP_COND_MAX_RETRIES 100
@@ -25,6 +26,7 @@
static const struct mmc_ops *ops;
static unsigned int mmc_ocr_value;
static struct mmc_csd_emmc mmc_csd;
+static struct sd_switch_status sd_switch_func_status;
static unsigned char mmc_ext_csd[512] __aligned(16);
static unsigned int mmc_flags;
static struct mmc_device_info *mmc_dev_info;
@@ -44,6 +46,11 @@ static bool is_cmd23_enabled(void)
return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
}
+static bool is_sd_cmd6_enabled(void)
+{
+ return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U);
+}
+
static int mmc_send_cmd(unsigned int idx, unsigned int arg,
unsigned int r_type, unsigned int *r_data)
{
@@ -62,8 +69,7 @@ static int mmc_send_cmd(unsigned int idx, unsigned int arg,
int i;
for (i = 0; i < 4; i++) {
- *r_data = cmd.resp_data[i];
- r_data++;
+ r_data[i] = cmd.resp_data[i];
}
}
@@ -77,7 +83,7 @@ static int mmc_send_cmd(unsigned int idx, unsigned int arg,
static int mmc_device_state(void)
{
int retries = MMC_DEFAULT_MAX_RETRIES;
- unsigned int resp_data[4];
+ unsigned int resp_data[4] = {0};
do {
int ret;
@@ -105,7 +111,7 @@ static int mmc_device_state(void)
return MMC_GET_STATE(resp_data[0]);
}
-static int mmc_send_part_switch_cmd(unsigned int part_config)
+static int mmc_send_part_switch_cmd(unsigned char part_config)
{
int ret;
unsigned int part_time = 0;
@@ -357,6 +363,33 @@ static int mmc_fill_device_info(void)
return 0;
}
+static int sd_switch(unsigned int mode, unsigned char group,
+ unsigned char func)
+{
+ unsigned int group_shift = (group - 1U) * 4U;
+ unsigned int group_mask = GENMASK(group_shift + 3U, group_shift);
+ unsigned int arg;
+ int ret;
+
+ ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status,
+ sizeof(sd_switch_func_status));
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* MMC CMD6: SWITCH_FUNC */
+ arg = mode | SD_SWITCH_ALL_GROUPS_MASK;
+ arg &= ~group_mask;
+ arg |= func << group_shift;
+ ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return ops->read(0, (uintptr_t)&sd_switch_func_status,
+ sizeof(sd_switch_func_status));
+}
+
static int sd_send_op_cond(void)
{
int n;
@@ -419,11 +452,6 @@ static int mmc_send_op_cond(void)
int ret, n;
unsigned int resp_data[4];
- ret = mmc_reset_to_idle();
- if (ret != 0) {
- return ret;
- }
-
for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
@@ -524,7 +552,39 @@ static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
return ret;
}
- return mmc_fill_device_info();
+ ret = mmc_fill_device_info();
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (is_sd_cmd6_enabled() &&
+ (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) {
+ /* Try to switch to High Speed Mode */
+ ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) {
+ /* High speed not supported, keep default speed */
+ return 0;
+ }
+
+ ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) {
+ /* Cannot switch to high speed, keep default speed */
+ return 0;
+ }
+
+ mmc_dev_info->max_bus_freq = 50000000U;
+ ret = ops->set_ios(clk, bus_width);
+ }
+
+ return ret;
}
size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
@@ -694,90 +754,70 @@ size_t mmc_erase_blocks(int lba, size_t size)
return size;
}
-static inline void mmc_rpmb_enable(void)
+static int mmc_part_switch(unsigned char part_type)
{
- mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
- PART_CFG_BOOT_PARTITION1_ENABLE |
- PART_CFG_BOOT_PARTITION1_ACCESS);
-}
-
-static inline void mmc_rpmb_disable(void)
-{
- mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
- PART_CFG_BOOT_PARTITION1_ENABLE);
-}
+ unsigned char part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG];
-size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
-{
- size_t size_read;
-
- mmc_rpmb_enable();
- size_read = mmc_read_blocks(lba, buf, size);
- mmc_rpmb_disable();
+ part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+ part_config |= part_type;
- return size_read;
+ return mmc_send_part_switch_cmd(part_config);
}
-size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
+static unsigned char mmc_current_boot_part(void)
{
- size_t size_written;
-
- mmc_rpmb_enable();
- size_written = mmc_write_blocks(lba, buf, size);
- mmc_rpmb_disable();
-
- return size_written;
+ return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]);
}
-size_t mmc_rpmb_erase_blocks(int lba, size_t size)
+int mmc_part_switch_current_boot(void)
{
- size_t size_erased;
+ unsigned char current_boot_part = mmc_current_boot_part();
+ int ret;
+
+ if ((current_boot_part != 1U) && (current_boot_part != 2U)) {
+ ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part);
+ return -EIO;
+ }
- mmc_rpmb_enable();
- size_erased = mmc_erase_blocks(lba, size);
- mmc_rpmb_disable();
+ ret = mmc_part_switch(current_boot_part);
+ if (ret < 0) {
+ ERROR("Failed to switch to boot partition, %d\n", ret);
+ }
- return size_erased;
+ return ret;
}
-static int mmc_part_switch(unsigned int part_type)
+int mmc_part_switch_user(void)
{
- uint8_t part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG];
+ int ret;
- part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
- part_config |= part_type;
+ ret = mmc_part_switch(PART_CFG_BOOT_PARTITION_NO_ACCESS);
+ if (ret < 0) {
+ ERROR("Failed to switch to user partition, %d\n", ret);
+ }
- return mmc_send_part_switch_cmd(part_config);
+ return ret;
}
-static unsigned char mmc_current_boot_part(void)
+size_t mmc_boot_part_size(void)
{
- return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]);
+ return mmc_ext_csd[CMD_EXTCSD_BOOT_SIZE_MULT] * SZ_128K;
}
size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size)
{
size_t size_read;
int ret;
- unsigned char current_boot_part = mmc_current_boot_part();
-
- if (current_boot_part != 1U &&
- current_boot_part != 2U) {
- ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part);
- return 0;
- }
- ret = mmc_part_switch(current_boot_part);
+ ret = mmc_part_switch_current_boot();
if (ret < 0) {
- ERROR("Failed to switch to boot partition, %d\n", ret);
return 0;
}
size_read = mmc_read_blocks(lba, buf, size);
- ret = mmc_part_switch(0);
+ ret = mmc_part_switch_user();
if (ret < 0) {
- ERROR("Failed to switch back to user partition, %d\n", ret);
return 0;
}
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index 44b001e35b..6ef2256ab4 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,18 +8,29 @@
#include <errno.h>
#include <stddef.h>
-#include <platform_def.h>
-
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/nand.h>
#include <lib/utils.h>
+#include <platform_def.h>
+
/*
* Define a single nand_device used by specific NAND frameworks.
*/
static struct nand_device nand_dev;
-static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE];
+
+#pragma weak plat_get_scratch_buffer
+void plat_get_scratch_buffer(void **buffer_addr, size_t *buf_size)
+{
+ static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE];
+
+ assert(buffer_addr != NULL);
+ assert(buf_size != NULL);
+
+ *buffer_addr = (void *)scratch_buff;
+ *buf_size = sizeof(scratch_buff);
+}
int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
size_t *length_read)
@@ -34,6 +45,12 @@ int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
unsigned int bytes_read;
int is_bad;
int ret;
+ uint8_t *scratch_buff;
+ size_t scratch_buff_size;
+
+ plat_get_scratch_buffer((void **)&scratch_buff, &scratch_buff_size);
+
+ assert(scratch_buff != NULL);
VERBOSE("Block %u - %u, page_start %u, nb %u, length %zu, offset %u\n",
block, end_block, page_start, nb_pages, length, offset);
@@ -41,7 +58,7 @@ int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
*length_read = 0UL;
if (((start_offset != 0U) || (length % nand_dev.page_size) != 0U) &&
- (sizeof(scratch_buff) < nand_dev.page_size)) {
+ (scratch_buff_size < nand_dev.page_size)) {
return -EINVAL;
}
@@ -112,6 +129,47 @@ int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
return 0;
}
+int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset)
+{
+ unsigned int block;
+ unsigned int offset_block;
+ unsigned int max_block;
+ int is_bad;
+ size_t count_bb = 0U;
+
+ block = base / nand_dev.block_size;
+
+ if (offset != 0U) {
+ offset_block = (base + offset - 1U) / nand_dev.block_size;
+ } else {
+ offset_block = block;
+ }
+
+ max_block = nand_dev.size / nand_dev.block_size;
+
+ while (block <= offset_block) {
+ if (offset_block >= max_block) {
+ return -EIO;
+ }
+
+ is_bad = nand_dev.mtd_block_is_bad(block);
+ if (is_bad < 0) {
+ return is_bad;
+ }
+
+ if (is_bad == 1) {
+ count_bb++;
+ offset_block++;
+ }
+
+ block++;
+ }
+
+ *extra_offset = count_bb * nand_dev.block_size;
+
+ return 0;
+}
+
struct nand_device *get_nand_device(void)
{
return &nand_dev;
diff --git a/drivers/mtd/nand/raw_nand.c b/drivers/mtd/nand/raw_nand.c
index 1fb5facaff..3595c21424 100644
--- a/drivers/mtd/nand/raw_nand.c
+++ b/drivers/mtd/nand/raw_nand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,13 +8,13 @@
#include <errno.h>
#include <stddef.h>
-#include <platform_def.h>
-
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/raw_nand.h>
#include <lib/utils.h>
+#include <platform_def.h>
+
#define ONFI_SIGNATURE_ADDR 0x20U
/* CRC calculation */
@@ -24,9 +24,6 @@
/* Status register */
#define NAND_STATUS_READY BIT(6)
-#define SZ_128M 0x08000000U
-#define SZ_512 0x200U
-
static struct rawnand_device rawnand_dev;
#pragma weak plat_get_raw_nand_data
@@ -221,6 +218,18 @@ int nand_wait_ready(unsigned int delay_ms)
return -ETIMEDOUT;
}
+static int nand_reset(void)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_RESET, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_send_wait(PSEC_TO_MSEC(NAND_TRST_MAX), 0U);
+}
+
#if NAND_ONFI_DETECT
static uint16_t nand_check_crc(uint16_t crc, uint8_t *data_in,
unsigned int data_len)
@@ -268,18 +277,6 @@ static int nand_read_id(uint8_t addr, uint8_t *id, unsigned int size)
return nand_read_data(id, size, true);
}
-static int nand_reset(void)
-{
- int ret;
-
- ret = nand_send_cmd(NAND_CMD_RESET, NAND_TWB_MAX);
- if (ret != 0) {
- return ret;
- }
-
- return nand_send_wait(PSEC_TO_MSEC(NAND_TRST_MAX), 0U);
-}
-
static int nand_read_param_page(void)
{
struct nand_param_page page;
@@ -349,11 +346,6 @@ static int detect_onfi(void)
int ret;
char id[4];
- ret = nand_reset();
- if (ret != 0) {
- return ret;
- }
-
ret = nand_read_id(ONFI_SIGNATURE_ADDR, (uint8_t *)id, sizeof(id));
if (ret != 0) {
return ret;
@@ -409,6 +401,8 @@ void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops)
int nand_raw_init(unsigned long long *size, unsigned int *erase_size)
{
+ int ret;
+
rawnand_dev.nand_dev = get_nand_device();
if (rawnand_dev.nand_dev == NULL) {
return -EINVAL;
@@ -423,6 +417,11 @@ int nand_raw_init(unsigned long long *size, unsigned int *erase_size)
return -ENODEV;
}
+ ret = nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
#if NAND_ONFI_DETECT
if (detect_onfi() != 0) {
WARN("Detect ONFI failed\n");
diff --git a/drivers/mtd/nand/spi_nand.c b/drivers/mtd/nand/spi_nand.c
index d01a11963f..744383aa3c 100644
--- a/drivers/mtd/nand/spi_nand.c
+++ b/drivers/mtd/nand/spi_nand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2023, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,16 +8,15 @@
#include <errno.h>
#include <stddef.h>
-#include <platform_def.h>
-
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/spi_nand.h>
#include <lib/utils.h>
+#include <platform_def.h>
+
#define SPI_NAND_MAX_ID_LEN 4U
#define DELAY_US_400MS 400000U
-#define MACRONIX_ID 0xC2U
static struct spinand_device spinand_dev;
@@ -91,7 +90,7 @@ static int spi_nand_quad_enable(uint8_t manufacturer_id)
{
bool enable = false;
- if (manufacturer_id != MACRONIX_ID) {
+ if ((spinand_dev.flags & SPI_NAND_HAS_QE_BIT) == 0U) {
return 0;
}
@@ -246,7 +245,7 @@ static int spi_nand_mtd_block_is_bad(unsigned int block)
if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
(bbm_marker[1] != GENMASK_32(7, 0))) {
- WARN("Block %i is bad\n", block);
+ WARN("Block %u is bad\n", block);
return 1;
}
@@ -286,6 +285,10 @@ int spi_nand_init(unsigned long long *size, unsigned int *erase_size)
return -EINVAL;
}
+ assert((spinand_dev.nand_dev->page_size != 0U) &&
+ (spinand_dev.nand_dev->block_size != 0U) &&
+ (spinand_dev.nand_dev->size != 0U));
+
ret = spi_nand_reset();
if (ret != 0) {
return ret;
@@ -301,14 +304,14 @@ int spi_nand_init(unsigned long long *size, unsigned int *erase_size)
return ret;
}
- ret = spi_nand_quad_enable(id[0]);
+ ret = spi_nand_quad_enable(id[1]);
if (ret != 0) {
return ret;
}
- VERBOSE("SPI_NAND Detected ID 0x%x 0x%x\n", id[0], id[1]);
+ VERBOSE("SPI_NAND Detected ID 0x%x\n", id[1]);
- VERBOSE("Page size %i, Block size %i, size %lli\n",
+ VERBOSE("Page size %u, Block size %u, size %llu\n",
spinand_dev.nand_dev->page_size,
spinand_dev.nand_dev->block_size,
spinand_dev.nand_dev->size);
diff --git a/drivers/mtd/nor/spi_nor.c b/drivers/mtd/nor/spi_nor.c
index 108f893d3f..2e343448a0 100644
--- a/drivers/mtd/nor/spi_nor.c
+++ b/drivers/mtd/nor/spi_nor.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -103,7 +103,7 @@ static int spi_nor_ready(void)
0 : 1;
}
- return (((sr & SR_WIP) != 0U) ? 1 : 0);
+ return (((sr & SR_WIP) == 0U) ? 0 : 1);
}
static int spi_nor_wait_ready(void)
@@ -131,7 +131,7 @@ static int spi_nor_macronix_quad_enable(void)
return ret;
}
- if ((sr & SR_QUAD_EN_MX) == 0U) {
+ if ((sr & SR_QUAD_EN_MX) != 0U) {
return 0;
}
@@ -141,7 +141,7 @@ static int spi_nor_macronix_quad_enable(void)
}
sr |= SR_QUAD_EN_MX;
- ret = spi_nor_reg(SPI_NOR_OP_WRSR, &sr, 1, SPI_MEM_DATA_OUT);
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, &sr, 1U, SPI_MEM_DATA_OUT);
if (ret != 0) {
return ret;
}
@@ -168,7 +168,7 @@ static int spi_nor_write_sr_cr(uint8_t *sr_cr)
return ret;
}
- ret = spi_nor_reg(SPI_NOR_OP_WRSR, sr_cr, 2, SPI_MEM_DATA_OUT);
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, sr_cr, 2U, SPI_MEM_DATA_OUT);
if (ret != 0) {
return -EINVAL;
}
@@ -230,7 +230,7 @@ static int spi_nor_clean_bar(void)
}
return spi_nor_reg(nor_dev.bank_write_cmd, &nor_dev.selected_bank,
- 1, SPI_MEM_DATA_OUT);
+ 1U, SPI_MEM_DATA_OUT);
}
static int spi_nor_write_bar(uint32_t offset)
@@ -248,7 +248,7 @@ static int spi_nor_write_bar(uint32_t offset)
}
ret = spi_nor_reg(nor_dev.bank_write_cmd, &selected_bank,
- 1, SPI_MEM_DATA_OUT);
+ 1U, SPI_MEM_DATA_OUT);
if (ret != 0) {
return ret;
}
@@ -260,11 +260,11 @@ static int spi_nor_write_bar(uint32_t offset)
static int spi_nor_read_bar(void)
{
- uint8_t selected_bank = 0;
+ uint8_t selected_bank = 0U;
int ret;
ret = spi_nor_reg(nor_dev.bank_read_cmd, &selected_bank,
- 1, SPI_MEM_DATA_IN);
+ 1U, SPI_MEM_DATA_IN);
if (ret != 0) {
return ret;
}
@@ -280,11 +280,11 @@ int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
size_t remain_len;
int ret;
- *length_read = 0;
+ *length_read = 0U;
nor_dev.read_op.addr.val = offset;
nor_dev.read_op.data.buf = (void *)buffer;
- VERBOSE("%s offset %i length %zu\n", __func__, offset, length);
+ VERBOSE("%s offset %u length %zu\n", __func__, offset, length);
while (length != 0U) {
if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
@@ -324,7 +324,7 @@ int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
int spi_nor_init(unsigned long long *size, unsigned int *erase_size)
{
- int ret = 0;
+ int ret;
uint8_t id;
/* Default read command used */
@@ -339,7 +339,7 @@ int spi_nor_init(unsigned long long *size, unsigned int *erase_size)
return -EINVAL;
}
- assert(nor_dev.size != 0);
+ assert(nor_dev.size != 0U);
if (nor_dev.size > BANK_SIZE) {
nor_dev.flags |= SPI_NOR_USE_BANK;
diff --git a/drivers/mtd/spi-mem/spi_mem.c b/drivers/mtd/spi-mem/spi_mem.c
index 63ea7699b8..c43d5196c0 100644
--- a/drivers/mtd/spi-mem/spi_mem.c
+++ b/drivers/mtd/spi-mem/spi_mem.c
@@ -1,15 +1,16 @@
/*
- * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
-
-#include <libfdt.h>
+#include <inttypes.h>
+#include <stdint.h>
#include <drivers/spi_mem.h>
#include <lib/utils_def.h>
+#include <libfdt.h>
#define SPI_MEM_DEFAULT_SPEED_HZ 100000U
@@ -150,7 +151,7 @@ int spi_mem_exec_op(const struct spi_mem_op *op)
const struct spi_bus_ops *ops = spi_slave.ops;
int ret;
- VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%llx len:%x\n",
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%" PRIx64 " len:%x\n",
__func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
op->dummy.buswidth, op->data.buswidth,
op->addr.val, op->data.nbytes);
@@ -256,7 +257,7 @@ int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
mode |= SPI_TX_QUAD;
break;
default:
- WARN("spi-tx-bus-width %d not supported\n",
+ WARN("spi-tx-bus-width %u not supported\n",
fdt32_to_cpu(*cuint));
return -EINVAL;
}
@@ -274,7 +275,7 @@ int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
mode |= SPI_RX_QUAD;
break;
default:
- WARN("spi-rx-bus-width %d not supported\n",
+ WARN("spi-rx-bus-width %u not supported\n",
fdt32_to_cpu(*cuint));
return -EINVAL;
}
diff --git a/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h b/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h
deleted file mode 100644
index eaead7614e..0000000000
--- a/drivers/nxp/auth/csf_hdr_parser/csf_hdr.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef CSF_HDR_H
-#define CSF_HDR_H
-
-#include "caam.h"
-#include "hash.h"
-#include "rsa.h"
-
-/* Barker code size in bytes */
-#define CSF_BARKER_LEN 4 /* barker code length in ESBC uboot client */
- /* header */
-
-#ifdef CSF_HDR_CH3
-struct csf_hdr {
- uint8_t barker[CSF_BARKER_LEN]; /* 0x00 Barker code */
- uint32_t srk_tbl_off; /* 0x04 SRK Table Offset */
-
- struct {
- uint8_t num_srk; /* 0x08 No. of keys */
- uint8_t srk_sel; /* Key no. to be used */
- uint8_t reserve; /* 0x0a rseerved */
- } len_kr;
- uint8_t ie_flag;
-
- uint32_t uid_flag;
-
- uint32_t psign; /* 0x10 signature offset */
- uint32_t sign_len; /* 0x14 length of signature */
-
- union {
- struct {
- uint32_t sg_table_offset; /* 0x18 SG Table Offset */
- uint32_t sg_entries; /* 0x1c no of entries in SG */
- } sg_isbc;
- uint64_t img_addr; /* 64 bit pointer to ESBC Image */
- };
-
- union {
- struct {
- uint32_t img_size; /* ESBC client img size in bytes */
- uint32_t ie_key_sel;
- } img;
- uint64_t entry_point; /* 0x20-0x24 ESBC entry point */
- };
-
- uint32_t fsl_uid_0; /* 0x28 Freescale unique id 0 */
- uint32_t fsl_uid_1; /* 0x2c Freescale unique id 1 */
- uint32_t oem_uid_0; /* 0x30 OEM unique id 0 */
- uint32_t oem_uid_1; /* 0x34 OEM unique id 1 */
- uint32_t oem_uid_2; /* 0x38 OEM unique id 2 */
- uint32_t oem_uid_3; /* 0x3c OEM unique id 3 */
- uint32_t oem_uid_4; /* 0x40 OEM unique id 4 */
-
- uint32_t reserved[3]; /* 0x44 - 0x4f */
-};
-
-/* Srk table and key revocation check */
-#define UNREVOCABLE_KEY 8
-#define REVOC_KEY_ALIGN 7
-#define MAX_KEY_ENTRIES 8
-
-#else
-
-/* CSF header for Chassis 2 */
-struct csf_hdr {
- uint8_t barker[CSF_BARKER_LEN]; /* barker code */
- union {
- uint32_t pkey; /* public key offset */
- uint32_t srk_tbl_off;
- };
-
- union {
- uint32_t key_len; /* pub key length in bytes */
- struct {
- uint32_t srk_table_flag:8;
- uint32_t srk_sel:8;
- uint32_t num_srk:16;
- } len_kr;
- };
-
- uint32_t psign; /* signature offset */
- uint32_t sign_len; /* length of the signature in bytes */
-
- /* SG Table used by ISBC header */
- union {
- struct {
- uint32_t sg_table_offset; /* 0x14 SG Table Offset */
- uint32_t sg_entries; /* no of entries in SG table */
- } sg_isbc;
- struct {
- uint32_t reserved1; /* Reserved field */
- uint32_t img_size; /* ESBC img size in bytes */
- } img;
- };
-
- uint32_t entry_point; /* ESBC client entry point */
- uint32_t reserved2; /* Scatter gather flag */
- uint32_t uid_flag;
- uint32_t fsl_uid_0;
- uint32_t oem_uid_0;
- uint32_t reserved3[2];
- uint32_t fsl_uid_1;
- uint32_t oem_uid_1;
-
- /* The entries below aren't present in ISBC header */
- uint64_t img_addr; /* 64 bit pointer to ESBC Image */
- uint32_t ie_flag;
- uint32_t ie_key_sel;
-};
-
-/* Srk table and key revocation check */
-#define UNREVOCABLE_KEY 4
-#define REVOC_KEY_ALIGN 3
-#define MAX_KEY_ENTRIES 4
-
-#endif
-
-struct srk_table {
- uint32_t key_len;
- uint8_t pkey[2 * RSA_4K_KEY_SZ_BYTES];
-};
-
-/*
- * This struct contains the following fields
- * length of the segment
- * Destination Target ID
- * source address
- * destination address
- */
-struct sg_table {
- uint32_t len; /* Length of Image */
- uint32_t res1;
- union {
- uint64_t src_addr; /* SRC Address of Image */
- struct {
- uint32_t src_addr;
- uint32_t dst_addr;
- } img;
- };
-};
-
-int validate_esbc_header(void *img_hdr, void **img_key, uint32_t *key_len,
- void **img_sign, uint32_t *sign_len,
- enum sig_alg *algo);
-
-int calc_img_hash(struct csf_hdr *hdr, void *img_addr, uint32_t img_size,
- uint8_t *img_hash, uint32_t *hash_len);
-
-#endif
diff --git a/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk b/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk
index d518dbba9d..1af51f8090 100644
--- a/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk
+++ b/drivers/nxp/auth/csf_hdr_parser/csf_hdr.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,7 +9,7 @@ CSF_HDR_SOURCES := $(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/csf_hdr_parser.c
CSF_HDR_SOURCES += $(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/plat_img_parser.c
-PLAT_INCLUDES += -I$(PLAT_DRIVERS_PATH)/auth/csf_hdr_parser/
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/auth/csf_hdr_parser/
$(eval $(call add_define, CSF_HEADER_PREPENDED))
diff --git a/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c b/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c
index b878082aee..4f31c6e356 100644
--- a/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c
+++ b/drivers/nxp/auth/csf_hdr_parser/csf_hdr_parser.c
@@ -38,7 +38,7 @@ static const uint8_t barker_code[CSF_BARKER_LEN] = { 0x68, 0x39, 0x27, 0x81 };
/* Flag to indicate if values are there in rotpk_hash_table */
bool rotpk_not_dpld = true;
-uint8_t rotpk_hash_table[MAX_KEY_ENTRIES][SHA256_BYTES];
+uint8_t rotpk_hash_table[MAX_KEY_ENTRIES][SHA256_BYTES] __aligned(CACHE_WRITEBACK_GRANULE);
uint32_t num_rotpk_hash_entries;
/*
diff --git a/drivers/nxp/auth/tbbr/tbbr_cot.c b/drivers/nxp/auth/tbbr/tbbr_cot.c
index bb21fa04cb..ac4595f024 100644
--- a/drivers/nxp/auth/tbbr/tbbr_cot.c
+++ b/drivers/nxp/auth/tbbr/tbbr_cot.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
*
* Copyright 2020 NXP
*
@@ -8,6 +8,7 @@
#include <stddef.h>
+#include <common/tbbr/cot_def.h>
#include <drivers/auth/auth_mod.h>
#if USE_TBBR_DEFS
diff --git a/drivers/nxp/console/16550_console.S b/drivers/nxp/console/16550_console.S
index 044d3d0740..b5617a3e8f 100644
--- a/drivers/nxp/console/16550_console.S
+++ b/drivers/nxp/console/16550_console.S
@@ -167,7 +167,7 @@ func nxp_console_16550_register
register_16550:
mov x0, x6
mov x30, x7
- finish_console_register 16550 putc=1, getc=1, flush=1
+ finish_console_register 16550 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
ret x7
diff --git a/drivers/nxp/console/console.mk b/drivers/nxp/console/console.mk
index 22d13360e5..6174650d1f 100644
--- a/drivers/nxp/console/console.mk
+++ b/drivers/nxp/console/console.mk
@@ -14,7 +14,7 @@ ifeq (${ADD_CONSOLE},)
ADD_CONSOLE := 1
-PLAT_INCLUDES += -I$(PLAT_DRIVERS_PATH)/console
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/console
ifeq ($(CONSOLE), NS16550)
NXP_CONSOLE := NS16550
diff --git a/drivers/nxp/console/plat_console.h b/drivers/nxp/console/plat_console.h
deleted file mode 100644
index 8b1b23a041..0000000000
--- a/drivers/nxp/console/plat_console.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef PLAT_CONSOLE_H
-#define PLAT_CONSOLE_H
-
-#include <stdint.h>
-#include <drivers/console.h>
-
-#if (NXP_CONSOLE == NS16550)
-/*
- * NXP specific UART - 16550 configuration
- *
- * Initialize a NXP 16550 console instance and register it with the console
- * framework. The |console| pointer must point to storage that will be valid
- * for the lifetime of the console, such as a global or static local variable.
- * Its contents will be reinitialized from scratch.
- * When |clock| has a value of 0, the UART will *not* be initialised. This
- * means the UART should already be enabled and the baudrate and clock setup
- * should have been done already, either by platform specific code or by
- * previous firmware stages. The |baud| parameter will be ignored in this
- * case as well.
- */
-int nxp_console_16550_register(uintptr_t baseaddr, uint32_t clock,
- uint32_t baud, console_t *console);
-#endif
-/*
- * Function to initialize platform's console
- * and register with console framework
- */
-void plat_console_init(uintptr_t nxp_console_addr, uint32_t uart_clk_div,
- uint32_t baud);
-
-#endif
diff --git a/drivers/nxp/crypto/caam/caam.mk b/drivers/nxp/crypto/caam/caam.mk
index 548c7b1476..f929f5395d 100644
--- a/drivers/nxp/crypto/caam/caam.mk
+++ b/drivers/nxp/crypto/caam/caam.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2020-2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,11 +8,10 @@
ifeq (${ADD_CAAM},)
ADD_CAAM := 1
-CAAM_DRIVER_PATH := drivers/nxp/crypto/caam
-CAAM_DRIVER_SOURCES += $(wildcard $(CAAM_DRIVER_PATH)/src/*.c)
+CAAM_DRIVER_SOURCES += $(wildcard $(PLAT_DRIVERS_PATH)/crypto/caam/src/*.c)
-PLAT_INCLUDES += -I$(CAAM_DRIVER_PATH)/include
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/crypto/caam
ifeq (${BL_COMM_CRYPTO_NEEDED},yes)
BL_COMMON_SOURCES += ${CAAM_DRIVER_SOURCES}
diff --git a/drivers/nxp/crypto/caam/include/caam.h b/drivers/nxp/crypto/caam/include/caam.h
deleted file mode 100644
index 580e133fc0..0000000000
--- a/drivers/nxp/crypto/caam/include/caam.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef CAAM_H
-#define CAAM_H
-
-#include "caam_io.h"
-#include "sec_jr_driver.h"
-
-
-/* Job ring 3 is reserved for usage by sec firmware */
-#define DEFAULT_JR 3
-
-#if defined(CONFIG_CHASSIS_3_2) || defined(CONFIG_CHASSIS_2)
-#define CAAM_JR0_OFFSET 0x10000
-#define CAAM_JR1_OFFSET 0x20000
-#define CAAM_JR2_OFFSET 0x30000
-#define CAAM_JR3_OFFSET 0x40000
-#endif
-
-enum sig_alg {
- RSA,
- ECC
-};
-
-/* This function does basic SEC Initialization */
-int sec_init(uintptr_t nxp_caam_addr);
-int config_sec_block(void);
-uintptr_t get_caam_addr(void);
-
-/* This function is used to submit jobs to JR */
-int run_descriptor_jr(struct job_descriptor *desc);
-
-/* This function is used to instatiate the HW RNG is already not instantiated */
-int hw_rng_instantiate(void);
-
-/* This function is used to return random bytes of byte_len from HW RNG */
-int get_rand_bytes_hw(uint8_t *bytes, int byte_len);
-
-/* This function is used to set the hw unique key from HW CAAM */
-int get_hw_unq_key_blob_hw(uint8_t *hw_key, int size);
-
-/* This function is used to fetch random number from
- * CAAM of length either of 4 bytes or 8 bytes depending
- * rngWidth value.
- */
-unsigned long long get_random(int rngWidth);
-
-#endif /* CAAM_H */
diff --git a/drivers/nxp/crypto/caam/include/caam_io.h b/drivers/nxp/crypto/caam/include/caam_io.h
deleted file mode 100644
index 4fdb04d6df..0000000000
--- a/drivers/nxp/crypto/caam/include/caam_io.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef CAAM_IO_H
-#define CAAM_IO_H
-
-#include <endian.h>
-#include <lib/mmio.h>
-
-typedef unsigned long long phys_addr_t;
-typedef unsigned long long phys_size_t;
-
-/* Return higher 32 bits of physical address */
-#define PHYS_ADDR_HI(phys_addr) \
- (uint32_t)(((uint64_t)phys_addr) >> 32)
-
-/* Return lower 32 bits of physical address */
-#define PHYS_ADDR_LO(phys_addr) \
- (uint32_t)(((uint64_t)phys_addr) & 0xFFFFFFFF)
-
-#ifdef NXP_SEC_BE
-#define sec_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define sec_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#define sec_in64(addr) ( \
- ((uint64_t)sec_in32((uintptr_t)(addr)) << 32) | \
- (sec_in32(((uintptr_t)(addr)) + 4)))
-#define sec_out64(addr, val) ({ \
- sec_out32(((uintptr_t)(addr)), (uint32_t)((val) >> 32)); \
- sec_out32(((uintptr_t)(addr)) + 4, (uint32_t)(val)); })
-#elif defined(NXP_SEC_LE)
-#define sec_in32(a) mmio_read_32((uintptr_t)(a))
-#define sec_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
-#define sec_in64(addr) ( \
- ((uint64_t)sec_in32((uintptr_t)(addr) + 4) << 32) | \
- (sec_in32((uintptr_t)(addr))))
-#define sec_out64(addr, val) ({ \
- sec_out32(((uintptr_t)(addr)) + 4, (uint32_t)((val) >> 32)); \
- sec_out32(((uintptr_t)(addr)), (uint32_t)(val)); })
-#else
-#error Please define CCSR SEC register endianness
-#endif
-
-static inline void *ptov(phys_addr_t *ptr)
-{
- return (void *)ptr;
-}
-
-static inline phys_addr_t *vtop(void *ptr)
-{
- return (phys_addr_t *)ptr;
-}
-#endif /* CAAM_IO_H */
diff --git a/drivers/nxp/crypto/caam/include/hash.h b/drivers/nxp/crypto/caam/include/hash.h
deleted file mode 100644
index 946087d468..0000000000
--- a/drivers/nxp/crypto/caam/include/hash.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef __HASH_H__
-#define __HASH_H__
-
-#include <stdbool.h>
-
-/* List of hash algorithms */
-enum hash_algo {
- SHA1 = 0,
- SHA256
-};
-
-/* number of bytes in the SHA256-256 digest */
-#define SHA256_DIGEST_SIZE 32
-
-/*
- * number of words in the digest - Digest is kept internally
- * as 8 32-bit words
- */
-#define _SHA256_DIGEST_LENGTH 8
-
-/*
- * block length - A block, treated as a sequence of
- * 32-bit words
- */
-#define SHA256_BLOCK_LENGTH 16
-
-/* number of bytes in the block */
-#define SHA256_DATA_SIZE 64
-
-#define MAX_SG 12
-
-struct sg_entry {
-#if defined(NXP_SEC_LE)
- uint32_t addr_lo; /* Memory Address - lo */
- uint32_t addr_hi; /* Memory Address of start of buffer - hi */
-#else
- uint32_t addr_hi; /* Memory Address of start of buffer - hi */
- uint32_t addr_lo; /* Memory Address - lo */
-#endif
-
- uint32_t len_flag; /* Length of the data in the frame */
-#define SG_ENTRY_LENGTH_MASK 0x3FFFFFFF
-#define SG_ENTRY_EXTENSION_BIT 0x80000000
-#define SG_ENTRY_FINAL_BIT 0x40000000
- uint32_t bpid_offset;
-#define SG_ENTRY_BPID_MASK 0x00FF0000
-#define SG_ENTRY_BPID_SHIFT 16
-#define SG_ENTRY_OFFSET_MASK 0x00001FFF
-#define SG_ENTRY_OFFSET_SHIFT 0
-};
-
-/*
- * SHA256-256 context
- * contain the following fields
- * State
- * count low
- * count high
- * block data buffer
- * index to the buffer
- */
-struct hash_ctx {
- struct sg_entry sg_tbl[MAX_SG];
- uint32_t hash_desc[64];
- uint8_t hash[SHA256_DIGEST_SIZE];
- uint32_t sg_num;
- uint32_t len;
- uint8_t *data;
- enum hash_algo algo;
- bool active;
-};
-
-int hash_init(enum hash_algo algo, void **ctx);
-int hash_update(enum hash_algo algo, void *context, void *data_ptr,
- unsigned int data_len);
-int hash_final(enum hash_algo algo, void *context, void *hash_ptr,
- unsigned int hash_len);
-
-#endif
diff --git a/drivers/nxp/crypto/caam/include/jobdesc.h b/drivers/nxp/crypto/caam/include/jobdesc.h
deleted file mode 100644
index 5921f7be31..0000000000
--- a/drivers/nxp/crypto/caam/include/jobdesc.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef __JOBDESC_H
-#define __JOBDESC_H
-
-#include <rsa.h>
-
-#define DESC_LEN_MASK 0x7f
-#define DESC_START_SHIFT 16
-
-#define KEY_BLOB_SIZE 32
-#define MAC_SIZE 16
-
-#define KEY_IDNFR_SZ_BYTES 16
-#define CLASS_SHIFT 25
-#define CLASS_2 (0x02 << CLASS_SHIFT)
-
-#define CMD_SHIFT 27
-#define CMD_OPERATION (U(0x10) << CMD_SHIFT)
-
-#define OP_TYPE_SHIFT 24
-#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT)
-
-/* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */
-#define OP_PCLID_SHIFT 16
-#define OP_PCLID_BLOB (0x0d << OP_PCLID_SHIFT)
-
-#define BLOB_PROTO_INFO 0x00000002
-
-uint32_t desc_length(uint32_t *desc);
-
-int cnstr_rng_jobdesc(uint32_t *desc, uint32_t state_handle,
- uint32_t *add_inp, uint32_t add_ip_len,
- uint8_t *out_data, uint32_t len);
-
-int cnstr_rng_instantiate_jobdesc(uint32_t *desc);
-
-/* Construct descriptor to generate hw key blob */
-int cnstr_hw_encap_blob_jobdesc(uint32_t *desc,
- uint8_t *key_idnfr, uint32_t key_sz,
- uint32_t key_class, uint8_t *plain_txt,
- uint32_t in_sz, uint8_t *enc_blob,
- uint32_t out_sz, uint32_t operation);
-
-void cnstr_hash_jobdesc(uint32_t *desc, uint8_t *msg, uint32_t msgsz,
- uint8_t *digest);
-
-void cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
- struct pk_in_params *pkin, uint8_t *out,
- uint32_t out_siz);
-#endif
diff --git a/drivers/nxp/crypto/caam/include/jr_driver_config.h b/drivers/nxp/crypto/caam/include/jr_driver_config.h
deleted file mode 100644
index f25c42e4d1..0000000000
--- a/drivers/nxp/crypto/caam/include/jr_driver_config.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef _JR_DRIVER_CONFIG_H_
-#define _JR_DRIVER_CONFIG_H_
-
-/* Helper defines */
-
- /* Define used for setting a flag on */
-#define ON 1
- /* Define used for setting a flag off */
-#define OFF 0
-
- /* SEC is configured to start work in polling mode, */
-#define SEC_STARTUP_POLLING_MODE 0
-/*
- * SEC is configured to start work in interrupt mode,
- * when configured for NAPI notification style.
- */
-#define SEC_STARTUP_INTERRUPT_MODE 1
-
-/*
- * SEC driver will use ONLY interrupts to receive notifications
- * for processed packets from SEC engine hardware.
- */
-#define SEC_NOTIFICATION_TYPE_IRQ 1
-/*
- * SEC driver will use ONLY polling to receive notifications
- * for processed packets from SEC engine hardware.
- */
-#define SEC_NOTIFICATION_TYPE_POLL 2
-
-/*
- * Determines how SEC user space driver will receive notifications
- * for processed packets from SEC engine.
- * Valid values are: #SEC_NOTIFICATION_TYPE_POLL, #SEC_NOTIFICATION_TYPE_IRQ
- */
-#define SEC_NOTIFICATION_TYPE SEC_NOTIFICATION_TYPE_POLL
-
- /* Maximum number of job rings supported by SEC hardware */
-#define MAX_SEC_JOB_RINGS 1
-
-/*
- * Size of cryptographic context that is used directly in communicating
- * with SEC device.
- * SEC device works only with physical addresses. This is the maximum size
- * for a SEC descriptor ( = 64 words).
- */
-
-#define SEC_CRYPTO_DESCRIPTOR_SIZE 256
-
-/*
- * Size of job descriptor submitted to SEC device for each packet to be
- * processed.
- * Job descriptor contains 3 DMA address pointers:
- * - to shared descriptor, to input buffer and to output buffer.
- * The job descriptor contains other SEC specific commands as well:
- * - HEADER command, SEQ IN PTR command SEQ OUT PTR command and opaque
- * data, each measuring 4 bytes.
- * Job descriptor size, depending on physical address representation:
- * - 32 bit - size is 28 bytes - cacheline-aligned size is 64 bytes
- * - 36 bit - size is 40 bytes - cacheline-aligned size is 64 bytes
- * @note: Job descriptor must be cacheline-aligned to ensure efficient memory
- * access.
- * @note: If other format is used for job descriptor, then the size must be
- * revised.
- */
-
-#define SEC_JOB_DESCRIPTOR_SIZE 64
-
-/*
- * Size of one entry in the input ring of a job ring.
- * Input ring contains pointers to job descriptors.
- * The memory used for an input ring and output ring must be physically
- * contiguous.
- */
-
-#define SEC_JOB_INPUT_RING_ENTRY_SIZE sizeof(phys_addr_t)
-
-/*
- * Size of one entry in the output ring of a job ring.
- * Output ring entry is a pointer to a job descriptor followed by a 4 byte
- * status word.
- * The memory used for an input ring and output ring must be physically
- * contiguous.
- * @note If desired to use also the optional SEQ OUT indication in output
- * ring entries, then 4 more bytes must be added to the size.
- */
-
-#define SEC_JOB_OUTPUT_RING_ENTRY_SIZE (SEC_JOB_INPUT_RING_ENTRY_SIZE + 4)
-
- /* DMA memory required for an input ring of a job ring. */
-#define SEC_DMA_MEM_INPUT_RING_SIZE \
- ((SEC_JOB_INPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE))
-
-/*
- * DMA memory required for an output ring of a job ring.
- * Required extra 4 byte for status word per each entry.
- */
-#define SEC_DMA_MEM_OUTPUT_RING_SIZE \
- ((SEC_JOB_OUTPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE))
-
- /* DMA memory required for descriptors of a job ring. */
-#define SEC_DMA_MEM_DESCRIPTORS \
- ((SEC_CRYPTO_DESCRIPTOR_SIZE)*(SEC_JOB_RING_SIZE))
-
- /* DMA memory required for a job ring, including both input output rings. */
-#define SEC_DMA_MEM_JOB_RING_SIZE \
- ((SEC_DMA_MEM_INPUT_RING_SIZE) + \
- (SEC_DMA_MEM_OUTPUT_RING_SIZE))
-
-/*
- * When calling sec_init() UA will provide an area of virtual memory
- * of size #SEC_DMA_MEMORY_SIZE to be used internally by the driver
- * to allocate data (like SEC descriptors) that needs to be passed to
- * SEC device in physical addressing and later on retrieved from SEC device.
- * At initialization the UA provides specialized ptov/vtop functions/macros to
- * translate addresses allocated from this memory area.
- */
-#define SEC_DMA_MEMORY_SIZE \
- ((SEC_DMA_MEM_JOB_RING_SIZE) * (MAX_SEC_JOB_RINGS))
-
-/*
- * SEC DEVICE related configuration.
-
- * Enable/Disable logging support at compile time.
- * Valid values:
- * ON - enable logging
- * OFF - disable logging
- * The messages are logged at stdout.
- */
-
-#define SEC_DRIVER_LOGGING OFF
-
-/*
- * Configure logging level at compile time.
- * Valid values:
- * SEC_DRIVER_LOG_ERROR - log only errors
- * SEC_DRIVER_LOG_INFO - log errors and info messages
- * SEC_DRIVER_LOG_DEBUG - log errors, info and debug messages
- */
-
-#define SEC_DRIVER_LOGGING_LEVEL SEC_DRIVER_LOG_DEBUG
-
-/*
- * SEC JOB RING related configuration.
-
- * Configure the size of the JOB RING.
- * The maximum size of the ring is hardware limited to 1024.
- * However the number of packets in flight in a time interval of
- * 1ms can be calculated
- * from the traffic rate (Mbps) and packet size.
- * Here it was considered a packet size of 40 bytes.
- * @note Round up to nearest power of 2 for optimized update
- * of producer/consumer indexes of each job ring
- * \todo Should set to 750, according to the calculation above, but
- * the JR size must be power of 2, thus the next closest value must
- * be chosen (i.e. 512 since 1024 is not available)
- * For firmware choose this to be 16
- */
-
-#define SEC_JOB_RING_SIZE 16
-
-/*
- * Interrupt coalescing related configuration.
- * NOTE: SEC hardware enabled interrupt
- * coalescing is not supported on SEC version 3.1!
- * SEC version 4.4 has support for interrupt
- * coalescing.
- */
-
-#if SEC_NOTIFICATION_TYPE != SEC_NOTIFICATION_TYPE_POLL
-
-#define SEC_INT_COALESCING_ENABLE ON
-/*
- * Interrupt Coalescing Descriptor Count Threshold.
- * While interrupt coalescing is enabled (ICEN=1), this value determines
- * how many Descriptors are completed before raising an interrupt.
- * Valid values for this field are from 0 to 255.
- * Note that a value of 1 functionally defeats the advantages of interrupt
- * coalescing since the threshold value is reached each time that a
- * Job Descriptor is completed. A value of 0 is treated in the same
- * manner as a value of 1.
- *
- */
-#define SEC_INTERRUPT_COALESCING_DESCRIPTOR_COUNT_THRESH 10
-
-/*
- * Interrupt Coalescing Timer Threshold.
- * While interrupt coalescing is enabled (ICEN=1), this value determines the
- * maximum amount of time after processing a Descriptor before raising an
- * interrupt.
- * The threshold value is represented in units equal to 64 CAAM interface
- * clocks. Valid values for this field are from 1 to 65535.
- * A value of 0 results in behavior identical to that when interrupt
- * coalescing is disabled.
- */
-#define SEC_INTERRUPT_COALESCING_TIMER_THRESH 100
-#endif /* SEC_NOTIFICATION_TYPE_POLL */
-
-#endif /* _JR_DRIVER_CONFIG_H_ */
diff --git a/drivers/nxp/crypto/caam/include/rsa.h b/drivers/nxp/crypto/caam/include/rsa.h
deleted file mode 100644
index bd5dc71143..0000000000
--- a/drivers/nxp/crypto/caam/include/rsa.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef _RSA_H__
-#define _RSA_H__
-
-/* RSA key size defines */
-#define RSA_4K_KEY_SZ 4096
-#define RSA_4K_KEY_SZ_BYTES (RSA_4K_KEY_SZ/8)
-#define RSA_2K_KEY_SZ 2048
-#define RSA_2K_KEY_SZ_BYTES (RSA_2K_KEY_SZ/8)
-#define RSA_1K_KEY_SZ 1024
-#define RSA_1K_KEY_SZ_BYTES (RSA_1K_KEY_SZ/8)
-
-#define SHA256_BYTES (256/8)
-
-struct pk_in_params {
- uint8_t *e;
- uint32_t e_siz;
- uint8_t *n;
- uint32_t n_siz;
- uint8_t *a;
- uint32_t a_siz;
- uint8_t *b;
- uint32_t b_siz;
-};
-
-struct rsa_context {
- struct pk_in_params pkin;
-};
-
-int rsa_verify_signature(void *hash_ptr, unsigned int hash_len,
- void *sig_ptr, unsigned int sig_len,
- void *pk_ptr, unsigned int pk_len);
-
-#endif
diff --git a/drivers/nxp/crypto/caam/include/sec_hw_specific.h b/drivers/nxp/crypto/caam/include/sec_hw_specific.h
deleted file mode 100644
index a82a1a019b..0000000000
--- a/drivers/nxp/crypto/caam/include/sec_hw_specific.h
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef _SEC_HW_SPECIFIC_H_
-#define _SEC_HW_SPECIFIC_H_
-
-#include "caam.h"
-#include "sec_jr_driver.h"
-
- /* DEFINES AND MACROS */
-
-/* Used to retry resetting a job ring in SEC hardware. */
-#define SEC_TIMEOUT 100000
-
-/*
- * Offset to the registers of a job ring.
- *Is different for each job ring.
- */
-#define CHAN_BASE(jr) ((phys_addr_t)(jr)->register_base_addr)
-
-#define unlikely(x) __builtin_expect(!!(x), 0)
-
-#define SEC_JOB_RING_IS_FULL(pi, ci, ring_max_size, ring_threshold) \
- ((((pi) + 1 + ((ring_max_size) - (ring_threshold))) & \
- (ring_max_size - 1)) == ((ci)))
-
-#define SEC_CIRCULAR_COUNTER(x, max) (((x) + 1) & (max - 1))
-
- /* Struct representing various job ring registers */
-struct jobring_regs {
-#ifdef NXP_SEC_BE
- unsigned int irba_h;
- unsigned int irba_l;
-#else
- unsigned int irba_l;
- unsigned int irba_h;
-#endif
- unsigned int rsvd1;
- unsigned int irs;
- unsigned int rsvd2;
- unsigned int irsa;
- unsigned int rsvd3;
- unsigned int irja;
-#ifdef NXP_SEC_BE
- unsigned int orba_h;
- unsigned int orba_l;
-#else
- unsigned int orba_l;
- unsigned int orba_h;
-#endif
- unsigned int rsvd4;
- unsigned int ors;
- unsigned int rsvd5;
- unsigned int orjr;
- unsigned int rsvd6;
- unsigned int orsf;
- unsigned int rsvd7;
- unsigned int jrsta;
- unsigned int rsvd8;
- unsigned int jrint;
- unsigned int jrcfg0;
- unsigned int jrcfg1;
- unsigned int rsvd9;
- unsigned int irri;
- unsigned int rsvd10;
- unsigned int orwi;
- unsigned int rsvd11;
- unsigned int jrcr;
-};
-
- /* Offsets representing common SEC Registers */
-#define SEC_REG_MCFGR_OFFSET 0x0004
-#define SEC_REG_SCFGR_OFFSET 0x000C
-#define SEC_REG_JR0ICIDR_MS_OFFSET 0x0010
-#define SEC_REG_JR0ICIDR_LS_OFFSET 0x0014
-#define SEC_REG_JR1ICIDR_MS_OFFSET 0x0018
-#define SEC_REG_JR1ICIDR_LS_OFFSET 0x001C
-#define SEC_REG_JR2ICIDR_MS_OFFSET 0x0020
-#define SEC_REG_JR2ICIDR_LS_OFFSET 0x0024
-#define SEC_REG_JR3ICIDR_MS_OFFSET 0x0028
-#define SEC_REG_JR3ICIDR_LS_OFFSET 0x002C
-#define SEC_REG_JRSTARTR_OFFSET 0x005C
-#define SEC_REG_CTPR_MS_OFFSET 0x0FA8
-
- /* Offsets representing various RNG registers */
-#define RNG_REG_RTMCTL_OFFSET 0x0600
-#define RNG_REG_RTSDCTL_OFFSET 0x0610
-#define RNG_REG_RTFRQMIN_OFFSET 0x0618
-#define RNG_REG_RTFRQMAX_OFFSET 0x061C
-#define RNG_REG_RDSTA_OFFSET 0x06C0
-#define ALG_AAI_SH_SHIFT 4
-
- /* SEC Registers Bitmasks */
-#define MCFGR_PS_SHIFT 16
-#define MCFGR_AWCACHE_SHIFT 8
-#define MCFGR_AWCACHE_MASK (0xF << MCFGR_AWCACHE_SHIFT)
-#define MCFGR_ARCACHE_SHIFT 12
-#define MCFGR_ARCACHE_MASK (0xF << MCFGR_ARCACHE_SHIFT)
-
-#define SCFGR_RNGSH0 0x00000200
-#define SCFGR_VIRT_EN 0x00008000
-
-#define JRICID_MS_LICID 0x80000000
-#define JRICID_MS_LAMTD 0x00020000
-#define JRICID_MS_AMTDT 0x00010000
-#define JRICID_MS_TZ 0x00008000
-#define JRICID_LS_SDID_MASK 0x00000FFF
-#define JRICID_LS_NSEQID_MASK 0x0FFF0000
-#define JRICID_LS_NSEQID_SHIFT 16
-#define JRICID_LS_SEQID_MASK 0x00000FFF
-
-#define JRSTARTR_STARTJR0 0x00000001
-#define JRSTARTR_STARTJR1 0x00000002
-#define JRSTARTR_STARTJR2 0x00000004
-#define JRSTARTR_STARTJR3 0x00000008
-
-#define CTPR_VIRT_EN_POR 0x00000002
-#define CTPR_VIRT_EN_INC 0x00000001
-
- /* RNG RDSTA bitmask */
-#define RNG_STATE0_HANDLE_INSTANTIATED 0x00000001
-#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */
- /* use von Neumann data in both entropy shifter and statistical checker */
-#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0
- /* use raw data in both entropy shifter and statistical checker */
-#define RTMCTL_SAMP_MODE_RAW_ES_SC 1
- /* use von Neumann data in entropy shifter, raw data in statistical checker */
-#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2
- /* invalid combination */
-#define RTMCTL_SAMP_MODE_INVALID 3
-#define RTSDCTL_ENT_DLY_MIN 3200
-#define RTSDCTL_ENT_DLY_MAX 12800
-#define RTSDCTL_ENT_DLY_SHIFT 16
-#define RTSDCTL_ENT_DLY_MASK (U(0xffff) << RTSDCTL_ENT_DLY_SHIFT)
-#define RTFRQMAX_DISABLE (1 << 20)
-
- /* Constants for error handling on job ring */
-#define JR_REG_JRINT_ERR_TYPE_SHIFT 8
-#define JR_REG_JRINT_ERR_ORWI_SHIFT 16
-#define JR_REG_JRINIT_JRE_SHIFT 1
-
-#define JRINT_JRE (1 << JR_REG_JRINIT_JRE_SHIFT)
-#define JRINT_ERR_WRITE_STATUS (1 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_BAD_INPUT_BASE (3 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_BAD_OUTPUT_BASE (4 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_WRITE_2_IRBA (5 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_WRITE_2_ORBA (6 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_RES_B4_HALT (7 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_REM_TOO_MANY (8 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_ADD_TOO_MANY (9 << JR_REG_JRINT_ERR_TYPE_SHIFT)
-#define JRINT_ERR_HALT_MASK 0x0C
-#define JRINT_ERR_HALT_INPROGRESS 0x04
-#define JRINT_ERR_HALT_COMPLETE 0x08
-
-#define JR_REG_JRCR_VAL_RESET 0x00000001
-
-#define JR_REG_JRCFG_LO_ICTT_SHIFT 0x10
-#define JR_REG_JRCFG_LO_ICDCT_SHIFT 0x08
-#define JR_REG_JRCFG_LO_ICEN_EN 0x02
-#define JR_REG_JRCFG_LO_IMSK_EN 0x01
-
- /* Constants for Descriptor Processing errors */
-#define SEC_HW_ERR_SSRC_NO_SRC 0x00
-#define SEC_HW_ERR_SSRC_CCB_ERR 0x02
-#define SEC_HW_ERR_SSRC_JMP_HALT_U 0x03
-#define SEC_HW_ERR_SSRC_DECO 0x04
-#define SEC_HW_ERR_SSRC_JR 0x06
-#define SEC_HW_ERR_SSRC_JMP_HALT_COND 0x07
-
-#define SEC_HW_ERR_DECO_HFN_THRESHOLD 0xF1
-#define SEC_HW_ERR_CCB_ICV_CHECK_FAIL 0x0A
-
- /* Macros for extracting error codes for the job ring */
-
-#define JR_REG_JRINT_ERR_TYPE_EXTRACT(value) \
- ((value) & 0x00000F00)
-
-#define JR_REG_JRINT_ERR_ORWI_EXTRACT(value) \
- (((value) & 0x3FFF0000) >> \
- JR_REG_JRINT_ERR_ORWI_SHIFT)
-
-#define JR_REG_JRINT_JRE_EXTRACT(value) \
- ((value) & JRINT_JRE)
-
- /* Macros for manipulating JR registers */
-typedef union {
- uint64_t m_whole;
- struct {
-#ifdef NXP_SEC_BE
- uint32_t high;
- uint32_t low;
-#else
- uint32_t low;
- uint32_t high;
-#endif
- } m_halves;
-} ptr_addr_t;
-
-#if defined(CONFIG_PHYS_64BIT)
-#define sec_read_addr(a) sec_in64((a))
-#define sec_write_addr(a, v) sec_out64((a), (v))
-#else
-#define sec_read_addr(a) sec_in32((a))
-#define sec_write_addr(a, v) sec_out32((a), (v))
-#endif
-
-#define JR_REG(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET)
-#define JR_REG_LO(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET_LO)
-
-#define GET_JR_REG(name, jr) (sec_in32(JR_REG(name, (jr))))
-#define GET_JR_REG_LO(name, jr) (sec_in32(JR_REG_LO(name, (jr))))
-
-#define SET_JR_REG(name, jr, val) \
- (sec_out32(JR_REG(name, (jr)), (val)))
-
-#define SET_JR_REG_LO(name, jr, val) \
- (sec_out32(JR_REG_LO(name, (jr)), (val)))
-
- /* STRUCTURES AND OTHER TYPEDEFS */
- /* Lists the possible states for a job ring. */
-typedef enum sec_job_ring_state_e {
- SEC_JOB_RING_STATE_STARTED, /* Job ring is initialized */
- SEC_JOB_RING_STATE_RESET, /* Job ring reset is in progres */
-} sec_job_ring_state_t;
-
-struct sec_job_ring_t {
- /*
- * Consumer index for job ring (jobs array).
- * @note: cidx and pidx are accessed from
- * different threads.
- * Place the cidx and pidx inside the structure
- * so that they lay on different cachelines, to
- * avoid false sharing between threads when the
- * threads run on different cores!
- */
- uint32_t cidx;
-
- /* Producer index for job ring (jobs array) */
- uint32_t pidx;
-
- /* Ring of input descriptors. Size of array is power of 2 to allow
- * fast update of producer/consumer indexes with bitwise operations.
- */
- phys_addr_t *input_ring;
-
- /* Ring of output descriptors. */
- struct sec_outring_entry *output_ring;
-
- /* The file descriptor used for polling for interrupts notifications */
- uint32_t irq_fd;
-
- /* Model used by SEC Driver to receive notifications from SEC.
- * Can be either of the three:
- * #SEC_NOTIFICATION_TYPE_IRQ or
- * #SEC_NOTIFICATION_TYPE_POLL
- */
- uint32_t jr_mode;
- /* Base address for SEC's register memory for this job ring. */
- void *register_base_addr;
- /* notifies if coelescing is enabled for the job ring */
- uint8_t coalescing_en;
- /* The state of this job ring */
- sec_job_ring_state_t jr_state;
-};
-
- /* Forward structure declaration */
-typedef struct sec_job_ring_t sec_job_ring_t;
-
-struct sec_outring_entry {
- phys_addr_t desc; /* Pointer to completed descriptor */
- uint32_t status; /* Status for completed descriptor */
-} __packed;
-
- /* Lists the states possible for the SEC user space driver. */
-typedef enum sec_driver_state_e {
- SEC_DRIVER_STATE_IDLE, /*< Driver not initialized */
- SEC_DRIVER_STATE_STARTED, /*< Driver initialized and */
- SEC_DRIVER_STATE_RELEASE, /*< Driver release is in progress */
-} sec_driver_state_t;
-
- /* Union describing the possible error codes that */
- /* can be set in the descriptor status word */
-
-union hw_error_code {
- uint32_t error;
- union {
- struct {
- uint32_t ssrc:4;
- uint32_t ssed_val:28;
- } __packed value;
- struct {
- uint32_t ssrc:4;
- uint32_t res:28;
- } __packed no_status_src;
- struct {
- uint32_t ssrc:4;
- uint32_t jmp:1;
- uint32_t res:11;
- uint32_t desc_idx:8;
- uint32_t cha_id:4;
- uint32_t err_id:4;
- } __packed ccb_status_src;
- struct {
- uint32_t ssrc:4;
- uint32_t jmp:1;
- uint32_t res:11;
- uint32_t desc_idx:8;
- uint32_t offset:8;
- } __packed jmp_halt_user_src;
- struct {
- uint32_t ssrc:4;
- uint32_t jmp:1;
- uint32_t res:11;
- uint32_t desc_idx:8;
- uint32_t desc_err:8;
- } __packed deco_src;
- struct {
- uint32_t ssrc:4;
- uint32_t res:17;
- uint32_t naddr:3;
- uint32_t desc_err:8;
- } __packed jr_src;
- struct {
- uint32_t ssrc:4;
- uint32_t jmp:1;
- uint32_t res:11;
- uint32_t desc_idx:8;
- uint32_t cond:8;
- } __packed jmp_halt_cond_src;
- } __packed error_desc;
-} __packed;
-
- /* FUNCTION PROTOTYPES */
-
-/*
- * @brief Initialize a job ring/channel in SEC device.
- * Write configuration register/s to properly initialize a job ring.
- *
- * @param [in] job_ring The job ring
- *
- * @retval 0 for success
- * @retval other for error
- */
-int hw_reset_job_ring(sec_job_ring_t *job_ring);
-
-/*
- * @brief Reset a job ring/channel in SEC device.
- * Write configuration register/s to reset a job ring.
- *
- * @param [in] job_ring The job ring
- *
- * @retval 0 for success
- * @retval -1 in case job ring reset failed
- */
-int hw_shutdown_job_ring(sec_job_ring_t *job_ring);
-
-/*
- * @brief Handle a job ring/channel error in SEC device.
- * Identify the error type and clear error bits if required.
- *
- * @param [in] job_ring The job ring
- * @param [in] sec_error_code error code as first read from SEC engine
- */
-
-void hw_handle_job_ring_error(sec_job_ring_t *job_ring,
- uint32_t sec_error_code);
-/*
- * @brief Handle a job ring error in the device.
- * Identify the error type and printout a explanatory
- * messages.
- *
- * @param [in] job_ring The job ring
- *
- */
-
-int hw_job_ring_error(sec_job_ring_t *job_ring);
-
-/* @brief Set interrupt coalescing parameters on the Job Ring.
- * @param [in] job_ring The job ring
- * @param [in] irq_coalesing_timer
- * Interrupt coalescing timer threshold.
- * This value determines the maximum
- * amount of time after processing a descriptor
- * before raising an interrupt.
- * @param [in] irq_coalescing_count
- * Interrupt coalescing count threshold.
- * This value determines how many descriptors
- * are completed before raising an interrupt.
- */
-
-int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring,
- uint16_t irq_coalescing_timer,
- uint8_t irq_coalescing_count);
-
-/* @brief Enable interrupt coalescing on a job ring
- * @param [in] job_ring The job ring
- */
-
-int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring);
-
-/*
- * @brief Disable interrupt coalescing on a job ring
- * @param [in] job_ring The job ring
- */
-
-int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring);
-
-/*
- * @brief Poll the HW for already processed jobs in the JR
- * and notify the available jobs to UA.
- *
- * @param [in] job_ring The job ring to poll.
- * @param [in] limit The maximum number of jobs to notify.
- * If set to negative value, all available
- * jobs are notified.
- *
- * @retval >=0 for No of jobs notified to UA.
- * @retval -1 for error
- */
-
-int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit);
-
-/* @brief Poll the HW for already processed jobs in the JR
- * and silently discard the available jobs or notify them to UA
- * with indicated error code.
-
- * @param [in,out] job_ring The job ring to poll.
- * @param [in] do_notify Can be #TRUE or #FALSE.
- * Indicates if descriptors to be discarded
- * or notified to UA with given error_code.
- * @param [in] error_code The detailed SEC error code.
- * @param [out] notified_descs Number of notified descriptors.
- * Can be NULL if do_notify is #FALSE
- */
-void hw_flush_job_ring(struct sec_job_ring_t *job_ring,
- uint32_t do_notify,
- uint32_t error_code, uint32_t *notified_descs);
-
-/*
- * @brief Flush job rings of any processed descs.
- * The processed descs are silently dropped,
- * WITHOUT being notified to UA.
- */
-void flush_job_rings(void);
-
-/*
- * @brief Handle desc that generated error in SEC engine.
- * Identify the exact type of error and handle the error.
- * Depending on the error type, the job ring could be reset.
- * All descs that are submitted for processing on this job ring
- * are notified to User Application with error status and detailed error code.
-
- * @param [in] job_ring Job ring
- * @param [in] sec_error_code Error code read from job ring's Channel
- * Status Register
- * @param [out] notified_descs Number of notified descs. Can be NULL if
- * do_notify is #FALSE
- * @param [out] do_driver_shutdown If set to #TRUE, then UA is returned code
- * #SEC_PROCESSING_ERROR
- * which is indication that UA must call
- * sec_release() after this.
- */
-void sec_handle_desc_error(struct sec_job_ring_t *job_ring,
- uint32_t sec_error_code,
- uint32_t *notified_descs,
- uint32_t *do_driver_shutdown);
-
-/*
- * @brief Release the software and hardware resources tied to a job ring.
- * @param [in] job_ring The job ring
- * @retval 0 for success
- * @retval -1 for error
- */
-int shutdown_job_ring(struct sec_job_ring_t *job_ring);
-
-/*
- * @brief Enable irqs on associated job ring.
- * @param [in] job_ring The job ring
- * @retval 0 for success
- * @retval -1 for error
- */
-int jr_enable_irqs(struct sec_job_ring_t *job_ring);
-
-/*
- * @brief Disable irqs on associated job ring.
- * @param [in] job_ring The job ring
- * @retval 0 for success
- * @retval -1 for error
- */
-int jr_disable_irqs(struct sec_job_ring_t *job_ring);
-
- /*
- * IRJA - Input Ring Jobs Added Register shows
- * how many new jobs were added to the Input Ring.
- */
-static inline void hw_enqueue_desc_on_job_ring(struct jobring_regs *regs,
- int num)
-{
- sec_out32(&regs->irja, num);
-}
-
-#endif /* _SEC_HW_SPECIFIC_H_ */
diff --git a/drivers/nxp/crypto/caam/include/sec_jr_driver.h b/drivers/nxp/crypto/caam/include/sec_jr_driver.h
deleted file mode 100644
index 1381eaba90..0000000000
--- a/drivers/nxp/crypto/caam/include/sec_jr_driver.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef _JR_DRIVER_H_
-#define _JR_DRIVER_H_
-
-#include "jr_driver_config.h"
-
-/* The maximum size of a SEC descriptor, in WORDs (32 bits). */
-#define MAX_DESC_SIZE_WORDS 64
-
-#define CAAM_TIMEOUT 200000 /* ms */
-
-/* Return codes for JR user space driver APIs */
-typedef enum sec_return_code_e {
- SEC_SUCCESS = 0,
- SEC_INVALID_INPUT_PARAM,
- SEC_OUT_OF_MEMORY,
- SEC_DESCRIPTOR_IN_FLIGHT,
- SEC_LAST_DESCRIPTOR_IN_FLIGHT,
- SEC_PROCESSING_ERROR,
- SEC_DESC_PROCESSING_ERROR,
- SEC_JR_IS_FULL,
- SEC_DRIVER_RELEASE_IN_PROGRESS,
- SEC_DRIVER_ALREADY_INITIALIZED,
- SEC_DRIVER_NOT_INITIALIZED,
- SEC_JOB_RING_RESET_IN_PROGRESS,
- SEC_RESET_ENGINE_FAILED,
- SEC_ENABLE_IRQS_FAILED,
- SEC_DISABLE_IRQS_FAILED,
- SEC_RETURN_CODE_MAX_VALUE,
-} sec_return_code_t;
-
-/* STRUCTURES AND OTHER TYPEDEFS */
-
-/*
- * @brief Function called by JR User Space driver to notify every processed
- * descriptor.
- *
- * Callback provided by the User Application.
- * Callback is invoked by JR User Space driver for each descriptor processed by
- * SEC
- * @param [in] status Status word indicating processing result for
- * this descriptor.
- * @param [in] arg Opaque data passed by User Application
- * It is opaque from JR driver's point of view.
- * @param [in] job_ring The job ring handle on which the processed
- * descriptor word was enqueued
- */
-typedef void (*user_callback) (uint32_t *desc, uint32_t status,
- void *arg, void *job_ring);
-
-/*
- * Structure encompassing a job descriptor which is to be processed
- * by SEC. User should also initialise this structure with the callback
- * function pointer which will be called by driver after recieving proccessed
- * descriptor from SEC. User data is also passed in this data structure which
- * will be sent as an argument to the user callback function.
- */
-struct job_descriptor {
- uint32_t desc[MAX_DESC_SIZE_WORDS];
- void *arg;
- user_callback callback;
-};
-
-/*
- * @brief Initialize the JR User Space driver.
- * This function will handle initialization of sec library
- * along with registering platform specific callbacks,
- * as well as local data initialization.
- * Call once during application startup.
- * @note Global SEC initialization is done in SEC kernel driver.
- * @note The hardware IDs of the initialized Job Rings are opaque to the UA.
- * The exact Job Rings used by this library are decided between SEC user
- * space driver and SEC kernel driver. A static partitioning of Job Rings is
- * assumed, configured in DTS(device tree specification) file.
- * @param [in] platform_cb Registering the platform specific
- * callbacks with driver
- * @retval ::0 for successful execution
- * @retval ::-1 failure
- */
-int sec_jr_lib_init(void);
-
-/*
- * @brief Initialize the software and hardware resources tied to a job ring.
- * @param [in] jr_mode; Model to be used by SEC Driver to receive
- * notifications from SEC. Can be either
- * SEC_NOTIFICATION_TYPE_IRQ or
- * SEC_NOTIFICATION_TYPE_POLL
- * @param [in] irq_coalescing_timer This value determines the maximum
- * amount of time after processing a
- * descriptor before raising an interrupt.
- * @param [in] irq_coalescing_count This value determines how many
- * descriptors are completed before
- * raising an interrupt.
- * @param [in] reg_base_addr The job ring base address register
- * @param [in] irq_id The job ring interrupt identification number.
- * @retval job_ring_handle for successful job ring configuration
- * @retval NULL on error
- */
-void *init_job_ring(uint8_t jr_mode,
- uint16_t irq_coalescing_timer,
- uint8_t irq_coalescing_count,
- void *reg_base_addr, uint32_t irq_id);
-
-/*
- * @brief Release the resources used by the JR User Space driver.
- * Reset and release SEC's job rings indicated by the User Application at
- * init_job_ring() and free any memory allocated internally.
- * Call once during application tear down.
- * @note In case there are any descriptors in-flight (descriptors received by
- * JR driver for processing and for which no response was yet provided to UA),
- * the descriptors are discarded without any notifications to User Application.
- * @retval ::0 is returned for a successful execution
- * @retval ::-1 is returned if JR driver release is in progress
- */
-int sec_release(void);
-
-/*
- * @brief Submit a descriptor for SEC processing.
- * This function creates a "job" which is meant to instruct SEC HW
- * to perform the processing on the input buffer. The "job" is enqueued
- * in the Job Ring associated. The function will return after the "job"
- * enqueue is finished. The function will not wait for SEC to
- * start or/and finish the "job" processing.
- * After the processing is finished the SEC HW writes the processing result
- * to the provided output buffer.
- * The Caller must poll JR driver using jr_dequeue()
- * to receive notifications of the processing completion
- * status. The notifications are received by caller by means of callback
- * (see ::user_callback).
- * @param [in] job_ring_handle The handle of the job ring on which
- * descriptor is to be enqueued
- * @param [in] job_descriptor The job descriptor structure of type
- * struct job_descriptor. This structure
- * should be filled with job descriptor along
- * with callback function to be called after
- * processing of descriptor and some
- * opaque data passed to be passed to the
- * callback function
- *
- * @retval ::0 is returned for successful execution
- * @retval ::-1 is returned if there is some enqueue failure
- */
-int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr);
-
-/*
- * @brief Polls for available descriptors processed by SEC on a specific
- * Job Ring
- * This function polls the SEC Job Rings and delivers processed descriptors
- * Each processed descriptor has a user_callback registered.
- * This user_callback is invoked for each processed descriptor.
- * The polling is stopped when "limit" descriptors are notified or when
- * there are no more descriptors to notify.
- * @note The dequeue_jr() API cannot be called from within a user_callback
- * function
- * @param [in] job_ring_handle The Job Ring handle.
- * @param [in] limit This value represents the maximum number
- * of processed descriptors that can be
- * notified API call on this Job Ring.
- * Note that fewer descriptors may be notified
- * if enough processed descriptors are not
- * available.
- * If limit has a negative value, then all
- * ready descriptors will be notified.
- *
- * @retval :: >=0 is returned where retval is the total
- * Number of descriptors notified
- * during this function call.
- * @retval :: -1 is returned in case of some error
- */
-int dequeue_jr(void *job_ring_handle, int32_t limit);
-
-#endif /* _JR_DRIVER_H_ */
diff --git a/drivers/nxp/crypto/caam/src/auth/hash.c b/drivers/nxp/crypto/caam/src/auth/hash.c
index 1665df1a86..0f3cf95524 100644
--- a/drivers/nxp/crypto/caam/src/auth/hash.c
+++ b/drivers/nxp/crypto/caam/src/auth/hash.c
@@ -106,7 +106,7 @@ int hash_update(enum hash_algo algo, void *context, void *data_ptr,
* Function : hash_final
* Arguments : ctx - SHA context
* Return : SUCCESS or FAILURE
- * Description : This function sets the final bit and enqueues the decriptor
+ * Description : This function sets the final bit and enqueues the descriptor
***************************************************************************/
int hash_final(enum hash_algo algo, void *context, void *hash_ptr,
unsigned int hash_len)
diff --git a/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c b/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c
index 646e981f70..408d974aab 100644
--- a/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c
+++ b/drivers/nxp/crypto/caam/src/auth/nxp_crypto.c
@@ -120,4 +120,4 @@ static int verify_hash(void *data_ptr, unsigned int data_len,
/*
* Register crypto library descriptor
*/
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL, NULL, NULL);
diff --git a/drivers/nxp/crypto/caam/src/hw_key_blob.c b/drivers/nxp/crypto/caam/src/hw_key_blob.c
index 0720695d3d..6bcb6ba7f9 100644
--- a/drivers/nxp/crypto/caam/src/hw_key_blob.c
+++ b/drivers/nxp/crypto/caam/src/hw_key_blob.c
@@ -18,7 +18,7 @@
#include "sec_hw_specific.h"
-/* Callback function after Instantiation decsriptor is submitted to SEC
+/* Callback function after Instantiation descriptor is submitted to SEC
*/
static void blob_done(uint32_t *desc, uint32_t status, void *arg,
void *job_ring)
diff --git a/drivers/nxp/crypto/caam/src/jobdesc.c b/drivers/nxp/crypto/caam/src/jobdesc.c
index 9c235af2e3..92fcb74f3f 100644
--- a/drivers/nxp/crypto/caam/src/jobdesc.c
+++ b/drivers/nxp/crypto/caam/src/jobdesc.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2020 NXP
+ * Copyright 2017-2022 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -11,13 +11,13 @@
#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
#include "caam.h"
#include <common/debug.h>
#include "jobdesc.h"
#include "rsa.h"
#include "sec_hw_specific.h"
-
/* Return Length of desctiptr from first word */
uint32_t desc_length(uint32_t *desc)
{
@@ -41,6 +41,8 @@ void desc_add_word(uint32_t *desc, uint32_t word)
{
uint32_t len = desc_length(desc);
+ assert((len + 1) < MAX_DESC_SIZE_WORDS);
+
/* Add Word at Last */
uint32_t *last = desc + len;
*last = word;
@@ -54,14 +56,17 @@ void desc_add_ptr(uint32_t *desc, phys_addr_t *ptr)
{
uint32_t len = desc_length(desc);
+ assert((len + (uint32_t) (sizeof(phys_addr_t) / sizeof(uint32_t)))
+ < MAX_DESC_SIZE_WORDS);
+
/* Add Word at Last */
phys_addr_t *last = (phys_addr_t *) (desc + len);
#ifdef CONFIG_PHYS_64BIT
ptr_addr_t *ptr_addr = (ptr_addr_t *) last;
- ptr_addr->m_halves.high = PHYS_ADDR_HI(ptr);
- ptr_addr->m_halves.low = PHYS_ADDR_LO(ptr);
+ ptr_addr->high = PHYS_ADDR_HI(ptr);
+ ptr_addr->low = PHYS_ADDR_LO(ptr);
#else
*last = ptr;
#endif
diff --git a/drivers/nxp/crypto/caam/src/rng.c b/drivers/nxp/crypto/caam/src/rng.c
index 0b9d87de41..58430dbfd4 100644
--- a/drivers/nxp/crypto/caam/src/rng.c
+++ b/drivers/nxp/crypto/caam/src/rng.c
@@ -17,7 +17,7 @@
#include "sec_hw_specific.h"
-/* Callback function after Instantiation decsriptor is submitted to SEC */
+/* Callback function after Instantiation descriptor is submitted to SEC */
static void rng_done(uint32_t *desc, uint32_t status, void *arg,
void *job_ring)
{
@@ -183,7 +183,7 @@ int hw_rng_instantiate(void)
/*if instantiate_rng(...) fails, the loop will rerun
*and the kick_trng(...) function will modify the
*upper and lower limits of the entropy sampling
- *interval, leading to a sucessful initialization of
+ *interval, leading to a successful initialization of
*/
ret = instantiate_rng();
} while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
diff --git a/drivers/nxp/csu/csu.h b/drivers/nxp/csu/csu.h
deleted file mode 100644
index 9f82feb0a3..0000000000
--- a/drivers/nxp/csu/csu.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef CSU_H
-#define CSU_H
-
-#define CSU_SEC_ACCESS_REG_OFFSET (0x0021CU)
-
-/* Macros defining access permissions to configure
- * the regions controlled by Central Security Unit.
- */
-enum csu_cslx_access {
- CSU_NS_SUP_R = (0x8U),
- CSU_NS_SUP_W = (0x80U),
- CSU_NS_SUP_RW = (0x88U),
- CSU_NS_USER_R = (0x4U),
- CSU_NS_USER_W = (0x40U),
- CSU_NS_USER_RW = (0x44U),
- CSU_S_SUP_R = (0x2U),
- CSU_S_SUP_W = (0x20U),
- CSU_S_SUP_RW = (0x22U),
- CSU_S_USER_R = (0x1U),
- CSU_S_USER_W = (0x10U),
- CSU_S_USER_RW = (0x11U),
- CSU_ALL_RW = (0xffU),
-};
-
-struct csu_ns_dev_st {
- uintptr_t ind;
- uint32_t val;
-};
-
-void enable_layerscape_ns_access(struct csu_ns_dev_st *csu_ns_dev,
- uint32_t num, uintptr_t nxp_csu_addr);
-
-#endif
diff --git a/drivers/nxp/csu/csu.mk b/drivers/nxp/csu/csu.mk
index ebdf674835..bc16035efc 100644
--- a/drivers/nxp/csu/csu.mk
+++ b/drivers/nxp/csu/csu.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,11 +8,9 @@ ifeq (${CSU_ADDED},)
CSU_ADDED := 1
-CSU_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/csu
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/csu
-PLAT_INCLUDES += -I$(CSU_DRIVERS_PATH)
-
-CSU_SOURCES += $(CSU_DRIVERS_PATH)/csu.c
+CSU_SOURCES += $(PLAT_DRIVERS_PATH)/csu/csu.c
ifeq (${BL_COMM_CSU_NEEDED},yes)
BL_COMMON_SOURCES += ${CSU_SOURCES}
diff --git a/drivers/nxp/dcfg/dcfg.c b/drivers/nxp/dcfg/dcfg.c
index 2e813e7806..e5c4db4377 100644
--- a/drivers/nxp/dcfg/dcfg.c
+++ b/drivers/nxp/dcfg/dcfg.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 NXP
+ * Copyright 2020-2022 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -43,20 +43,12 @@ const soc_info_t *get_soc_info(void)
reg = gur_in32(dcfg_init_info->g_nxp_dcfg_addr + DCFG_SVR_OFFSET);
- soc_info.mfr_id = (reg & SVR_MFR_ID_MASK) >> SVR_MFR_ID_SHIFT;
-#if defined(CONFIG_CHASSIS_3_2)
- soc_info.family = (reg & SVR_FAMILY_MASK) >> SVR_FAMILY_SHIFT;
- soc_info.dev_id = (reg & SVR_DEV_ID_MASK) >> SVR_DEV_ID_SHIFT;
-#endif
+ soc_info.svr_reg.val = reg;
+
/* zero means SEC enabled. */
soc_info.sec_enabled =
(((reg & SVR_SEC_MASK) >> SVR_SEC_SHIFT) == 0) ? true : false;
- soc_info.personality = (reg & SVR_PERSONALITY_MASK)
- >> SVR_PERSONALITY_SHIFT;
- soc_info.maj_ver = (reg & SVR_MAJ_VER_MASK) >> SVR_MAJ_VER_SHIFT;
- soc_info.min_ver = reg & SVR_MIN_VER_MASK;
-
soc_info.is_populated = true;
return (const soc_info_t *) &soc_info;
}
@@ -82,14 +74,11 @@ const devdisr5_info_t *get_devdisr5_info(void)
reg = gur_in32(dcfg_init_info->g_nxp_dcfg_addr + DCFG_DEVDISR5_OFFSET);
-#if defined(CONFIG_CHASSIS_3_2)
devdisr5_info.ddrc1_present = (reg & DISR5_DDRC1_MASK) ? 0 : 1;
+#if defined(CONFIG_CHASSIS_3_2)
devdisr5_info.ddrc2_present = (reg & DISR5_DDRC2_MASK) ? 0 : 1;
- devdisr5_info.ocram_present = (reg & DISR5_OCRAM_MASK) ? 0 : 1;
-#elif defined(CONFIG_CHASSIS_2)
- devdisr5_info.ddrc1_present = (reg & DISR5_DDRC1_MASK) ? 0 : 1;
- devdisr5_info.ocram_present = (reg & DISR5_OCRAM_MASK) ? 0 : 1;
#endif
+ devdisr5_info.ocram_present = (reg & DISR5_OCRAM_MASK) ? 0 : 1;
devdisr5_info.is_populated = true;
return (const devdisr5_info_t *) &devdisr5_info;
diff --git a/drivers/nxp/dcfg/dcfg.h b/drivers/nxp/dcfg/dcfg.h
deleted file mode 100644
index 161e2950f9..0000000000
--- a/drivers/nxp/dcfg/dcfg.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2018-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DCFG_H
-#define DCFG_H
-
-#include <endian.h>
-
-#if defined(CONFIG_CHASSIS_2)
-#include <dcfg_lsch2.h>
-#elif defined(CONFIG_CHASSIS_3_2)
-#include <dcfg_lsch3.h>
-#endif
-
-#ifdef NXP_GUR_BE
-#define gur_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define gur_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#elif defined(NXP_GUR_LE)
-#define gur_in32(a) mmio_read_32((uintptr_t)(a))
-#define gur_out32(a, v) mmio_write_32((uintptr_t)(a), v)
-#else
-#error Please define CCSR GUR register endianness
-#endif
-
-typedef struct {
- bool is_populated;
- uint8_t mfr_id;
-#if defined(CONFIG_CHASSIS_3_2)
- uint8_t family;
- uint8_t dev_id;
-#endif
- uint8_t personality;
- bool sec_enabled;
- uint8_t maj_ver;
- uint8_t min_ver;
-} soc_info_t;
-
-typedef struct {
- bool is_populated;
- uint8_t ocram_present;
- uint8_t ddrc1_present;
-#if defined(CONFIG_CHASSIS_3_2)
- uint8_t ddrc2_present;
-#endif
-} devdisr5_info_t;
-
-typedef struct {
- uint32_t porsr1;
- uintptr_t g_nxp_dcfg_addr;
- unsigned long nxp_sysclk_freq;
- unsigned long nxp_ddrclk_freq;
- unsigned int nxp_plat_clk_divider;
-} dcfg_init_info_t;
-
-
-struct sysinfo {
- unsigned long freq_platform;
- unsigned long freq_ddr_pll0;
- unsigned long freq_ddr_pll1;
-};
-
-int get_clocks(struct sysinfo *sys);
-
-/* Read the PORSR1 register */
-uint32_t read_reg_porsr1(void);
-
-/*******************************************************************************
- * Returns true if secur eboot is enabled on board
- * mode = 0 (development mode - sb_en = 1)
- * mode = 1 (production mode - ITS = 1)
- ******************************************************************************/
-bool check_boot_mode_secure(uint32_t *mode);
-
-const soc_info_t *get_soc_info();
-const devdisr5_info_t *get_devdisr5_info();
-
-void dcfg_init(dcfg_init_info_t *dcfg_init_data);
-bool is_sec_enabled(void);
-
-void error_handler(int error_code);
-#endif /* DCFG_H */
diff --git a/drivers/nxp/dcfg/dcfg.mk b/drivers/nxp/dcfg/dcfg.mk
index 61d1850458..206595f10c 100644
--- a/drivers/nxp/dcfg/dcfg.mk
+++ b/drivers/nxp/dcfg/dcfg.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,11 +8,9 @@ ifeq (${ADD_DCFG},)
ADD_DCFG := 1
-DCFG_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/dcfg
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/dcfg
-PLAT_INCLUDES += -I$(DCFG_DRIVERS_PATH)
-
-DCFG_SOURCES += $(DCFG_DRIVERS_PATH)/dcfg.c
+DCFG_SOURCES += $(PLAT_DRIVERS_PATH)/dcfg/dcfg.c
ifeq (${BL_COMM_DCFG_NEEDED},yes)
BL_COMMON_SOURCES += ${DCFG_SOURCES}
diff --git a/drivers/nxp/dcfg/dcfg_lsch2.h b/drivers/nxp/dcfg/dcfg_lsch2.h
deleted file mode 100644
index c021aa1631..0000000000
--- a/drivers/nxp/dcfg/dcfg_lsch2.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DCFG_LSCH2_H
-#define DCFG_LSCH2_H
-
-/* dcfg block register offsets and bitfields */
-#define DCFG_PORSR1_OFFSET 0x00
-#define DCFG_DEVDISR1_OFFSET 0x070
-#define DCFG_DEVDISR4_OFFSET 0x07C
-#define DCFG_DEVDISR5_OFFSET 0x080
-#define DCFG_COREDISR_OFFSET 0x094
-#define RCWSR0_OFFSET 0x100
-#define RCWSR5_OFFSET 0x118
-#define DCFG_BOOTLOCPTRL_OFFSET 0x400
-#define DCFG_BOOTLOCPTRH_OFFSET 0x404
-#define DCFG_COREDISABLEDSR_OFFSET 0x990
-#define DCFG_SCRATCH4_OFFSET 0x20C
-#define DCFG_SVR_OFFSET 0x0A4
-#define DCFG_BRR_OFFSET 0x0E4
-
-#define DCFG_RSTCR_OFFSET 0x0B0
-#define RSTCR_RESET_REQ 0x2
-
-#define DCFG_RSTRQSR1_OFFSET 0x0C8
-#define DCFG_RSTRQMR1_OFFSET 0x0C0
-
-/* DCFG DCSR Macros */
-#define DCFG_DCSR_PORCR1_OFFSET 0x0
-
-#define SVR_MFR_ID_MASK 0xF0000000
-#define SVR_MFR_ID_SHIFT 28
-#define SVR_FAMILY_MASK 0xF000000
-#define SVR_FAMILY_SHIFT 24
-#define SVR_DEV_ID_MASK 0x3F0000
-#define SVR_DEV_ID_SHIFT 16
-#define SVR_PERSONALITY_MASK 0x3E00
-#define SVR_PERSONALITY_SHIFT 9
-#define SVR_SEC_MASK 0x100
-#define SVR_SEC_SHIFT 8
-#define SVR_MAJ_VER_MASK 0xF0
-#define SVR_MAJ_VER_SHIFT 4
-#define SVR_MIN_VER_MASK 0xF
-
-#define DISR5_DDRC1_MASK 0x1
-#define DISR5_OCRAM_MASK 0x40
-
-/* DCFG regsiters bit masks */
-#define RCWSR0_SYS_PLL_RAT_SHIFT 25
-#define RCWSR0_SYS_PLL_RAT_MASK 0x1f
-#define RCWSR0_MEM_PLL_RAT_SHIFT 16
-#define RCWSR0_MEM_PLL_RAT_MASK 0x3f
-#define RCWSR0_MEM2_PLL_RAT_SHIFT 18
-#define RCWSR0_MEM2_PLL_RAT_MASK 0x3f
-
-#define RCWSR_SB_EN_OFFSET RCWSR5_OFFSET
-#define RCWSR_SBEN_MASK 0x1
-#define RCWSR_SBEN_SHIFT 21
-
-/* RCW SRC NAND */
-#define RCW_SRC_NAND_MASK (0x100)
-#define RCW_SRC_NAND_VAL (0x100)
-#define NAND_RESERVED_MASK (0xFC)
-#define NAND_RESERVED_1 (0x0)
-#define NAND_RESERVED_2 (0x80)
-
-/* RCW SRC NOR */
-#define RCW_SRC_NOR_MASK (0x1F0)
-#define NOR_8B_VAL (0x10)
-#define NOR_16B_VAL (0x20)
-#define SD_VAL (0x40)
-#define QSPI_VAL1 (0x44)
-#define QSPI_VAL2 (0x45)
-
-#endif /* DCFG_LSCH2_H */
diff --git a/drivers/nxp/dcfg/dcfg_lsch3.h b/drivers/nxp/dcfg/dcfg_lsch3.h
deleted file mode 100644
index 8144542530..0000000000
--- a/drivers/nxp/dcfg/dcfg_lsch3.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DCFG_LSCH3_H
-#define DCFG_LSCH3_H
-
-/* dcfg block register offsets and bitfields */
-#define DCFG_PORSR1_OFFSET 0x00
-
-#define DCFG_DEVDISR1_OFFSET 0x70
-#define DCFG_DEVDISR1_SEC (1 << 22)
-
-#define DCFG_DEVDISR2_OFFSET 0x74
-
-#define DCFG_DEVDISR3_OFFSET 0x78
-#define DCFG_DEVDISR3_QBMAIN (1 << 12)
-
-#define DCFG_DEVDISR4_OFFSET 0x7C
-#define DCFG_DEVDISR4_SPI_QSPI (1 << 4 | 1 << 5)
-
-#define DCFG_DEVDISR5_OFFSET 0x80
-#define DISR5_DDRC1_MASK 0x1
-#define DISR5_DDRC2_MASK 0x2
-#define DISR5_OCRAM_MASK 0x1000
-#define DEVDISR5_MASK_ALL_MEM 0x00001003
-#define DEVDISR5_MASK_DDR 0x00000003
-#define DEVDISR5_MASK_DBG 0x00000400
-
-#define DCFG_DEVDISR6_OFFSET 0x84
-//#define DEVDISR6_MASK 0x00000001
-
-#define DCFG_COREDISR_OFFSET 0x94
-
-#define DCFG_SVR_OFFSET 0x0A4
-#define SVR_MFR_ID_MASK 0xF0000000
-#define SVR_MFR_ID_SHIFT 28
-#define SVR_FAMILY_MASK 0xF000000
-#define SVR_FAMILY_SHIFT 24
-#define SVR_DEV_ID_MASK 0x3F0000
-#define SVR_DEV_ID_SHIFT 16
-#define SVR_PERSONALITY_MASK 0x3E00
-#define SVR_PERSONALITY_SHIFT 9
-#define SVR_SEC_MASK 0x100
-#define SVR_SEC_SHIFT 8
-#define SVR_MAJ_VER_MASK 0xF0
-#define SVR_MAJ_VER_SHIFT 4
-#define SVR_MIN_VER_MASK 0xF
-
-#define RCWSR0_OFFSET 0x100
-#define RCWSR0_SYS_PLL_RAT_SHIFT 2
-#define RCWSR0_SYS_PLL_RAT_MASK 0x1f
-#define RCWSR0_MEM_PLL_RAT_SHIFT 10
-#define RCWSR0_MEM_PLL_RAT_MASK 0x3f
-#define RCWSR0_MEM2_PLL_RAT_SHIFT 18
-#define RCWSR0_MEM2_PLL_RAT_MASK 0x3f
-
-#define RCWSR5_OFFSET 0x110
-#define RCWSR9_OFFSET 0x120
-#define RCWSR_SB_EN_OFFSET RCWSR9_OFFSET
-#define RCWSR_SBEN_MASK 0x1
-#define RCWSR_SBEN_SHIFT 10
-
-#define RCW_SR27_OFFSET 0x168
-/* DCFG register to dump error code */
-#define DCFG_SCRATCH4_OFFSET 0x20C
-#define DCFG_SCRATCHRW5_OFFSET 0x210
-#define DCFG_SCRATCHRW6_OFFSET 0x214
-#define DCFG_SCRATCHRW7_OFFSET 0x218
-#define DCFG_BOOTLOCPTRL_OFFSET 0x400
-#define DCFG_BOOTLOCPTRH_OFFSET 0x404
-#define DCFG_COREDISABLEDSR_OFFSET 0x990
-
-#endif /* DCFG_LSCH3_H */
diff --git a/drivers/nxp/dcfg/scfg.h b/drivers/nxp/dcfg/scfg.h
deleted file mode 100644
index 81df9a61a9..0000000000
--- a/drivers/nxp/dcfg/scfg.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef SCFG_H
-#define SCFG_H
-
-#ifdef CONFIG_CHASSIS_2
-
-/* SCFG register offsets */
-#define SCFG_CORE0_SFT_RST_OFFSET 0x0130
-#define SCFG_SNPCNFGCR_OFFSET 0x01A4
-#define SCFG_CORESRENCR_OFFSET 0x0204
-#define SCFG_RVBAR0_0_OFFSET 0x0220
-#define SCFG_RVBAR0_1_OFFSET 0x0224
-#define SCFG_COREBCR_OFFSET 0x0680
-#define SCFG_RETREQCR_OFFSET 0x0424
-
-#define SCFG_COREPMCR_OFFSET 0x042C
-#define COREPMCR_WFIL2 0x1
-
-#define SCFG_GIC400_ADDR_ALIGN_OFFSET 0x0188
-#define SCFG_BOOTLOCPTRH_OFFSET 0x0600
-#define SCFG_BOOTLOCPTRL_OFFSET 0x0604
-#define SCFG_SCRATCHRW2_OFFSET 0x0608
-#define SCFG_SCRATCHRW3_OFFSET 0x060C
-
-/* SCFG bit fields */
-#define SCFG_SNPCNFGCR_SECRDSNP 0x80000000
-#define SCFG_SNPCNFGCR_SECWRSNP 0x40000000
-#endif /* CONFIG_CHASSIS_2 */
-
-#ifndef __ASSEMBLER__
-#include <endian.h>
-#include <lib/mmio.h>
-
-#ifdef NXP_SCFG_BE
-#define scfg_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define scfg_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#define scfg_setbits32(a, v) mmio_setbits_32((uintptr_t)(a), v)
-#define scfg_clrbits32(a, v) mmio_clrbits_32((uintptr_t)(a), v)
-#define scfg_clrsetbits32(a, clear, set) \
- mmio_clrsetbits_32((uintptr_t)(a), clear, set)
-#elif defined(NXP_GUR_LE)
-#define scfg_in32(a) mmio_read_32((uintptr_t)(a))
-#define scfg_out32(a, v) mmio_write_32((uintptr_t)(a), v)
-#define scfg_setbits32(a, v) mmio_setbits_32((uintptr_t)(a), v)
-#define scfg_clrbits32(a, v) mmio_clrbits_32((uintptr_t)(a), v)
-#define scfg_clrsetbits32(a, clear, set) \
- mmio_clrsetbits_32((uintptr_t)(a), clear, set)
-#else
-#error Please define CCSR SCFG register endianness
-#endif
-#endif /* __ASSEMBLER__ */
-
-#endif /* SCFG_H */
diff --git a/drivers/nxp/ddr/fsl-mmdc/ddr.mk b/drivers/nxp/ddr/fsl-mmdc/ddr.mk
index e6cc7c1d0c..afccb623d5 100644
--- a/drivers/nxp/ddr/fsl-mmdc/ddr.mk
+++ b/drivers/nxp/ddr/fsl-mmdc/ddr.mk
@@ -9,11 +9,11 @@
DDR_DRIVERS_PATH := drivers/nxp/ddr
-DDR_CNTLR_SOURCES := ${DDR_DRIVERS_PATH}/fsl-mmdc/fsl_mmdc.c \
- ${DDR_DRIVERS_PATH}/nxp-ddr/utility.c \
- ${DDR_DRIVERS_PATH}/nxp-ddr/ddr.c \
- ${DDR_DRIVERS_PATH}/nxp-ddr/ddrc.c
+DDR_CNTLR_SOURCES := ${PLAT_DRIVERS_PATH}/ddr/fsl-mmdc/fsl_mmdc.c \
+ ${PLAT_DRIVERS_PATH}/ddr/nxp-ddr/utility.c \
+ ${PLAT_DRIVERS_PATH}/ddr/nxp-ddr/ddr.c \
+ ${PLAT_DRIVERS_PATH}/ddr/nxp-ddr/ddrc.c
-PLAT_INCLUDES += -I$(DDR_DRIVERS_PATH)/include \
- -I$(DDR_DRIVERS_PATH)/fsl-mmdc
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ddr \
+ -I$(PLAT_DRIVERS_INCLUDE_PATH)/ddr/fsl-mmdc
#------------------------------------------------
diff --git a/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h b/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h
deleted file mode 100644
index 31db55230e..0000000000
--- a/drivers/nxp/ddr/fsl-mmdc/fsl_mmdc.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef FSL_MMDC_H
-#define FSL_MMDC_H
-
-/* PHY Write Leveling Configuration and Error Status Register (MPWLGCR) */
-#define MPWLGCR_HW_WL_EN (1 << 0)
-
-/* PHY Pre-defined Compare and CA delay-line Configuration (MPPDCMPR2) */
-#define MPPDCMPR2_MPR_COMPARE_EN (1 << 0)
-
-
-/* MMDC PHY Read DQS gating control register 0 (MPDGCTRL0) */
-#define AUTO_RD_DQS_GATING_CALIBRATION_EN (1 << 28)
-
-/* MMDC PHY Read Delay HW Calibration Control Register (MPRDDLHWCTL) */
-#define MPRDDLHWCTL_AUTO_RD_CALIBRATION_EN (1 << 4)
-
-/* MMDC Core Power Saving Control and Status Register (MMDC_MAPSR) */
-#define MMDC_MAPSR_PWR_SAV_CTRL_STAT 0x00001067
-
-/* MMDC Core Refresh Control Register (MMDC_MDREF) */
-#define MDREF_START_REFRESH (1 << 0)
-
-/* MMDC Core Special Command Register (MDSCR) */
-#define CMD_ADDR_MSB_MR_OP(x) (x << 24)
-#define CMD_ADDR_LSB_MR_ADDR(x) (x << 16)
-#define MDSCR_DISABLE_CFG_REQ (0 << 15)
-#define MDSCR_ENABLE_CON_REQ (1 << 15)
-#define MDSCR_CON_ACK (1 << 14)
-#define MDSCR_WL_EN (1 << 9)
-#define CMD_NORMAL (0 << 4)
-#define CMD_PRECHARGE (1 << 4)
-#define CMD_AUTO_REFRESH (2 << 4)
-#define CMD_LOAD_MODE_REG (3 << 4)
-#define CMD_ZQ_CALIBRATION (4 << 4)
-#define CMD_PRECHARGE_BANK_OPEN (5 << 4)
-#define CMD_MRR (6 << 4)
-#define CMD_BANK_ADDR_0 0x0
-#define CMD_BANK_ADDR_1 0x1
-#define CMD_BANK_ADDR_2 0x2
-#define CMD_BANK_ADDR_3 0x3
-#define CMD_BANK_ADDR_4 0x4
-#define CMD_BANK_ADDR_5 0x5
-#define CMD_BANK_ADDR_6 0x6
-#define CMD_BANK_ADDR_7 0x7
-
-/* MMDC Core Control Register (MDCTL) */
-#define MDCTL_SDE0 (U(1) << 31)
-#define MDCTL_SDE1 (1 << 30)
-
-/* MMDC PHY ZQ HW control register (MMDC_MPZQHWCTRL) */
-#define MPZQHWCTRL_ZQ_HW_FORCE (1 << 16)
-
-/* MMDC PHY Measure Unit Register (MMDC_MPMUR0) */
-#define MMDC_MPMUR0_FRC_MSR (1 << 11)
-
-/* MMDC PHY Read delay-lines Configuration Register (MMDC_MPRDDLCTL) */
-/* default 64 for a quarter cycle delay */
-#define MMDC_MPRDDLCTL_DEFAULT_DELAY 0x40404040
-
-/* MMDC Registers */
-struct mmdc_regs {
- unsigned int mdctl;
- unsigned int mdpdc;
- unsigned int mdotc;
- unsigned int mdcfg0;
- unsigned int mdcfg1;
- unsigned int mdcfg2;
- unsigned int mdmisc;
- unsigned int mdscr;
- unsigned int mdref;
- unsigned int res1[2];
- unsigned int mdrwd;
- unsigned int mdor;
- unsigned int mdmrr;
- unsigned int mdcfg3lp;
- unsigned int mdmr4;
- unsigned int mdasp;
- unsigned int res2[239];
- unsigned int maarcr;
- unsigned int mapsr;
- unsigned int maexidr0;
- unsigned int maexidr1;
- unsigned int madpcr0;
- unsigned int madpcr1;
- unsigned int madpsr0;
- unsigned int madpsr1;
- unsigned int madpsr2;
- unsigned int madpsr3;
- unsigned int madpsr4;
- unsigned int madpsr5;
- unsigned int masbs0;
- unsigned int masbs1;
- unsigned int res3[2];
- unsigned int magenp;
- unsigned int res4[239];
- unsigned int mpzqhwctrl;
- unsigned int mpzqswctrl;
- unsigned int mpwlgcr;
- unsigned int mpwldectrl0;
- unsigned int mpwldectrl1;
- unsigned int mpwldlst;
- unsigned int mpodtctrl;
- unsigned int mprddqby0dl;
- unsigned int mprddqby1dl;
- unsigned int mprddqby2dl;
- unsigned int mprddqby3dl;
- unsigned int mpwrdqby0dl;
- unsigned int mpwrdqby1dl;
- unsigned int mpwrdqby2dl;
- unsigned int mpwrdqby3dl;
- unsigned int mpdgctrl0;
- unsigned int mpdgctrl1;
- unsigned int mpdgdlst0;
- unsigned int mprddlctl;
- unsigned int mprddlst;
- unsigned int mpwrdlctl;
- unsigned int mpwrdlst;
- unsigned int mpsdctrl;
- unsigned int mpzqlp2ctl;
- unsigned int mprddlhwctl;
- unsigned int mpwrdlhwctl;
- unsigned int mprddlhwst0;
- unsigned int mprddlhwst1;
- unsigned int mpwrdlhwst0;
- unsigned int mpwrdlhwst1;
- unsigned int mpwlhwerr;
- unsigned int mpdghwst0;
- unsigned int mpdghwst1;
- unsigned int mpdghwst2;
- unsigned int mpdghwst3;
- unsigned int mppdcmpr1;
- unsigned int mppdcmpr2;
- unsigned int mpswdar0;
- unsigned int mpswdrdr0;
- unsigned int mpswdrdr1;
- unsigned int mpswdrdr2;
- unsigned int mpswdrdr3;
- unsigned int mpswdrdr4;
- unsigned int mpswdrdr5;
- unsigned int mpswdrdr6;
- unsigned int mpswdrdr7;
- unsigned int mpmur0;
- unsigned int mpwrcadl;
- unsigned int mpdccr;
-};
-
-struct fsl_mmdc_info {
- unsigned int mdctl;
- unsigned int mdpdc;
- unsigned int mdotc;
- unsigned int mdcfg0;
- unsigned int mdcfg1;
- unsigned int mdcfg2;
- unsigned int mdmisc;
- unsigned int mdref;
- unsigned int mdrwd;
- unsigned int mdor;
- unsigned int mdasp;
- unsigned int mpodtctrl;
- unsigned int mpzqhwctrl;
- unsigned int mprddlctl;
-};
-
-void mmdc_init(const struct fsl_mmdc_info *priv, uintptr_t nxp_ddr_addr);
-
-#endif /* FSL_MMDC_H */
diff --git a/drivers/nxp/ddr/include/ddr.h b/drivers/nxp/ddr/include/ddr.h
deleted file mode 100644
index 0ef28706fb..0000000000
--- a/drivers/nxp/ddr/include/ddr.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DDR_H
-#define DDR_H
-
-#include "ddr_io.h"
-#include "dimm.h"
-#include "immap.h"
-
-#ifndef DDRC_NUM_CS
-#define DDRC_NUM_CS 4
-#endif
-
-/*
- * This is irrespective of what is the number of DDR controller,
- * number of DIMM used. This is set to maximum
- * Max controllers = 2
- * Max num of DIMM per controlle = 2
- * MAX NUM CS = 4
- * Not to be changed.
- */
-#define MAX_DDRC_NUM 2
-#define MAX_DIMM_NUM 2
-#define MAX_CS_NUM 4
-
-#include "opts.h"
-#include "regs.h"
-#include "utility.h"
-
-#ifdef DDR_DEBUG
-#define debug(...) INFO(__VA_ARGS__)
-#else
-#define debug(...) VERBOSE(__VA_ARGS__)
-#endif
-
-#ifndef DDRC_NUM_DIMM
-#define DDRC_NUM_DIMM 1
-#endif
-
-#define CONFIG_CS_PER_SLOT \
- (DDRC_NUM_CS / DDRC_NUM_DIMM)
-
-/* Record of register values computed */
-struct ddr_cfg_regs {
- struct {
- unsigned int bnds;
- unsigned int config;
- unsigned int config_2;
- } cs[MAX_CS_NUM];
- unsigned int dec[10];
- unsigned int timing_cfg[10];
- unsigned int sdram_cfg[3];
- unsigned int sdram_mode[16];
- unsigned int md_cntl;
- unsigned int interval;
- unsigned int data_init;
- unsigned int clk_cntl;
- unsigned int init_addr;
- unsigned int init_ext_addr;
- unsigned int zq_cntl;
- unsigned int wrlvl_cntl[3];
- unsigned int ddr_sr_cntr;
- unsigned int sdram_rcw[6];
- unsigned int dq_map[4];
- unsigned int eor;
- unsigned int cdr[2];
- unsigned int err_disable;
- unsigned int err_int_en;
- unsigned int tx_cfg[4];
- unsigned int debug[64];
-};
-
-struct ddr_conf {
- int dimm_in_use[MAX_DIMM_NUM];
- int cs_in_use; /* bitmask, bit 0 for cs0, bit 1 for cs1, etc. */
- int cs_on_dimm[MAX_DIMM_NUM]; /* bitmask */
- unsigned long long cs_base_addr[MAX_CS_NUM];
- unsigned long long cs_size[MAX_CS_NUM];
- unsigned long long base_addr;
- unsigned long long total_mem;
-};
-
-struct ddr_info {
- unsigned long clk;
- unsigned long long mem_base;
- unsigned int num_ctlrs;
- unsigned int dimm_on_ctlr;
- struct dimm_params dimm;
- struct memctl_opt opt;
- struct ddr_conf conf;
- struct ddr_cfg_regs ddr_reg;
- struct ccsr_ddr *ddr[MAX_DDRC_NUM];
- uint16_t *phy[MAX_DDRC_NUM];
- int *spd_addr;
- unsigned int ip_rev;
- uintptr_t phy_gen2_fw_img_buf;
- void *img_loadr;
- int warm_boot_flag;
-};
-
-struct rc_timing {
- unsigned int speed_bin;
- unsigned int clk_adj;
- unsigned int wrlvl;
-};
-
-struct board_timing {
- unsigned int rc;
- struct rc_timing const *p;
- unsigned int add1;
- unsigned int add2;
-};
-
-enum warm_boot {
- DDR_COLD_BOOT = 0,
- DDR_WARM_BOOT = 1,
- DDR_WRM_BOOT_NT_SUPPORTED = -1,
-};
-
-int disable_unused_ddrc(struct ddr_info *priv, int mask,
- uintptr_t nxp_ccn_hn_f0_addr);
-int ddr_board_options(struct ddr_info *priv);
-int compute_ddrc(const unsigned long clk,
- const struct memctl_opt *popts,
- const struct ddr_conf *conf,
- struct ddr_cfg_regs *ddr,
- const struct dimm_params *dimm_params,
- const unsigned int ip_rev);
-int compute_ddr_phy(struct ddr_info *priv);
-int ddrc_set_regs(const unsigned long clk,
- const struct ddr_cfg_regs *regs,
- const struct ccsr_ddr *ddr,
- int twopass);
-int cal_board_params(struct ddr_info *priv,
- const struct board_timing *dimm,
- int len);
-/* return bit mask of used DIMM(s) */
-int ddr_get_ddr_params(struct dimm_params *pdimm, struct ddr_conf *conf);
-long long dram_init(struct ddr_info *priv
-#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
- , uintptr_t nxp_ccn_hn_f0_addr
-#endif
- );
-long long board_static_ddr(struct ddr_info *info);
-
-#endif /* DDR_H */
diff --git a/drivers/nxp/ddr/include/ddr_io.h b/drivers/nxp/ddr/include/ddr_io.h
deleted file mode 100644
index fbd7e974d5..0000000000
--- a/drivers/nxp/ddr/include/ddr_io.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DDR_IO_H
-#define DDR_IO_H
-
-#include <endian.h>
-
-#include <lib/mmio.h>
-
-#define min(a, b) (((a) > (b)) ? (b) : (a))
-
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-
-/* macro for memory barrier */
-#define mb() asm volatile("dsb sy" : : : "memory")
-
-#ifdef NXP_DDR_BE
-#define ddr_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define ddr_out32(a, v) mmio_write_32((uintptr_t)(a),\
- bswap32(v))
-#elif defined(NXP_DDR_LE)
-#define ddr_in32(a) mmio_read_32((uintptr_t)(a))
-#define ddr_out32(a, v) mmio_write_32((uintptr_t)(a), v)
-#else
-#error Please define CCSR DDR register endianness
-#endif
-
-#define ddr_setbits32(a, v) ddr_out32((a), ddr_in32(a) | (v))
-#define ddr_clrbits32(a, v) ddr_out32((a), ddr_in32(a) & ~(v))
-#define ddr_clrsetbits32(a, c, s) ddr_out32((a), (ddr_in32(a) & ~(c)) \
- | (s))
-
-#endif /* DDR_IO_H */
diff --git a/drivers/nxp/ddr/include/dimm.h b/drivers/nxp/ddr/include/dimm.h
deleted file mode 100644
index fcae179845..0000000000
--- a/drivers/nxp/ddr/include/dimm.h
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DIMM_H
-#define DIMM_H
-
-#define SPD_MEMTYPE_DDR4 0x0C
-
-#define DDR4_SPD_MODULETYPE_MASK 0x0f
-#define DDR4_SPD_MODULETYPE_EXT 0x00
-#define DDR4_SPD_RDIMM 0x01
-#define DDR4_SPD_UDIMM 0x02
-#define DDR4_SPD_SO_DIMM 0x03
-#define DDR4_SPD_LRDIMM 0x04
-#define DDR4_SPD_MINI_RDIMM 0x05
-#define DDR4_SPD_MINI_UDIMM 0x06
-#define DDR4_SPD_72B_SO_RDIMM 0x08
-#define DDR4_SPD_72B_SO_UDIMM 0x09
-#define DDR4_SPD_16B_SO_DIMM 0x0c
-#define DDR4_SPD_32B_SO_DIMM 0x0d
-
-#define SPD_SPA0_ADDRESS 0x36
-#define SPD_SPA1_ADDRESS 0x37
-
-#define spd_to_ps(mtb, ftb) \
- ((mtb) * pdimm->mtb_ps + ((ftb) * pdimm->ftb_10th_ps) / 10)
-
-#ifdef DDR_DEBUG
-#define dump_spd(spd, len) { \
- register int i; \
- register unsigned char *buf = (void *)(spd); \
- \
- for (i = 0; i < (len); i++) { \
- print_uint(i); \
- puts("\t: 0x"); \
- print_hex(buf[i]); \
- puts("\n"); \
- } \
-}
-#else
-#define dump_spd(spd, len) {}
-#endif
-
-/* From JEEC Standard No. 21-C release 23A */
-struct ddr4_spd {
- /* General Section: Bytes 0-127 */
- unsigned char info_size_crc; /* 0 # bytes */
- unsigned char spd_rev; /* 1 Total # bytes of SPD */
- unsigned char mem_type; /* 2 Key Byte / mem type */
- unsigned char module_type; /* 3 Key Byte / Module Type */
- unsigned char density_banks; /* 4 Density and Banks */
- unsigned char addressing; /* 5 Addressing */
- unsigned char package_type; /* 6 Package type */
- unsigned char opt_feature; /* 7 Optional features */
- unsigned char thermal_ref; /* 8 Thermal and refresh */
- unsigned char oth_opt_features; /* 9 Other optional features */
- unsigned char res_10; /* 10 Reserved */
- unsigned char module_vdd; /* 11 Module nominal voltage */
- unsigned char organization; /* 12 Module Organization */
- unsigned char bus_width; /* 13 Module Memory Bus Width */
- unsigned char therm_sensor; /* 14 Module Thermal Sensor */
- unsigned char ext_type; /* 15 Extended module type */
- unsigned char res_16;
- unsigned char timebases; /* 17 MTb and FTB */
- unsigned char tck_min; /* 18 tCKAVGmin */
- unsigned char tck_max; /* 19 TCKAVGmax */
- unsigned char caslat_b1; /* 20 CAS latencies, 1st byte */
- unsigned char caslat_b2; /* 21 CAS latencies, 2nd byte */
- unsigned char caslat_b3; /* 22 CAS latencies, 3rd byte */
- unsigned char caslat_b4; /* 23 CAS latencies, 4th byte */
- unsigned char taa_min; /* 24 Min CAS Latency Time */
- unsigned char trcd_min; /* 25 Min RAS# to CAS# Delay Time */
- unsigned char trp_min; /* 26 Min Row Precharge Delay Time */
- unsigned char tras_trc_ext; /* 27 Upper Nibbles for tRAS and tRC */
- unsigned char tras_min_lsb; /* 28 tRASmin, lsb */
- unsigned char trc_min_lsb; /* 29 tRCmin, lsb */
- unsigned char trfc1_min_lsb; /* 30 Min Refresh Recovery Delay Time */
- unsigned char trfc1_min_msb; /* 31 Min Refresh Recovery Delay Time */
- unsigned char trfc2_min_lsb; /* 32 Min Refresh Recovery Delay Time */
- unsigned char trfc2_min_msb; /* 33 Min Refresh Recovery Delay Time */
- unsigned char trfc4_min_lsb; /* 34 Min Refresh Recovery Delay Time */
- unsigned char trfc4_min_msb; /* 35 Min Refresh Recovery Delay Time */
- unsigned char tfaw_msb; /* 36 Upper Nibble for tFAW */
- unsigned char tfaw_min; /* 37 tFAW, lsb */
- unsigned char trrds_min; /* 38 tRRD_Smin, MTB */
- unsigned char trrdl_min; /* 39 tRRD_Lmin, MTB */
- unsigned char tccdl_min; /* 40 tCCS_Lmin, MTB */
- unsigned char res_41[60-41]; /* 41 Rserved */
- unsigned char mapping[78-60]; /* 60~77 Connector to SDRAM bit map */
- unsigned char res_78[117-78]; /* 78~116, Reserved */
- signed char fine_tccdl_min; /* 117 Fine offset for tCCD_Lmin */
- signed char fine_trrdl_min; /* 118 Fine offset for tRRD_Lmin */
- signed char fine_trrds_min; /* 119 Fine offset for tRRD_Smin */
- signed char fine_trc_min; /* 120 Fine offset for tRCmin */
- signed char fine_trp_min; /* 121 Fine offset for tRPmin */
- signed char fine_trcd_min; /* 122 Fine offset for tRCDmin */
- signed char fine_taa_min; /* 123 Fine offset for tAAmin */
- signed char fine_tck_max; /* 124 Fine offset for tCKAVGmax */
- signed char fine_tck_min; /* 125 Fine offset for tCKAVGmin */
- /* CRC: Bytes 126-127 */
- unsigned char crc[2]; /* 126-127 SPD CRC */
-
- /* Module-Specific Section: Bytes 128-255 */
- union {
- struct {
- /* 128 (Unbuffered) Module Nominal Height */
- unsigned char mod_height;
- /* 129 (Unbuffered) Module Maximum Thickness */
- unsigned char mod_thickness;
- /* 130 (Unbuffered) Reference Raw Card Used */
- unsigned char ref_raw_card;
- /* 131 (Unbuffered) Address Mapping from
- * Edge Connector to DRAM
- */
- unsigned char addr_mapping;
- /* 132~253 (Unbuffered) Reserved */
- unsigned char res_132[254-132];
- /* 254~255 CRC */
- unsigned char crc[2];
- } unbuffered;
- struct {
- /* 128 (Registered) Module Nominal Height */
- unsigned char mod_height;
- /* 129 (Registered) Module Maximum Thickness */
- unsigned char mod_thickness;
- /* 130 (Registered) Reference Raw Card Used */
- unsigned char ref_raw_card;
- /* 131 DIMM Module Attributes */
- unsigned char modu_attr;
- /* 132 RDIMM Thermal Heat Spreader Solution */
- unsigned char thermal;
- /* 133 Register Manufacturer ID Code, LSB */
- unsigned char reg_id_lo;
- /* 134 Register Manufacturer ID Code, MSB */
- unsigned char reg_id_hi;
- /* 135 Register Revision Number */
- unsigned char reg_rev;
- /* 136 Address mapping from register to DRAM */
- unsigned char reg_map;
- unsigned char ca_stren;
- unsigned char clk_stren;
- /* 139~253 Reserved */
- unsigned char res_139[254-139];
- /* 254~255 CRC */
- unsigned char crc[2];
- } registered;
- struct {
- /* 128 (Loadreduced) Module Nominal Height */
- unsigned char mod_height;
- /* 129 (Loadreduced) Module Maximum Thickness */
- unsigned char mod_thickness;
- /* 130 (Loadreduced) Reference Raw Card Used */
- unsigned char ref_raw_card;
- /* 131 DIMM Module Attributes */
- unsigned char modu_attr;
- /* 132 RDIMM Thermal Heat Spreader Solution */
- unsigned char thermal;
- /* 133 Register Manufacturer ID Code, LSB */
- unsigned char reg_id_lo;
- /* 134 Register Manufacturer ID Code, MSB */
- unsigned char reg_id_hi;
- /* 135 Register Revision Number */
- unsigned char reg_rev;
- /* 136 Address mapping from register to DRAM */
- unsigned char reg_map;
- /* 137 Register Output Drive Strength for CMD/Add*/
- unsigned char reg_drv;
- /* 138 Register Output Drive Strength for CK */
- unsigned char reg_drv_ck;
- /* 139 Data Buffer Revision Number */
- unsigned char data_buf_rev;
- /* 140 DRAM VrefDQ for Package Rank 0 */
- unsigned char vrefqe_r0;
- /* 141 DRAM VrefDQ for Package Rank 1 */
- unsigned char vrefqe_r1;
- /* 142 DRAM VrefDQ for Package Rank 2 */
- unsigned char vrefqe_r2;
- /* 143 DRAM VrefDQ for Package Rank 3 */
- unsigned char vrefqe_r3;
- /* 144 Data Buffer VrefDQ for DRAM Interface */
- unsigned char data_intf;
- /*
- * 145 Data Buffer MDQ Drive Strength and RTT
- * for data rate <= 1866
- */
- unsigned char data_drv_1866;
- /*
- * 146 Data Buffer MDQ Drive Strength and RTT
- * for 1866 < data rate <= 2400
- */
- unsigned char data_drv_2400;
- /*
- * 147 Data Buffer MDQ Drive Strength and RTT
- * for 2400 < data rate <= 3200
- */
- unsigned char data_drv_3200;
- /* 148 DRAM Drive Strength */
- unsigned char dram_drv;
- /*
- * 149 DRAM ODT (RTT_WR, RTT_NOM)
- * for data rate <= 1866
- */
- unsigned char dram_odt_1866;
- /*
- * 150 DRAM ODT (RTT_WR, RTT_NOM)
- * for 1866 < data rate <= 2400
- */
- unsigned char dram_odt_2400;
- /*
- * 151 DRAM ODT (RTT_WR, RTT_NOM)
- * for 2400 < data rate <= 3200
- */
- unsigned char dram_odt_3200;
- /*
- * 152 DRAM ODT (RTT_PARK)
- * for data rate <= 1866
- */
- unsigned char dram_odt_park_1866;
- /*
- * 153 DRAM ODT (RTT_PARK)
- * for 1866 < data rate <= 2400
- */
- unsigned char dram_odt_park_2400;
- /*
- * 154 DRAM ODT (RTT_PARK)
- * for 2400 < data rate <= 3200
- */
- unsigned char dram_odt_park_3200;
- unsigned char res_155[254-155]; /* Reserved */
- /* 254~255 CRC */
- unsigned char crc[2];
- } loadreduced;
- unsigned char uc[128]; /* 128-255 Module-Specific Section */
- } mod_section;
-
- unsigned char res_256[320-256]; /* 256~319 Reserved */
-
- /* Module supplier's data: Byte 320~383 */
- unsigned char mmid_lsb; /* 320 Module MfgID Code LSB */
- unsigned char mmid_msb; /* 321 Module MfgID Code MSB */
- unsigned char mloc; /* 322 Mfg Location */
- unsigned char mdate[2]; /* 323~324 Mfg Date */
- unsigned char sernum[4]; /* 325~328 Module Serial Number */
- unsigned char mpart[20]; /* 329~348 Mfg's Module Part Number */
- unsigned char mrev; /* 349 Module Revision Code */
- unsigned char dmid_lsb; /* 350 DRAM MfgID Code LSB */
- unsigned char dmid_msb; /* 351 DRAM MfgID Code MSB */
- unsigned char stepping; /* 352 DRAM stepping */
- unsigned char msd[29]; /* 353~381 Mfg's Specific Data */
- unsigned char res_382[2]; /* 382~383 Reserved */
-};
-
-/* Parameters for a DDR dimm computed from the SPD */
-struct dimm_params {
- /* DIMM organization parameters */
- char mpart[19]; /* guaranteed null terminated */
-
- unsigned int n_ranks;
- unsigned int die_density;
- unsigned long long rank_density;
- unsigned long long capacity;
- unsigned int primary_sdram_width;
- unsigned int ec_sdram_width;
- unsigned int rdimm;
- unsigned int package_3ds; /* number of dies in 3DS */
- unsigned int device_width; /* x4, x8, x16 components */
- unsigned int rc;
-
- /* SDRAM device parameters */
- unsigned int n_row_addr;
- unsigned int n_col_addr;
- unsigned int edc_config; /* 0 = none, 1 = parity, 2 = ECC */
- unsigned int bank_addr_bits;
- unsigned int bank_group_bits;
- unsigned int burst_lengths_bitmask; /* BL=4 bit 2, BL=8 = bit 3 */
-
- /* mirrored DIMMs */
- unsigned int mirrored_dimm; /* only for ddr3 */
-
- /* DIMM timing parameters */
-
- int mtb_ps; /* medium timebase ps */
- int ftb_10th_ps; /* fine timebase, in 1/10 ps */
- int taa_ps; /* minimum CAS latency time */
- int tfaw_ps; /* four active window delay */
-
- /*
- * SDRAM clock periods
- * The range for these are 1000-10000 so a short should be sufficient
- */
- int tckmin_x_ps;
- int tckmax_ps;
-
- /* SPD-defined CAS latencies */
- unsigned int caslat_x;
-
- /* basic timing parameters */
- int trcd_ps;
- int trp_ps;
- int tras_ps;
-
- int trfc1_ps;
- int trfc2_ps;
- int trfc4_ps;
- int trrds_ps;
- int trrdl_ps;
- int tccdl_ps;
- int trfc_slr_ps;
-
- int trc_ps; /* maximum = 254 ns + .75 ns = 254750 ps */
- int twr_ps; /* 15ns for all speed bins */
-
- unsigned int refresh_rate_ps;
- unsigned int extended_op_srt;
-
- /* RDIMM */
- unsigned char rcw[16]; /* Register Control Word 0-15 */
- unsigned int dq_mapping[18];
- unsigned int dq_mapping_ors;
-};
-
-int read_spd(unsigned char chip, void *buf, int len);
-int crc16(unsigned char *ptr, int count);
-int cal_dimm_params(const struct ddr4_spd *spd, struct dimm_params *pdimm);
-
-#endif /* DIMM_H */
diff --git a/drivers/nxp/ddr/include/immap.h b/drivers/nxp/ddr/include/immap.h
deleted file mode 100644
index 83b4de6ef7..0000000000
--- a/drivers/nxp/ddr/include/immap.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DDR_IMMAP_H
-#define DDR_IMMAP_H
-
-#define DDR_DBUS_64 0
-#define DDR_DBUS_32 1
-#define DDR_DBUS_16 2
-
-/*
- * DDRC register file for DDRC 5.0 and above
- */
-struct ccsr_ddr {
- struct {
- unsigned int a; /* 0x0, 0x8, 0x10, 0x18 */
- unsigned int res; /* 0x4, 0xc, 0x14, 0x1c */
- } bnds[4];
- unsigned char res_20[0x40 - 0x20];
- unsigned int dec[10]; /* 0x40 */
- unsigned char res_68[0x80 - 0x68];
- unsigned int csn_cfg[4]; /* 0x80, 0x84, 0x88, 0x8c */
- unsigned char res_90[48];
- unsigned int csn_cfg_2[4]; /* 0xc0, 0xc4, 0xc8, 0xcc */
- unsigned char res_d0[48];
- unsigned int timing_cfg_3; /* SDRAM Timing Configuration 3 */
- unsigned int timing_cfg_0; /* SDRAM Timing Configuration 0 */
- unsigned int timing_cfg_1; /* SDRAM Timing Configuration 1 */
- unsigned int timing_cfg_2; /* SDRAM Timing Configuration 2 */
- unsigned int sdram_cfg; /* SDRAM Control Configuration */
- unsigned int sdram_cfg_2; /* SDRAM Control Configuration 2 */
- unsigned int sdram_mode; /* SDRAM Mode Configuration */
- unsigned int sdram_mode_2; /* SDRAM Mode Configuration 2 */
- unsigned int sdram_md_cntl; /* SDRAM Mode Control */
- unsigned int sdram_interval; /* SDRAM Interval Configuration */
- unsigned int sdram_data_init; /* SDRAM Data initialization */
- unsigned char res_12c[4];
- unsigned int sdram_clk_cntl; /* SDRAM Clock Control */
- unsigned char res_134[20];
- unsigned int init_addr; /* training init addr */
- unsigned int init_ext_addr; /* training init extended addr */
- unsigned char res_150[16];
- unsigned int timing_cfg_4; /* SDRAM Timing Configuration 4 */
- unsigned int timing_cfg_5; /* SDRAM Timing Configuration 5 */
- unsigned int timing_cfg_6; /* SDRAM Timing Configuration 6 */
- unsigned int timing_cfg_7; /* SDRAM Timing Configuration 7 */
- unsigned int zq_cntl; /* ZQ calibration control*/
- unsigned int wrlvl_cntl; /* write leveling control*/
- unsigned char reg_178[4];
- unsigned int ddr_sr_cntr; /* self refresh counter */
- unsigned int ddr_sdram_rcw_1; /* Control Words 1 */
- unsigned int ddr_sdram_rcw_2; /* Control Words 2 */
- unsigned char reg_188[8];
- unsigned int ddr_wrlvl_cntl_2; /* write leveling control 2 */
- unsigned int ddr_wrlvl_cntl_3; /* write leveling control 3 */
- unsigned char res_198[0x1a0-0x198];
- unsigned int ddr_sdram_rcw_3;
- unsigned int ddr_sdram_rcw_4;
- unsigned int ddr_sdram_rcw_5;
- unsigned int ddr_sdram_rcw_6;
- unsigned char res_1b0[0x200-0x1b0];
- unsigned int sdram_mode_3; /* SDRAM Mode Configuration 3 */
- unsigned int sdram_mode_4; /* SDRAM Mode Configuration 4 */
- unsigned int sdram_mode_5; /* SDRAM Mode Configuration 5 */
- unsigned int sdram_mode_6; /* SDRAM Mode Configuration 6 */
- unsigned int sdram_mode_7; /* SDRAM Mode Configuration 7 */
- unsigned int sdram_mode_8; /* SDRAM Mode Configuration 8 */
- unsigned char res_218[0x220-0x218];
- unsigned int sdram_mode_9; /* SDRAM Mode Configuration 9 */
- unsigned int sdram_mode_10; /* SDRAM Mode Configuration 10 */
- unsigned int sdram_mode_11; /* SDRAM Mode Configuration 11 */
- unsigned int sdram_mode_12; /* SDRAM Mode Configuration 12 */
- unsigned int sdram_mode_13; /* SDRAM Mode Configuration 13 */
- unsigned int sdram_mode_14; /* SDRAM Mode Configuration 14 */
- unsigned int sdram_mode_15; /* SDRAM Mode Configuration 15 */
- unsigned int sdram_mode_16; /* SDRAM Mode Configuration 16 */
- unsigned char res_240[0x250-0x240];
- unsigned int timing_cfg_8; /* SDRAM Timing Configuration 8 */
- unsigned int timing_cfg_9; /* SDRAM Timing Configuration 9 */
- unsigned int timing_cfg_10; /* SDRAM Timing COnfigurtion 10 */
- unsigned char res_258[0x260-0x25c];
- unsigned int sdram_cfg_3;
- unsigned char res_264[0x270-0x264];
- unsigned int sdram_md_cntl_2;
- unsigned char res_274[0x400-0x274];
- unsigned int dq_map[4];
- unsigned char res_410[0x800-0x410];
- unsigned int tx_cfg[4];
- unsigned char res_810[0xb20-0x810];
- unsigned int ddr_dsr1; /* Debug Status 1 */
- unsigned int ddr_dsr2; /* Debug Status 2 */
- unsigned int ddr_cdr1; /* Control Driver 1 */
- unsigned int ddr_cdr2; /* Control Driver 2 */
- unsigned char res_b30[200];
- unsigned int ip_rev1; /* IP Block Revision 1 */
- unsigned int ip_rev2; /* IP Block Revision 2 */
- unsigned int eor; /* Enhanced Optimization Register */
- unsigned char res_c04[252];
- unsigned int mtcr; /* Memory Test Control Register */
- unsigned char res_d04[28];
- unsigned int mtp[10]; /* Memory Test Patterns */
- unsigned char res_d48[184];
- unsigned int data_err_inject_hi; /* Data Path Err Injection Mask Hi*/
- unsigned int data_err_inject_lo;/* Data Path Err Injection Mask Lo*/
- unsigned int ecc_err_inject; /* Data Path Err Injection Mask ECC */
- unsigned char res_e0c[20];
- unsigned int capture_data_hi; /* Data Path Read Capture High */
- unsigned int capture_data_lo; /* Data Path Read Capture Low */
- unsigned int capture_ecc; /* Data Path Read Capture ECC */
- unsigned char res_e2c[20];
- unsigned int err_detect; /* Error Detect */
- unsigned int err_disable; /* Error Disable */
- unsigned int err_int_en;
- unsigned int capture_attributes; /* Error Attrs Capture */
- unsigned int capture_address; /* Error Addr Capture */
- unsigned int capture_ext_address; /* Error Extended Addr Capture */
- unsigned int err_sbe; /* Single-Bit ECC Error Management */
- unsigned char res_e5c[164];
- unsigned int debug[64]; /* debug_1 to debug_64 */
-};
-#endif /* DDR_IMMAP_H */
diff --git a/drivers/nxp/ddr/include/opts.h b/drivers/nxp/ddr/include/opts.h
deleted file mode 100644
index f32891bc85..0000000000
--- a/drivers/nxp/ddr/include/opts.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DDR_OPTS_H
-#define DDR_OPTS_H
-
-#define SDRAM_TYPE_DDR4 5 /* sdram_cfg register */
-
-#define DDR_BC4 4 /* burst chop */
-#define DDR_OTF 6 /* on-the-fly BC4 and BL8 */
-#define DDR_BL8 8 /* burst length 8 */
-
-#define DDR4_RTT_OFF 0
-#define DDR4_RTT_60_OHM 1 /* RZQ/4 */
-#define DDR4_RTT_120_OHM 2 /* RZQ/2 */
-#define DDR4_RTT_40_OHM 3 /* RZQ/6 */
-#define DDR4_RTT_240_OHM 4 /* RZQ/1 */
-#define DDR4_RTT_48_OHM 5 /* RZQ/5 */
-#define DDR4_RTT_80_OHM 6 /* RZQ/3 */
-#define DDR4_RTT_34_OHM 7 /* RZQ/7 */
-#define DDR4_RTT_WR_OFF 0
-#define DDR4_RTT_WR_120_OHM 1
-#define DDR4_RTT_WR_240_OHM 2
-#define DDR4_RTT_WR_HZ 3
-#define DDR4_RTT_WR_80_OHM 4
-#define DDR_ODT_NEVER 0x0
-#define DDR_ODT_CS 0x1
-#define DDR_ODT_ALL_OTHER_CS 0x2
-#define DDR_ODT_OTHER_DIMM 0x3
-#define DDR_ODT_ALL 0x4
-#define DDR_ODT_SAME_DIMM 0x5
-#define DDR_ODT_CS_AND_OTHER_DIMM 0x6
-#define DDR_ODT_OTHER_CS_ONSAMEDIMM 0x7
-#define DDR_BA_INTLV_CS01 0x40
-#define DDR_BA_INTLV_CS0123 0x64
-#define DDR_BA_NONE 0
-#define DDR_256B_INTLV 0x8
-
-struct memctl_opt {
- int rdimm;
- unsigned int dbw_cap_shift;
- struct local_opts_s {
- unsigned int auto_precharge;
- unsigned int odt_rd_cfg;
- unsigned int odt_wr_cfg;
- unsigned int odt_rtt_norm;
- unsigned int odt_rtt_wr;
- } cs_odt[DDRC_NUM_CS];
- int ctlr_intlv;
- unsigned int ctlr_intlv_mode;
- unsigned int ba_intlv;
- int addr_hash;
- int ecc_mode;
- int ctlr_init_ecc;
- int self_refresh_in_sleep;
- int self_refresh_irq_en;
- int dynamic_power;
- /* memory data width 0 = 64-bit, 1 = 32-bit, 2 = 16-bit */
- unsigned int data_bus_dimm;
- unsigned int data_bus_used; /* on individual board */
- unsigned int burst_length; /* BC4, OTF and BL8 */
- int otf_burst_chop_en;
- int mirrored_dimm;
- int quad_rank_present;
- int output_driver_impedance;
- int ap_en;
- int x4_en;
-
- int caslat_override;
- unsigned int caslat_override_value;
- int addt_lat_override;
- unsigned int addt_lat_override_value;
-
- unsigned int clk_adj;
- unsigned int cpo_sample;
- unsigned int wr_data_delay;
-
- unsigned int cswl_override;
- unsigned int wrlvl_override;
- unsigned int wrlvl_sample;
- unsigned int wrlvl_start;
- unsigned int wrlvl_ctl_2;
- unsigned int wrlvl_ctl_3;
-
- int half_strength_drive_en;
- int twot_en;
- int threet_en;
- unsigned int bstopre;
- unsigned int tfaw_ps;
-
- int rtt_override;
- unsigned int rtt_override_value;
- unsigned int rtt_wr_override_value;
- unsigned int rtt_park;
-
- int auto_self_refresh_en;
- unsigned int sr_it;
- unsigned int ddr_cdr1;
- unsigned int ddr_cdr2;
-
- unsigned int trwt_override;
- unsigned int trwt;
- unsigned int twrt;
- unsigned int trrt;
- unsigned int twwt;
-
- unsigned int vref_phy;
- unsigned int vref_dimm;
- unsigned int odt;
- unsigned int phy_tx_impedance;
- unsigned int phy_atx_impedance;
- unsigned int skip2d;
-};
-
-#endif /* DDR_OPTS_H */
diff --git a/drivers/nxp/ddr/include/regs.h b/drivers/nxp/ddr/include/regs.h
deleted file mode 100644
index e85fd8fa85..0000000000
--- a/drivers/nxp/ddr/include/regs.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef DDR_REG_H
-#define DDR_REG_H
-
-#define SDRAM_CS_CONFIG_EN 0x80000000
-
-/* DDR_SDRAM_CFG - DDR SDRAM Control Configuration
- */
-#define SDRAM_CFG_MEM_EN 0x80000000
-#define SDRAM_CFG_SREN 0x40000000
-#define SDRAM_CFG_ECC_EN 0x20000000
-#define SDRAM_CFG_RD_EN 0x10000000
-#define SDRAM_CFG_SDRAM_TYPE_MASK 0x07000000
-#define SDRAM_CFG_SDRAM_TYPE_SHIFT 24
-#define SDRAM_CFG_DYN_PWR 0x00200000
-#define SDRAM_CFG_DBW_MASK 0x00180000
-#define SDRAM_CFG_DBW_SHIFT 19
-#define SDRAM_CFG_32_BW 0x00080000
-#define SDRAM_CFG_16_BW 0x00100000
-#define SDRAM_CFG_8_BW 0x00180000
-#define SDRAM_CFG_8_BE 0x00040000
-#define SDRAM_CFG_2T_EN 0x00008000
-#define SDRAM_CFG_MEM_HLT 0x00000002
-#define SDRAM_CFG_BI 0x00000001
-
-#define SDRAM_CFG2_FRC_SR 0x80000000
-#define SDRAM_CFG2_FRC_SR_CLEAR ~(SDRAM_CFG2_FRC_SR)
-#define SDRAM_CFG2_D_INIT 0x00000010
-#define SDRAM_CFG2_AP_EN 0x00000020
-#define SDRAM_CFG2_ODT_ONLY_READ 2
-
-#define SDRAM_CFG3_DDRC_RST 0x80000000
-
-#define SDRAM_INTERVAL_REFINT 0xFFFF0000
-#define SDRAM_INTERVAL_REFINT_CLEAR ~(SDRAM_INTERVAL_REFINT)
-#define SDRAM_INTERVAL_BSTOPRE 0x3FFF
-
-/* DDR_MD_CNTL */
-#define MD_CNTL_MD_EN 0x80000000
-#define MD_CNTL_CS_SEL(x) (((x) & 0x7) << 28)
-#define MD_CNTL_MD_SEL(x) (((x) & 0xf) << 24)
-#define MD_CNTL_CKE(x) (((x) & 0x3) << 20)
-
-/* DDR_CDR1 */
-#define DDR_CDR1_DHC_EN 0x80000000
-#define DDR_CDR1_ODT_SHIFT 17
-#define DDR_CDR1_ODT_MASK 0x6
-#define DDR_CDR2_ODT_MASK 0x1
-#define DDR_CDR1_ODT(x) ((x & DDR_CDR1_ODT_MASK) << DDR_CDR1_ODT_SHIFT)
-#define DDR_CDR2_ODT(x) (x & DDR_CDR2_ODT_MASK)
-#define DDR_CDR2_VREF_OVRD(x) (0x00008080 | ((((x) - 37) & 0x3F) << 8))
-#define DDR_CDR2_VREF_TRAIN_EN 0x00000080
-#define DDR_CDR2_VREF_RANGE_2 0x00000040
-#define DDR_CDR_ODT_OFF 0x0
-#define DDR_CDR_ODT_100ohm 0x1
-#define DDR_CDR_ODT_120OHM 0x2
-#define DDR_CDR_ODT_80ohm 0x3
-#define DDR_CDR_ODT_60ohm 0x4
-#define DDR_CDR_ODT_40ohm 0x5
-#define DDR_CDR_ODT_50ohm 0x6
-#define DDR_CDR_ODT_30ohm 0x7
-
-
-/* DDR ERR_DISABLE */
-#define DDR_ERR_DISABLE_APED (1 << 8) /* Address parity error disable */
-#define DDR_ERR_DISABLE_SBED (1 << 2) /* Address parity error disable */
-#define DDR_ERR_DISABLE_MBED (1 << 3) /* Address parity error disable */
-
-/* Mode Registers */
-#define DDR_MR5_CA_PARITY_LAT_4_CLK 0x1 /* for DDR4-1600/1866/2133 */
-#define DDR_MR5_CA_PARITY_LAT_5_CLK 0x2 /* for DDR4-2400 */
-
-/* DDR DSR2 register */
-#define DDR_DSR_2_PHY_INIT_CMPLT 0x4
-
-/* SDRAM TIMING_CFG_10 register */
-#define DDR_TIMING_CFG_10_T_STAB 0x7FFF
-
-/* DEBUG 2 register */
-#define DDR_DBG_2_MEM_IDLE 0x00000002
-
-/* DEBUG 26 register */
-#define DDR_DEBUG_26_BIT_6 (0x1 << 6)
-#define DDR_DEBUG_26_BIT_7 (0x1 << 7)
-#define DDR_DEBUG_26_BIT_12 (0x1 << 12)
-#define DDR_DEBUG_26_BIT_13 (0x1 << 13)
-#define DDR_DEBUG_26_BIT_14 (0x1 << 14)
-#define DDR_DEBUG_26_BIT_15 (0x1 << 15)
-#define DDR_DEBUG_26_BIT_16 (0x1 << 16)
-#define DDR_DEBUG_26_BIT_17 (0x1 << 17)
-#define DDR_DEBUG_26_BIT_18 (0x1 << 18)
-#define DDR_DEBUG_26_BIT_19 (0x1 << 19)
-#define DDR_DEBUG_26_BIT_24 (0x1 << 24)
-#define DDR_DEBUG_26_BIT_25 (0x1 << 25)
-
-#define DDR_DEBUG_26_BIT_24_CLEAR ~(DDR_DEBUG_26_BIT_24)
-
-/* DEBUG_29 register */
-#define DDR_TX_BD_DIS (1 << 10) /* Transmit Bit Deskew Disable */
-
-#define DDR_INIT_ADDR_EXT_UIA (1 << 31)
-
-#endif /* DDR_REG_H */
diff --git a/drivers/nxp/ddr/include/utility.h b/drivers/nxp/ddr/include/utility.h
deleted file mode 100644
index 2e22ad5c36..0000000000
--- a/drivers/nxp/ddr/include/utility.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef UTILITY_H
-#define UTILITY_H
-
-#include <dcfg.h>
-
-#if defined(NXP_HAS_CCN504) || defined(NXP_HAS_CCN508)
-#define CCN_HN_F_SAM_CTL 0x8
-#define CCN_HN_F_REGION_SIZE 0x10000
-#endif
-
-unsigned long get_ddr_freq(struct sysinfo *sys, int ctrl_num);
-unsigned int get_memory_clk_ps(unsigned long clk);
-unsigned int picos_to_mclk(unsigned long data_rate, unsigned int picos);
-unsigned int get_ddrc_version(const struct ccsr_ddr *ddr);
-void print_ddr_info(struct ccsr_ddr *ddr);
-
-#endif
diff --git a/drivers/nxp/ddr/nxp-ddr/ddr.c b/drivers/nxp/ddr/nxp-ddr/ddr.c
index 216e05c7c3..17c2bbb2a1 100644
--- a/drivers/nxp/ddr/nxp-ddr/ddr.c
+++ b/drivers/nxp/ddr/nxp-ddr/ddr.c
@@ -5,6 +5,7 @@
*/
#include <errno.h>
+#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -268,7 +269,7 @@ static int cal_odt(const unsigned int clk,
unsigned int i;
const struct dynamic_odt *pdodt = NULL;
- const static struct dynamic_odt *table[2][5] = {
+ static const struct dynamic_odt *table[2][5] = {
{single_S, single_D, NULL, NULL},
{dual_SS, dual_DD, NULL, NULL},
};
@@ -292,7 +293,7 @@ static int cal_odt(const unsigned int clk,
}
if (pdodt == NULL) {
- ERROR("Error determing ODT.\n");
+ ERROR("Error determining ODT.\n");
return -EINVAL;
}
@@ -850,7 +851,7 @@ long long dram_init(struct ddr_info *priv
priv->ip_rev = ip_rev;
#ifndef CONFIG_STATIC_DDR
- INFO("time base %llu ms\n", time_base);
+ INFO("time base %" PRIu64 " ms\n", time_base);
debug("Parse DIMM SPD(s)\n");
valid_spd_mask = parse_spd(priv);
@@ -870,7 +871,7 @@ long long dram_init(struct ddr_info *priv
#endif
time = get_timer_val(time_base);
- INFO("Time after parsing SPD %llu ms\n", time);
+ INFO("Time after parsing SPD %" PRIu64 " ms\n", time);
debug("Synthesize configurations\n");
ret = synthesize_ctlr(priv);
if (ret != 0) {
@@ -911,11 +912,11 @@ long long dram_init(struct ddr_info *priv
}
time = get_timer_val(time_base);
- INFO("Time before programming controller %llu ms\n", time);
+ INFO("Time before programming controller %" PRIu64 " ms\n", time);
debug("Program controller registers\n");
ret = write_ddrc_regs(priv);
if (ret != 0) {
- ERROR("Programing DDRC error\n");
+ ERROR("Programming DDRC error\n");
return ret;
}
@@ -924,7 +925,7 @@ long long dram_init(struct ddr_info *priv
print_ddr_info(priv->ddr[0]);
time = get_timer_val(time_base);
- INFO("Time used by DDR driver %llu ms\n", time);
+ INFO("Time used by DDR driver %" PRIu64 " ms\n", time);
return dram_size;
}
diff --git a/drivers/nxp/ddr/nxp-ddr/ddr.mk b/drivers/nxp/ddr/nxp-ddr/ddr.mk
index 866c092169..f827a1b8d7 100644
--- a/drivers/nxp/ddr/nxp-ddr/ddr.mk
+++ b/drivers/nxp/ddr/nxp-ddr/ddr.mk
@@ -1,11 +1,9 @@
#
-# Copyright 2021 NXP
+# Copyright 2021-2022 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
-DDR_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/ddr
-
ifeq ($(PLAT_DDR_PHY), PHY_GEN2)
$(eval $(call add_define, PHY_GEN2))
PLAT_DDR_PHY_DIR := phy-gen2
@@ -21,6 +19,10 @@ ifeq (${ERRATA_DDR_A050450}, 1)
$(eval $(call add_define,ERRATA_DDR_A050450))
endif
+ifeq (${ERRATA_DDR_A050958}, 1)
+$(eval $(call add_define,ERRATA_DDR_A050958))
+endif
+
endif
ifeq ($(PLAT_DDR_PHY), PHY_GEN1)
@@ -68,12 +70,11 @@ ifeq ($(DEBUG_DDR_INPUT_CONFIG), yes)
$(eval $(call add_define, DEBUG_DDR_INPUT_CONFIG))
endif
-DDR_CNTLR_SOURCES := $(DDR_DRIVERS_PATH)/nxp-ddr/ddr.c \
- $(DDR_DRIVERS_PATH)/nxp-ddr/ddrc.c \
- $(DDR_DRIVERS_PATH)/nxp-ddr/dimm.c \
- $(DDR_DRIVERS_PATH)/nxp-ddr/regs.c \
- $(DDR_DRIVERS_PATH)/nxp-ddr/utility.c \
- $(DDR_DRIVERS_PATH)/$(PLAT_DDR_PHY_DIR)/phy.c
+DDR_CNTLR_SOURCES := $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddr.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/ddrc.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/dimm.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/regs.c \
+ $(PLAT_DRIVERS_PATH)/ddr/nxp-ddr/utility.c \
+ $(PLAT_DRIVERS_PATH)/ddr/$(PLAT_DDR_PHY_DIR)/phy.c
-PLAT_INCLUDES += -I$(DDR_DRIVERS_PATH)/nxp-ddr \
- -I$(DDR_DRIVERS_PATH)/include
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ddr
diff --git a/drivers/nxp/ddr/nxp-ddr/ddrc.c b/drivers/nxp/ddr/nxp-ddr/ddrc.c
index 17a2b6a474..4133fac1a1 100644
--- a/drivers/nxp/ddr/nxp-ddr/ddrc.c
+++ b/drivers/nxp/ddr/nxp-ddr/ddrc.c
@@ -346,7 +346,7 @@ int ddrc_set_regs(const unsigned long clk,
#ifdef ERRATA_DDR_A008511
/* Part 1 of 2 */
- /* This erraum only applies to verion 5.2.1 */
+ /* This erraum only applies to version 5.2.1 */
if (get_ddrc_version(ddr) == 0x50200) {
ERROR("Unsupported SoC.\n");
} else if (get_ddrc_version(ddr) == 0x50201) {
diff --git a/drivers/nxp/ddr/nxp-ddr/dimm.c b/drivers/nxp/ddr/nxp-ddr/dimm.c
index 16efcbaacd..a82db6c667 100644
--- a/drivers/nxp/ddr/nxp-ddr/dimm.c
+++ b/drivers/nxp/ddr/nxp-ddr/dimm.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 NXP
+ * Copyright 2021-2022 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -194,7 +194,7 @@ int cal_dimm_params(const struct ddr4_spd *spd, struct dimm_params *pdimm)
case DDR4_SPD_MINI_RDIMM:
case DDR4_SPD_72B_SO_RDIMM:
pdimm->rdimm = 1;
- pdimm->rc = spd->mod_section.registered.ref_raw_card & 0x8f;
+ pdimm->rc = spd->mod_section.registered.ref_raw_card & 0x9f;
if ((spd->mod_section.registered.reg_map & 0x1) != 0) {
pdimm->mirrored_dimm = 1;
}
@@ -223,7 +223,7 @@ int cal_dimm_params(const struct ddr4_spd *spd, struct dimm_params *pdimm)
case DDR4_SPD_72B_SO_UDIMM:
case DDR4_SPD_16B_SO_DIMM:
case DDR4_SPD_32B_SO_DIMM:
- pdimm->rc = spd->mod_section.unbuffered.ref_raw_card & 0x8f;
+ pdimm->rc = spd->mod_section.unbuffered.ref_raw_card & 0x9f;
if ((spd->mod_section.unbuffered.addr_mapping & 0x1) != 0) {
pdimm->mirrored_dimm = 1;
}
diff --git a/drivers/nxp/ddr/nxp-ddr/regs.c b/drivers/nxp/ddr/nxp-ddr/regs.c
index cedd7ca09e..26155abe09 100644
--- a/drivers/nxp/ddr/nxp-ddr/regs.c
+++ b/drivers/nxp/ddr/nxp-ddr/regs.c
@@ -1302,7 +1302,7 @@ static unsigned int skip_caslat(unsigned int tckmin_ps,
return 0;
}
- if ((bin[i].taamin_ps[j] == 0) ||
+ if (((bin[i].taamin_ps[j] == 0) && j > 0) ||
(bin[i].taamin_ps[j] > taamin_ps && j > 0)) {
j--;
}
diff --git a/drivers/nxp/ddr/nxp-ddr/utility.c b/drivers/nxp/ddr/nxp-ddr/utility.c
index d33ad77839..b6dffc872b 100644
--- a/drivers/nxp/ddr/nxp-ddr/utility.c
+++ b/drivers/nxp/ddr/nxp-ddr/utility.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 NXP
+ * Copyright 2021-2022 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -33,8 +33,10 @@
#define CCN_HN_F_SAM_NODEID_DDR0 0x4
#define CCN_HN_F_SAM_NODEID_DDR1 0xe
#elif defined(NXP_HAS_CCN508)
-#define CCN_HN_F_SAM_NODEID_DDR0 0x8
-#define CCN_HN_F_SAM_NODEID_DDR1 0x18
+#define CCN_HN_F_SAM_NODEID_DDR0_0 0x3
+#define CCN_HN_F_SAM_NODEID_DDR0_1 0x8
+#define CCN_HN_F_SAM_NODEID_DDR1_0 0x13
+#define CCN_HN_F_SAM_NODEID_DDR1_1 0x18
#endif
unsigned long get_ddr_freq(struct sysinfo *sys, int ctrl_num)
@@ -166,10 +168,21 @@ int disable_unused_ddrc(struct ddr_info *priv,
for (i = 0; i < num_hnf_nodes; i++) {
val = mmio_read_64((uintptr_t)hnf_sam_ctrl);
+#ifdef NXP_HAS_CCN504
nodeid = disable_ddrc == 1 ? CCN_HN_F_SAM_NODEID_DDR1 :
- (disable_ddrc == 2 ? CCN_HN_F_SAM_NODEID_DDR0 :
- (i < 4 ? CCN_HN_F_SAM_NODEID_DDR0
- : CCN_HN_F_SAM_NODEID_DDR1));
+ (disable_ddrc == 2 ? CCN_HN_F_SAM_NODEID_DDR0 :
+ 0x0); /*Failure condition. never hit */
+#elif defined(NXP_HAS_CCN508)
+ if (disable_ddrc == 1) {
+ nodeid = (i < 2 || i >= 6) ? CCN_HN_F_SAM_NODEID_DDR1_1 :
+ CCN_HN_F_SAM_NODEID_DDR1_0;
+ } else if (disable_ddrc == 2) {
+ nodeid = (i < 2 || i >= 6) ? CCN_HN_F_SAM_NODEID_DDR0_0 :
+ CCN_HN_F_SAM_NODEID_DDR0_1;
+ } else {
+ nodeid = 0; /* Failure condition. never hit */
+ }
+#endif
if (nodeid != (val & CCN_HN_F_SAM_NODEID_MASK)) {
debug("Setting HN-F node %d\n", i);
debug("nodeid = 0x%x\n", nodeid);
diff --git a/drivers/nxp/ddr/phy-gen2/messages.h b/drivers/nxp/ddr/phy-gen2/messages.h
index 7dec7df55f..bf2d45910a 100644
--- a/drivers/nxp/ddr/phy-gen2/messages.h
+++ b/drivers/nxp/ddr/phy-gen2/messages.h
@@ -13,7 +13,7 @@ struct phy_msg {
const char *msg;
};
-const static struct phy_msg messages_1d[] = {
+static const struct phy_msg messages_1d[] = {
{0x00000001,
"PMU1:prbsGenCtl:%x\n"
},
@@ -144,7 +144,7 @@ const static struct phy_msg messages_1d[] = {
"PMU3: Precharge all open banks\n"
},
{0x002b0002,
- "PMU: Error: Dbyte %d nibble %d found mutliple working coarse delay setting for MRD/MWD\n"
+ "PMU: Error: Dbyte %d nibble %d found multiple working coarse delay setting for MRD/MWD\n"
},
{0x002c0000,
"PMU4: MRD Passing Regions (coarseVal, fineLeft fineRight -> fineCenter)\n"
@@ -536,7 +536,7 @@ const static struct phy_msg messages_1d[] = {
"PMU3: Resetting DRAM\n"
},
{0x00b10000,
- "PMU3: setup for RCD initalization\n"
+ "PMU3: setup for RCD initialization\n"
},
{0x00b20000,
"PMU3: pmu_exit_SR from dev_init()\n"
@@ -974,10 +974,10 @@ const static struct phy_msg messages_1d[] = {
"PMU0: PHY VREF @ (%d/1000) VDDQ\n"
},
{0x01430002,
- "PMU0: initalizing phy vrefDacs to %d ExtVrefRange %x\n"
+ "PMU0: initializing phy vrefDacs to %d ExtVrefRange %x\n"
},
{0x01440002,
- "PMU0: initalizing global vref to %d range %d\n"
+ "PMU0: initializing global vref to %d range %d\n"
},
{0x01450002,
"PMU4: Setting initial device vrefDQ for CS%d to MR6 = 0x%04x\n"
@@ -1239,7 +1239,7 @@ const static struct phy_msg messages_1d[] = {
},
};
-const static struct phy_msg messages_2d[] = {
+static const struct phy_msg messages_2d[] = {
{0x00000001,
"PMU0: Converting %d into an MR\n"
},
@@ -1811,7 +1811,7 @@ const static struct phy_msg messages_2d[] = {
"PMU3: Precharge all open banks\n"
},
{0x00be0002,
- "PMU: Error: Dbyte %d nibble %d found mutliple working coarse delay setting for MRD/MWD\n"
+ "PMU: Error: Dbyte %d nibble %d found multiple working coarse delay setting for MRD/MWD\n"
},
{0x00bf0000,
"PMU4: MRD Passing Regions (coarseVal, fineLeft fineRight -> fineCenter)\n"
@@ -2203,7 +2203,7 @@ const static struct phy_msg messages_2d[] = {
"PMU3: Resetting DRAM\n"
},
{0x01440000,
- "PMU3: setup for RCD initalization\n"
+ "PMU3: setup for RCD initialization\n"
},
{0x01450000,
"PMU3: pmu_exit_SR from dev_init()\n"
@@ -2641,10 +2641,10 @@ const static struct phy_msg messages_2d[] = {
"PMU0: PHY VREF @ (%d/1000) VDDQ\n"
},
{0x01d60002,
- "PMU0: initalizing phy vrefDacs to %d ExtVrefRange %x\n"
+ "PMU0: initializing phy vrefDacs to %d ExtVrefRange %x\n"
},
{0x01d70002,
- "PMU0: initalizing global vref to %d range %d\n"
+ "PMU0: initializing global vref to %d range %d\n"
},
{0x01d80002,
"PMU4: Setting initial device vrefDQ for CS%d to MR6 = 0x%04x\n"
diff --git a/drivers/nxp/ddr/phy-gen2/phy.c b/drivers/nxp/ddr/phy-gen2/phy.c
index 97de1ae999..2006c04e89 100644
--- a/drivers/nxp/ddr/phy-gen2/phy.c
+++ b/drivers/nxp/ddr/phy-gen2/phy.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 NXP
+ * Copyright 2021-2022 NXP
* SPDX-License-Identifier: BSD-3-Clause
*
*/
@@ -241,12 +241,6 @@ static void get_cdd_val(uint16_t **phy_ptr, uint32_t rank, uint32_t freq,
rwmax = tmp;
}
- tmp = wrmax;
- wrmax = cdd[56];
- if (tmp > wrmax) {
- wrmax = tmp;
- }
-
break;
case 2U:
@@ -276,15 +270,7 @@ static void get_cdd_val(uint16_t **phy_ptr, uint32_t rank, uint32_t freq,
rwmax = tmp;
}
- buf[0] = cdd[56];
- buf[1] = cdd[55];
- buf[2] = cdd[52];
- buf[3] = cdd[51];
- tmp = wrmax;
- wrmax = findmax(buf, 4U);
- if (tmp > wrmax) {
- wrmax = tmp;
- }
+ wrmax = wwmax;
break;
@@ -310,12 +296,7 @@ static void get_cdd_val(uint16_t **phy_ptr, uint32_t rank, uint32_t freq,
rwmax = tmp;
}
- tmp = wrmax;
- c = &cdd[41];
- wrmax = findmax(c, 16U);
- if (tmp > wrmax) {
- wrmax = tmp;
- }
+ wrmax = wwmax;
break;
@@ -390,7 +371,12 @@ static void get_cdd_val(uint16_t **phy_ptr, uint32_t rank, uint32_t freq,
#ifdef NXP_WARM_BOOT
int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
- uint32_t num_of_phy, int train2d)
+ uint32_t num_of_phy, int train2d
+#ifdef NXP_APPLY_MAX_CDD
+ , struct ddr_ctrl_reg_values *ddrctrl_regs
+#endif
+ )
+
{
uint16_t *phy = NULL, value = 0x0;
uint32_t size = 1U, num_of_regs = 1U, phy_store = 0U;
@@ -457,6 +443,15 @@ int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
ret = xspi_write(phy_store, training_2D_values,
size);
}
+
+#ifdef NXP_APPLY_MAX_CDD
+ /* Save DDR control register Timing CFG 0 and 4 */
+ phy_store += size;
+ size = sizeof(ddrctrl_regs);
+ if (ret != 0) {
+ ret = xspi_write(phy_store, ddrctrl_regs, size);
+ }
+#endif
/* Disable clocks in case they were disabled. */
phy_io_write16(phy, t_drtub |
csr_ucclk_hclk_enables_addr, 0x0);
@@ -472,7 +467,11 @@ int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
}
int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
- uint32_t num_of_phy, int train2d)
+ uint32_t num_of_phy, int train2d
+#ifdef NXP_APPLY_MAX_CDD
+ , struct ddr_ctrl_reg_values *ddrctrl_regs
+#endif
+ )
{
uint16_t *phy = NULL;
uint32_t size = 1U, num_of_regs = 1U, phy_store = 0U;
@@ -504,6 +503,14 @@ int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
/* Reading 1D training values from flash*/
ret = xspi_read(phy_store, (uint32_t *)training_1D_values,
size);
+ if (ret != 0) {
+#ifdef DEBUG_WARM_RESET
+ debug("Unable to Read 1D training values %d\n",
+ ret);
+#endif
+ return -EINVAL;
+ }
+
debug("Restoring 1D Training reg val at:%08x\n", phy_store);
for (i = 0; i < num_of_regs; i++) {
phy_io_write16(phy, training_1D_values[i].addr,
@@ -523,6 +530,15 @@ int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
/* Reading 2D training values from flash */
ret = xspi_read(phy_store,
(uint32_t *)training_2D_values, size);
+
+ if (ret != 0) {
+#ifdef DEBUG_WARM_RESET
+ debug("Unable to Read 2D training values %d\n",
+ ret);
+#endif
+ return -EINVAL;
+ }
+
debug("Restoring 2D Training reg val at:%08x\n",
phy_store);
for (i = 0; i < num_of_regs; i++) {
@@ -537,6 +553,11 @@ int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
#endif
}
}
+#ifdef NXP_APPLY_MAX_CDD
+ phy_store = phy_store + size;
+ size = sizeof(ddrctrl_regs);
+ ret = xspi_read(phy_store, (uint32_t *)ddrctrl_regs, size);
+#endif
/* Disable clocks in case they were disabled. */
phy_io_write16(phy, t_drtub |
csr_ucclk_hclk_enables_addr, 0x0);
@@ -672,7 +693,7 @@ static void prog_seq0bdly0(uint16_t *phy,
#ifdef DDR_PLL_FIX
soc_info = get_soc_info();
- if (soc_info->maj_ver == 1) {
+ if (soc_info->svr_reg.bf.maj_ver == 1) {
ps_count[0] = 0x520; /* seq0bdly0 */
ps_count[1] = 0xa41; /* seq0bdly1 */
ps_count[2] = 0x668a; /* seq0bdly2 */
@@ -1093,8 +1114,8 @@ static void prog_dfi_rd_data_cs_dest_map(uint16_t *phy,
#ifdef ERRATA_DDR_A011396
/* Only apply to DDRC 5.05.00 */
- soc_info = get_soc_info(NXP_DCFG_ADDR);
- if ((soc_info->maj_ver == 1U) && (ip_rev == U(0x50500))) {
+ soc_info = get_soc_info();
+ if ((soc_info->svr_reg.bf.maj_ver == 1U) && (ip_rev == U(0x50500))) {
phy_io_write16(phy,
t_master | csr_dfi_rd_data_cs_dest_map_addr,
0U);
@@ -1673,6 +1694,10 @@ static void prog_dq_dqs_rcv_cntrl(uint16_t *phy,
int sel_analog_vref = 1;
uint32_t addr;
+#ifdef ERRATA_DDR_A050958
+ gain_curr_adj_defval = 0x1f;
+#endif
+
dq_dqs_rcv_cntrl = gain_curr_adj_defval << csr_gain_curr_adj_lsb |
major_mode_dbyte << csr_major_mode_dbyte_lsb |
dfe_ctrl_defval << csr_dfe_ctrl_lsb |
@@ -1890,8 +1915,8 @@ static int c_init_phy_config(uint16_t **phy_ptr,
prog_pll_ctrl2(phy, input);
#ifdef DDR_PLL_FIX
soc_info = get_soc_info();
- debug("SOC_SI_REV = %x\n", soc_info->maj_ver);
- if (soc_info->maj_ver == 1) {
+ debug("SOC_SI_REV = %x\n", soc_info->svr_reg.bf.maj_ver);
+ if (soc_info->svr_reg.bf.maj_ver == 1) {
prog_pll_pwr_dn(phy, input);
/*Enable FFE aka TxEqualizationMode for rev1 SI*/
@@ -2212,10 +2237,6 @@ static int load_fw(uint16_t **phy_ptr,
size = PHY_GEN2_MAX_IMAGE_SIZE;
image_buf = (uintptr_t)phy_gen2_fw_img_buf;
- mmap_add_dynamic_region(phy_gen2_fw_img_buf,
- phy_gen2_fw_img_buf,
- PHY_GEN2_MAX_IMAGE_SIZE,
- MT_MEMORY | MT_RW | MT_SECURE);
ret = img_loadr(imem_id, &image_buf, &size);
if (ret != 0) {
ERROR("Failed to load %d firmware.\n", imem_id);
@@ -2292,6 +2313,7 @@ static void parse_odt(const unsigned int val,
if (i < 0 || i > 3) {
printf("Error: invalid chip-select value\n");
+ return;
}
switch (val) {
case DDR_ODT_CS:
@@ -2473,6 +2495,9 @@ int compute_ddr_phy(struct ddr_info *priv)
__unused const soc_info_t *soc_info;
#ifdef NXP_APPLY_MAX_CDD
unsigned int tcfg0, tcfg4, rank;
+#ifdef NXP_WARM_BOOT
+ struct ddr_ctrl_reg_values ddrctrl_regs;
+#endif
#endif
if (dimm_param == NULL) {
@@ -2577,13 +2602,30 @@ int compute_ddr_phy(struct ddr_info *priv)
ret = restore_phy_training_values(priv->phy,
PHY_TRAINING_REGS_ON_FLASH,
priv->num_ctlrs,
- input.basic.train2d);
+ input.basic.train2d
+#ifdef NXP_APPLY_MAX_CDD
+ , &ddrctrl_regs
+#endif
+ );
if (ret != 0) {
ERROR("Restoring of training data failed %d\n", ret);
return ret;
}
+#ifdef NXP_APPLY_MAX_CDD
+ regs->timing_cfg[0] = ddrctrl_regs.timing_cfg0;
+ regs->timing_cfg[4] = ddrctrl_regs.timing_cfg4;
+#endif
} else {
#endif
+ /* Mapping IMG buffer firstly */
+ ret = mmap_add_dynamic_region(priv->phy_gen2_fw_img_buf,
+ priv->phy_gen2_fw_img_buf,
+ PHY_GEN2_MAX_IMAGE_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE);
+ if (ret != 0) {
+ ERROR("Failed to add dynamic memory region.\n");
+ return ret;
+ }
debug("Load 1D firmware\n");
ret = load_fw(priv->phy, &input, 0, &msg_1d,
@@ -2601,8 +2643,8 @@ int compute_ddr_phy(struct ddr_info *priv)
}
#ifdef NXP_APPLY_MAX_CDD
- soc_info = get_soc_info(NXP_DCFG_ADDR);
- if (soc_info->maj_ver == 2) {
+ soc_info = get_soc_info();
+ if (soc_info->svr_reg.bf.maj_ver == 2) {
tcfg0 = regs->timing_cfg[0];
tcfg4 = regs->timing_cfg[4];
rank = findrank(conf->cs_in_use);
@@ -2635,12 +2677,20 @@ int compute_ddr_phy(struct ddr_info *priv)
#ifdef NXP_WARM_BOOT
if (priv->warm_boot_flag != DDR_WRM_BOOT_NT_SUPPORTED &&
ret == 0) {
+#ifdef NXP_APPLY_MAX_CDD
+ ddrctrl_regs.timing_cfg0 = regs->timing_cfg[0];
+ ddrctrl_regs.timing_cfg4 = regs->timing_cfg[4];
+#endif
debug("save the phy training data\n");
//Save training data TBD
ret = save_phy_training_values(priv->phy,
PHY_TRAINING_REGS_ON_FLASH,
priv->num_ctlrs,
- input.basic.train2d);
+ input.basic.train2d
+#ifdef NXP_APPLY_MAX_CDD
+ , &ddrctrl_regs
+#endif
+ );
if (ret != 0) {
ERROR("Saving training data failed.");
ERROR("Warm boot will fail. Error=%d.\n", ret);
diff --git a/drivers/nxp/ddr/phy-gen2/phy.h b/drivers/nxp/ddr/phy-gen2/phy.h
index 15e80d10e2..5e80f36385 100644
--- a/drivers/nxp/ddr/phy-gen2/phy.h
+++ b/drivers/nxp/ddr/phy-gen2/phy.h
@@ -11,11 +11,18 @@
/* To store sector size to be erase on flash*/
#define PHY_ERASE_SIZE F_SECTOR_ERASE_SZ
+/*Structure to save DDR controller timing register 0 and 4 values*/
+struct ddr_ctrl_reg_values {
+ uint32_t timing_cfg0;
+ uint32_t timing_cfg4;
+};
+
/*Structure to implement address-data map tuples to store PHY training values*/
struct phy_training_values {
uint32_t addr;
uint16_t data;
};
+
/* Saves PHY Training Register values after cold reset
*@param[in] phy_ptr array to store addresses of PHYs
*@param[in] address_to_store address to save PHY training register values
@@ -24,6 +31,8 @@ struct phy_training_values {
*to be saved
*@param[in] train2d flag to store whether 2D training registers are to
*be saved or not
+ *@param[in] ddrctrl_regs to save ddr controller registers in case
+ *NXP_APPLY_MAX_CDD is applied
*
*PHY training values will be stored on flash at contigous memory in the order:
*1D training registers, 2D training registers
@@ -31,9 +40,13 @@ struct phy_training_values {
*
*if train2d is false saving 2D training registers will be skipped
*/
-int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
- uint32_t num_of_phy, int train2d);
+int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
+ uint32_t num_of_phy, int train2d
+#ifdef NXP_APPLY_MAX_CDD
+ , struct ddr_ctrl_reg_values *ddrctrl_regs
+#endif
+ );
/*Restores PHY Training Register values after warm reset
*@param[in] phy_ptr array to store addresses of PHYs
*@param[in] address_to_store address to retrieve PHY training register
@@ -42,12 +55,17 @@ int save_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_store,
*to be restored
*@param[in] train2d flag to store whether 2D training registers are
*to be restored or not
- *
+ *@param[in] ddrctrl_regs to restore ddr controller registers in case
+ *NXP_APPLY_MAX_CDD is applied
*if train2d is false saving 2D training registers will be skipped
*/
int restore_phy_training_values(uint16_t **phy_ptr, uint32_t address_to_restore,
- uint32_t num_of_phy, int train2d);
+ uint32_t num_of_phy, int train2d
+#ifdef NXP_APPLY_MAX_CDD
+ , struct ddr_ctrl_reg_values *ddrctrl_regs
+#endif
+ );
/*
* Address data tuples to store the PHY 1D
diff --git a/drivers/nxp/drivers.mk b/drivers/nxp/drivers.mk
index c6d55411d3..d77e985496 100644
--- a/drivers/nxp/drivers.mk
+++ b/drivers/nxp/drivers.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,7 +8,8 @@
###############################################################################
-PLAT_DRIVERS_PATH := drivers/nxp
+PLAT_DRIVERS_PATH := drivers/nxp
+PLAT_DRIVERS_INCLUDE_PATH := include/drivers/nxp
ifeq (${SMMU_NEEDED},yes)
PLAT_INCLUDES += -Iinclude/drivers/nxp/smmu/
@@ -88,3 +89,11 @@ endif
ifeq (${GPIO_NEEDED},yes)
include ${PLAT_DRIVERS_PATH}/gpio/gpio.mk
endif
+
+ifeq (${IFC_NOR_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/ifc/nor/ifc_nor.mk
+endif
+
+ifeq (${IFC_NAND_NEEDED},yes)
+include ${PLAT_DRIVERS_PATH}/ifc/nand/ifc_nand.mk
+endif
diff --git a/drivers/nxp/flexspi/nor/fspi.c b/drivers/nxp/flexspi/nor/fspi.c
index 7c919b80ab..1e8c5a2c66 100644
--- a/drivers/nxp/flexspi/nor/fspi.c
+++ b/drivers/nxp/flexspi/nor/fspi.c
@@ -123,6 +123,9 @@ static void fspi_op_setup(uint32_t fspi_op_seq_id, bool ignore_flash_sz)
cmd_id1 = FSPI_NOR_CMD_RDSR;
cmd_id2 = FSPI_NOR_CMD_RDSR;
break;
+ default:
+ ERROR("Unsupported command\n");
+ return;
}
x_addr = FSPI_LUTREG_OFFSET + (uint32_t)(0x10 * fspi_op_seq_id);
diff --git a/drivers/nxp/gic/gic.mk b/drivers/nxp/gic/gic.mk
index 68091e8c32..d75e071194 100644
--- a/drivers/nxp/gic/gic.mk
+++ b/drivers/nxp/gic/gic.mk
@@ -17,7 +17,7 @@ GIC_SOURCES += ${GICV2_SOURCES}
GIC_SOURCES += ${PLAT_DRIVERS_PATH}/gic/ls_gicv2.c \
plat/common/plat_gicv2.c
-PLAT_INCLUDES += -I${PLAT_DRIVERS_PATH}/gic/include/gicv2
+PLAT_INCLUDES += -I${PLAT_DRIVERS_INCLUDE_PATH}/gic/gicv2
else
ifeq ($(GIC), GIC500)
include drivers/arm/gic/v3/gicv3.mk
@@ -25,7 +25,7 @@ GIC_SOURCES += ${GICV3_SOURCES}
GIC_SOURCES += ${PLAT_DRIVERS_PATH}/gic/ls_gicv3.c \
plat/common/plat_gicv3.c
-PLAT_INCLUDES += -I${PLAT_DRIVERS_PATH}/gic/include/gicv3
+PLAT_INCLUDES += -I${PLAT_DRIVERS_INCLUDE_PATH}/gic/gicv3
else
$(error -> GIC type not set!)
endif
diff --git a/drivers/nxp/gic/include/gicv2/plat_gic.h b/drivers/nxp/gic/include/gicv2/plat_gic.h
deleted file mode 100644
index ff347440d6..0000000000
--- a/drivers/nxp/gic/include/gicv2/plat_gic.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef PLAT_GICV2_H
-#define PLAT_GICV2_H
-
-#include <drivers/arm/gicv2.h>
-
- /* register offsets */
-#define GICD_CTLR_OFFSET 0x0
-#define GICD_CPENDSGIR3_OFFSET 0xF1C
-#define GICD_SPENDSGIR3_OFFSET 0xF2C
-#define GICD_SGIR_OFFSET 0xF00
-#define GICD_IGROUPR0_OFFSET 0x080
-#define GICD_TYPER_OFFSET 0x0004
-#define GICD_ISENABLER0_OFFSET 0x0100
-#define GICD_ICENABLER0_OFFSET 0x0180
-#define GICD_IPRIORITYR3_OFFSET 0x040C
-#define GICD_ISENABLERn_OFFSET 0x0100
-#define GICD_ISACTIVER0_OFFSET 0x300
-
-#define GICC_CTLR_OFFSET 0x0
-#define GICC_PMR_OFFSET 0x0004
-#define GICC_IAR_OFFSET 0x000C
-#define GICC_DIR_OFFSET 0x1000
-#define GICC_EOIR_OFFSET 0x0010
-
- /* bitfield masks */
-#define GICC_CTLR_EN_GRP0 0x1
-#define GICC_CTLR_EN_GRP1 0x2
-#define GICC_CTLR_EOImodeS_MASK 0x200
-#define GICC_CTLR_DIS_BYPASS 0x60
-#define GICC_CTLR_CBPR_MASK 0x10
-#define GICC_CTLR_FIQ_EN_MASK 0x8
-#define GICC_CTLR_ACKCTL_MASK 0x4
-#define GICC_PMR_FILTER 0xFF
-
-#define GICD_CTLR_EN_GRP0 0x1
-#define GICD_CTLR_EN_GRP1 0x2
-#define GICD_IGROUP0_SGI15 0x8000
-#define GICD_ISENABLE0_SGI15 0x8000
-#define GICD_ICENABLE0_SGI15 0x8000
-#define GICD_ISACTIVER0_SGI15 0x8000
-#define GICD_CPENDSGIR_CLR_MASK 0xFF000000
-#define GICD_IPRIORITY_SGI15_MASK 0xFF000000
-#define GICD_SPENDSGIR3_SGI15_MASK 0xFF000000
-#define GICD_SPENDSGIR3_SGI15_OFFSET 0x18
-
-#ifndef __ASSEMBLER__
-
-/* GIC common API's */
-void plat_ls_gic_driver_init(const uintptr_t nxp_gicd_addr,
- const uintptr_t nxp_gicc_addr,
- uint8_t plat_core_count,
- interrupt_prop_t *ls_interrupt_props,
- uint8_t ls_interrupt_prop_count,
- uint32_t *target_mask_array);
-void plat_ls_gic_init(void);
-void plat_ls_gic_cpuif_enable(void);
-void plat_ls_gic_cpuif_disable(void);
-void plat_ls_gic_redistif_on(void);
-void plat_ls_gic_redistif_off(void);
-void plat_gic_pcpu_init(void);
-/* GIC utility functions */
-void get_gic_offset(uint32_t *gicc_base, uint32_t *gicd_base);
-#endif
-
-#endif /* PLAT_GICV2_H */
diff --git a/drivers/nxp/gic/include/gicv3/plat_gic.h b/drivers/nxp/gic/include/gicv3/plat_gic.h
deleted file mode 100644
index f4e12de350..0000000000
--- a/drivers/nxp/gic/include/gicv3/plat_gic.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef PLAT_GICV3_H
-#define PLAT_GICV3_H
-
-#include <drivers/arm/gicv3.h>
-
- /* offset between redistributors */
-#define GIC_RD_OFFSET 0x00020000
- /* offset between SGI's */
-#define GIC_SGI_OFFSET 0x00020000
- /* offset from rd base to sgi base */
-#define GIC_RD_2_SGI_OFFSET 0x00010000
-
- /* register offsets */
-#define GICD_CTLR_OFFSET 0x0
-#define GICD_CLR_SPI_SR 0x58
-#define GICD_IGROUPR_2 0x88
-#define GICD_ISENABLER_2 0x108
-#define GICD_ICENABLER_2 0x188
-#define GICD_ICPENDR_2 0x288
-#define GICD_ICACTIVER_2 0x388
-#define GICD_IPRIORITYR_22 0x458
-#define GICD_ICFGR_5 0xC14
-#define GICD_IGRPMODR_2 0xD08
-
-#define GICD_IROUTER60_OFFSET 0x61e0
-#define GICD_IROUTER76_OFFSET 0x6260
-#define GICD_IROUTER89_OFFSET 0x62C8
-#define GICD_IROUTER112_OFFSET 0x6380
-#define GICD_IROUTER113_OFFSET 0x6388
-
-#define GICR_ICENABLER0_OFFSET 0x180
-#define GICR_CTLR_OFFSET 0x0
-#define GICR_IGROUPR0_OFFSET 0x80
-#define GICR_IGRPMODR0_OFFSET 0xD00
-#define GICR_IPRIORITYR3_OFFSET 0x40C
-#define GICR_ICPENDR0_OFFSET 0x280
-#define GICR_ISENABLER0_OFFSET 0x100
-#define GICR_TYPER_OFFSET 0x8
-#define GICR_WAKER_OFFSET 0x14
-#define GICR_ICACTIVER0_OFFSET 0x380
-#define GICR_ICFGR0_OFFSET 0xC00
-
- /* bitfield masks */
-#define GICD_CTLR_EN_GRP_MASK 0x7
-#define GICD_CTLR_EN_GRP_1NS 0x2
-#define GICD_CTLR_EN_GRP_1S 0x4
-#define GICD_CTLR_EN_GRP_0 0x1
-#define GICD_CTLR_ARE_S_MASK 0x10
-#define GICD_CTLR_RWP 0x80000000
-
-#define GICR_ICENABLER0_SGI15 0x00008000
-#define GICR_CTLR_RWP 0x8
-#define GICR_CTLR_DPG0_MASK 0x2000000
-#define GICR_IGROUPR0_SGI15 0x00008000
-#define GICR_IGRPMODR0_SGI15 0x00008000
-#define GICR_ISENABLER0_SGI15 0x00008000
-#define GICR_IPRIORITYR3_SGI15_MASK 0xFF000000
-#define GICR_ICPENDR0_SGI15 0x8000
-
-#define GIC_SPI_89_MASK 0x02000000
-#define GIC_SPI89_PRIORITY_MASK 0xFF00
-#define GIC_IRM_SPI89 0x80000000
-
-#define GICD_IROUTER_VALUE 0x100
-#define GICR_WAKER_SLEEP_BIT 0x2
-#define GICR_WAKER_ASLEEP (1 << 2 | 1 << 1)
-
-#define ICC_SRE_EL3_SRE 0x1
-#define ICC_IGRPEN0_EL1_EN 0x1
-#define ICC_CTLR_EL3_CBPR_EL1S 0x1
-#define ICC_CTLR_EL3_RM 0x20
-#define ICC_CTLR_EL3_EOIMODE_EL3 0x4
-#define ICC_CTLR_EL3_PMHE 0x40
-#define ICC_PMR_EL1_P_FILTER 0xFF
-#define ICC_IAR0_EL1_SGI15 0xF
-#define ICC_SGI0R_EL1_INTID 0x0F000000
-#define ICC_IAR0_INTID_SPI_89 0x59
-
-#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
-#define ICC_PMR_EL1 S3_0_C4_C6_0
-#define ICC_SRE_EL3 S3_6_C12_C12_5
-#define ICC_CTLR_EL3 S3_6_C12_C12_4
-#define ICC_SRE_EL2 S3_4_C12_C9_5
-#define ICC_CTLR_EL1 S3_0_C12_C12_4
-
-#ifndef __ASSEMBLER__
-
-/* GIC common API's */
-typedef unsigned int (*my_core_pos_fn)(void);
-
-void plat_ls_gic_driver_init(const uintptr_t nxp_gicd_addr,
- const uintptr_t nxp_gicr_addr,
- uint8_t plat_core_count,
- interrupt_prop_t *ls_interrupt_props,
- uint8_t ls_interrupt_prop_count,
- uintptr_t *target_mask_array,
- mpidr_hash_fn mpidr_to_core_pos);
-//void plat_ls_gic_driver_init(void);
-void plat_ls_gic_init(void);
-void plat_ls_gic_cpuif_enable(void);
-void plat_ls_gic_cpuif_disable(void);
-void plat_ls_gic_redistif_on(void);
-void plat_ls_gic_redistif_off(void);
-void plat_gic_pcpu_init(void);
-#endif
-
-#endif /* PLAT_GICV3_H */
diff --git a/drivers/nxp/gpio/gpio.mk b/drivers/nxp/gpio/gpio.mk
index 157c60a16a..74f0dc4bf0 100644
--- a/drivers/nxp/gpio/gpio.mk
+++ b/drivers/nxp/gpio/gpio.mk
@@ -9,11 +9,9 @@ ifeq (${GPIO_ADDED},)
GPIO_ADDED := 1
-GPIO_DRIVERS_PATH := drivers/nxp/gpio
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/gpio
-PLAT_INCLUDES += -I$(GPIO_DRIVERS_PATH)
-
-GPIO_SOURCES := $(GPIO_DRIVERS_PATH)/nxp_gpio.c
+GPIO_SOURCES := $(PLAT_DRIVERS_PATH)/gpio/nxp_gpio.c
ifeq (${BL_COMM_GPIO_NEEDED},yes)
BL_COMMON_SOURCES += ${GPIO_SOURCES}
diff --git a/drivers/nxp/gpio/nxp_gpio.h b/drivers/nxp/gpio/nxp_gpio.h
deleted file mode 100644
index df758404ca..0000000000
--- a/drivers/nxp/gpio/nxp_gpio.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef PLAT_GPIO_H
-#define PLAT_GPIO_H
-
-#include <endian.h>
-#include <lib/mmio.h>
-
-/* GPIO Register offset */
-#define GPIO_SEL_MASK 0x7F
-#define GPIO_BIT_MASK 0x1F
-#define GPDIR_REG_OFFSET 0x0
-#define GPDAT_REG_OFFSET 0x8
-
-#define GPIO_ID_BASE_ADDR_SHIFT 5U
-#define GPIO_BITS_PER_BASE_REG 32U
-
-#define GPIO_0 0
-#define GPIO_1 1
-#define GPIO_2 2
-#define GPIO_3 3
-
-#define GPIO_SUCCESS 0x0
-#define GPIO_FAILURE 0x1
-
-#ifdef NXP_GPIO_BE
-#define gpio_read32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define gpio_write32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#elif defined(NXP_GPIO_LE)
-#define gpio_read32(a) mmio_read_32((uintptr_t)(a))
-#define gpio_write32(a, v) mmio_write_32((uintptr_t)(a), (v))
-#else
-#error Please define GPIO register endianness
-#endif
-
-typedef struct {
- uintptr_t gpio1_base_addr;
- uintptr_t gpio2_base_addr;
- uintptr_t gpio3_base_addr;
- uintptr_t gpio4_base_addr;
-} gpio_init_info_t;
-
-void gpio_init(gpio_init_info_t *gpio_init_data);
-uint32_t *select_gpio_n_bitnum(uint32_t povdd_gpio, uint32_t *bit_num);
-int clr_gpio_bit(uint32_t *gpio_base_addr, uint32_t bit_num);
-int set_gpio_bit(uint32_t *gpio_base_addr, uint32_t bit_num);
-
-#endif /* PLAT_GPIO_H */
diff --git a/drivers/nxp/i2c/i2c.h b/drivers/nxp/i2c/i2c.h
deleted file mode 100644
index 925bbc0e69..0000000000
--- a/drivers/nxp/i2c/i2c.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-
-#ifndef I2C_H
-#define I2C_H
-
-#include <lib/mmio.h>
-
-#define I2C_TIMEOUT 1000 /* ms */
-
-#define I2C_FD_CONSERV 0x7e
-#define I2C_CR_DIS (1 << 7)
-#define I2C_CR_EN (0 << 7)
-#define I2C_CR_MA (1 << 5)
-#define I2C_CR_TX (1 << 4)
-#define I2C_CR_TX_NAK (1 << 3)
-#define I2C_CR_RSTA (1 << 2)
-#define I2C_SR_BB (1 << 5)
-#define I2C_SR_IDLE (0 << 5)
-#define I2C_SR_AL (1 << 4)
-#define I2C_SR_IF (1 << 1)
-#define I2C_SR_RX_NAK (1 << 0)
-#define I2C_SR_RST (I2C_SR_AL | I2C_SR_IF)
-
-#define I2C_GLITCH_EN 0x8
-
-#define i2c_in(a) mmio_read_8((uintptr_t)(a))
-#define i2c_out(a, v) mmio_write_8((uintptr_t)(a), (v))
-
-struct ls_i2c {
- unsigned char ad; /* I2c Bus Address Register */
- unsigned char fd; /* I2c Bus Frequency Dividor Register */
- unsigned char cr; /* I2c Bus Control Register */
- unsigned char sr; /* I2c Bus Status Register */
- unsigned char dr; /* I2C Bus Data I/O Register */
- unsigned char ic; /* I2C Bus Interrupt Config Register */
- unsigned char dbg; /* I2C Bus Debug Register */
-};
-
-void i2c_init(uintptr_t nxp_i2c_addr);
-int i2c_read(unsigned char chip, int addr, int alen,
- unsigned char *buf, int len);
-int i2c_write(unsigned char chip, int addr, int alen,
- const unsigned char *buf, int len);
-int i2c_probe_chip(unsigned char chip);
-
-#endif /* I2C_H */
diff --git a/drivers/nxp/i2c/i2c.mk b/drivers/nxp/i2c/i2c.mk
index ae89115f8d..716e14a82f 100644
--- a/drivers/nxp/i2c/i2c.mk
+++ b/drivers/nxp/i2c/i2c.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -7,10 +7,10 @@
ifeq (${ADD_I2C},)
ADD_I2C := 1
-I2C_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/i2c
-I2C_SOURCES += $(I2C_DRIVERS_PATH)/i2c.c
-PLAT_INCLUDES += -I$(I2C_DRIVERS_PATH)
+I2C_SOURCES += $(PLAT_DRIVERS_PATH)/i2c/i2c.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/i2c
ifeq (${BL_COMM_I2C_NEEDED},yes)
BL_COMMON_SOURCES += ${I2C_SOURCES}
diff --git a/drivers/nxp/ifc/nand/ifc.h b/drivers/nxp/ifc/nand/ifc.h
new file mode 100644
index 0000000000..56c5f9292c
--- /dev/null
+++ b/drivers/nxp/ifc/nand/ifc.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IFC_H
+#define IFC_H
+
+#include <endian.h>
+
+#include <mmio.h>
+
+#define NXP_IFC_RUN_TIME_ADDR U(0x1000)
+
+/* CPSR - Chip Select Property Register Offset */
+#define EXT_CSPR(n) (U(0x000C) + (n * 0xC))
+#define CSPR(n) (U(0x0010) + (n * 0xC))
+#define CSOR(n) (U(0x0130) + (n * 0xC))
+#define EXT_CSOR(n) (U(0x0134) + (n * 0xC))
+#define IFC_AMASK_CS0 U(0x00A0)
+
+/* NAND specific Registers Offset */
+#define NCFGR (NXP_IFC_RUN_TIME_ADDR + U(0x0000))
+#define NAND_FCR0 (NXP_IFC_RUN_TIME_ADDR + U(0x0014))
+
+#define ROW0 (NXP_IFC_RUN_TIME_ADDR + U(0x003C))
+#define ROW1 (NXP_IFC_RUN_TIME_ADDR + U(0x004C))
+#define COL0 (NXP_IFC_RUN_TIME_ADDR + U(0x0044))
+#define COL1 (NXP_IFC_RUN_TIME_ADDR + U(0x0054))
+
+#define NAND_BC (NXP_IFC_RUN_TIME_ADDR + U(0x0108))
+#define NAND_FIR0 (NXP_IFC_RUN_TIME_ADDR + U(0x0110))
+#define NAND_FIR1 (NXP_IFC_RUN_TIME_ADDR + U(0x0114))
+#define NAND_FIR2 (NXP_IFC_RUN_TIME_ADDR + U(0x0118))
+#define NAND_CSEL (NXP_IFC_RUN_TIME_ADDR + U(0x015C))
+#define NANDSEQ_STRT (NXP_IFC_RUN_TIME_ADDR + U(0x0164))
+#define NAND_EVTER_STAT (NXP_IFC_RUN_TIME_ADDR + U(0x016C))
+#define NAND_AUTOBOOT_TRGR (NXP_IFC_RUN_TIME_ADDR + U(0x0284))
+
+/* Size of SRAM Buffer */
+#define CSPR_PS U(0x00000180)
+#define CSPR_PS_SHIFT 7
+#define CSPR_PS_8 0x1 // Port Size 8 bit
+#define CSPR_PS_16 0x2 // Port Size 16 bit
+#define CSPR_PS_32 0x3 // Port Size 32 bit
+
+/* Chip Select Option Register NAND Machine */
+#define CSOR_NAND_PGS U(0x00380000)
+#define CSOR_NAND_PGS_SHIFT 19
+#define CSOR_NAND_PGS_512 U(0x00000000)
+#define CSOR_NAND_PGS_2K U(0x00080000)
+#define CSOR_NAND_PGS_4K U(0x00100000)
+#define CSOR_NAND_PGS_8K U(0x00180000)
+#define CSOR_NAND_PGS_16K U(0x00200000)
+
+
+#define CSOR_NAND_PB U(0x00000700)
+#define CSOR_NAND_PB_32 U(0x00000000)
+#define CSOR_NAND_PB_64 U(0x00000100)
+#define CSOR_NAND_PB_128 U(0x00000200)
+#define CSOR_NAND_PB_256 U(0x00000300)
+#define CSOR_NAND_PB_512 U(0x00000400)
+#define CSOR_NAND_PB_1024 U(0x00000500)
+#define CSOR_NAND_PB_2048 U(0x00000600)
+#define CSOR_NAND_PPB_32 32
+#define CSOR_NAND_PPB_64 64
+#define CSOR_NAND_PPB_128 128
+#define CSOR_NAND_PPB_256 256
+#define CSOR_NAND_PPB_512 512
+#define CSOR_NAND_PPB_1024 1024
+#define CSOR_NAND_PPB_2048 2048
+
+/* NAND Chip select register */
+#define NAND_CSEL_SHIFT 26
+#define NAND_COL_MS_SHIFT 31
+
+/* FCR - Flash Command Register */
+#define FCR_CMD0 U(0xFF000000)
+#define FCR_CMD0_SHIFT 24
+#define FCR_CMD1 U(0x00FF0000)
+#define FCR_CMD1_SHIFT 16
+#define FCR_CMD2 U(0x0000FF00)
+#define FCR_CMD2_SHIFT 8
+#define FCR_CMD3 U(0x000000FF)
+#define FCR_CMD3_SHIFT 0
+
+/* FIR - Flash Instruction Register Opcode */
+#define FIR_OP0 U(0xFC000000)
+#define FIR_OP0_SHIFT 26
+#define FIR_OP1 U(0x03F00000)
+#define FIR_OP1_SHIFT 20
+#define FIR_OP2 U(0x000FC000)
+#define FIR_OP2_SHIFT 14
+#define FIR_OP3 U(0x00003F00)
+#define FIR_OP3_SHIFT 8
+#define FIR_OP4 U(0x000000FC)
+#define FIR_OP4_SHIFT 2
+#define FIR_OP5 U(0xFC000000)
+#define FIR_OP5_SHIFT 26
+#define FIR_OP6 U(0x03F00000)
+#define FIR_OP6_SHIFT 20
+
+/* Instruction Opcode - 6 bits */
+#define FIR_OP_NOP 0x00
+#define FIR_OP_CA0 0x01 /* Issue current column address */
+#define FIR_OP_CA1 0x02 /* Issue current column address */
+#define FIR_OP_RA0 0x05 /* Issue current column address */
+#define FIR_OP_RA1 0x06 /* Issue current column address */
+#define FIR_OP_CMD0 0x09 /* Issue command from FCR[CMD0] */
+#define FIR_OP_CMD1 0x0a /* Issue command from FCR[CMD1] */
+#define FIR_OP_CMD2 0x0b /* Issue command from FCR[CMD2] */
+#define FIR_OP_CMD3 0x0c /* Issue command from FCR[CMD3] */
+#define FIR_OP_CW0 0x11 /* Wait then issue FCR[CMD0] */
+#define FIR_OP_CW1 0x12 /* Wait then issue FCR[CMD1] */
+#define FIR_OP_CW2 0x13 /* Wait then issue FCR[CMD1] */
+#define FIR_OP_CW3 0x14 /* Wait then issue FCR[CMD1] */
+#define FIR_OP_WBCD 0x19 /* Wait then read FBCR bytes */
+#define FIR_OP_RBCD 0x1a /* Wait then read 1 or 2 bytes */
+#define FIR_OP_BTRD 0x1b /* Wait then read 1 or 2 bytes */
+#define FIR_OP_RDSTAT 0x1c /* Wait then read 1 or 2 bytes */
+#define FIR_OP_NWAIT 0x1d /* Wait then read 1 or 2 bytes */
+#define FIR_OP_WFR 0x1e /* Wait then read 1 or 2 bytes */
+
+#define NAND_SEQ_STRT_FIR_STRT U(0x80000000)
+#define NAND_SEQ_STRT_FIR_STRT_SHIFT 31
+
+#define NAND_EVTER_STAT_FTOER U(0x08000000)
+#define NAND_EVTER_STAT_WPER U(0x04000000)
+#define NAND_EVTER_STAT_ECCER U(0x02000000)
+#define NAND_EVTER_STAT_DQSER U(0x01000000)
+#define NAND_EVTER_STAT_RCW_DN U(0x00008000)
+#define NAND_EVTER_STAT_BOOT_DN U(0x00004000)
+#define NAND_EVTER_STAT_RCW_DN U(0x00008000)
+#define NAND_EVTER_STAT_OPC_DN U(0x80000000)
+#define NAND_EVTER_STAT_BBI_SRCH_SEL U(0x00000800)
+#define NCFGR_BOOT U(0x80000000)
+#define NAND_AUTOBOOT_TRGR_RCW_LD U(0x80000000)
+#define NAND_AUTOBOOT_TRGR_BOOT_LD U(0x20000000)
+
+/* ECC ERROR STATUS Registers */
+#define NAND_RCW_LD U(0x80000000)
+#define NAND_BOOT_LD U(0x20000000)
+
+/*Other Temp Defines */
+/*256 bad Blocks supported */
+#define BBT_SIZE 256
+
+/*Standard NAND flash commands */
+#define NAND_CMD_READ0 0
+#define NAND_CMD_READ1 1
+#define NAND_CMD_READOOB 0x50
+
+/*Extended commands for large page devices */
+#define NAND_CMD_READSTART 0x30
+
+#define NAND_TIMEOUT_MS 40
+
+#define EMPTY_VAL_CHECK U(0xFFFFFFFF)
+#define EMPTY_VAL 0xFF
+
+
+#define MAIN 0
+#define SPARE 1
+
+#define GOOD_BLK 1
+#define BAD_BLK 0
+#define DIV_2 2
+
+#define ATTRIBUTE_PGSZ 0xa
+#define ATTRIBUTE_PPB 0xb
+
+#define CSPR_PORT_SIZE_8 (0x1 << 7)
+#define CSPR_PORT_SIZE_16 (0x2 << 7)
+#define CSPR_PORT_SIZE_32 (0x3 << 7)
+
+/* NAND specific */
+#define RCW_SRC_NAND_PORT_MASK U(0x00000080)
+
+#define NAND_DEFAULT_CSPR U(0x00000053)
+#define NAND_DEFAULT_CSOR U(0x0180C00C)
+#define NAND_DEFAULT_EXT_CSPR U(0x00000000)
+#define NAND_DEFAULT_EXT_CSOR U(0x00000000)
+#define NAND_DEFAULT_FTIM0 U(0x181c0c10)
+#define NAND_DEFAULT_FTIM1 U(0x5454141e)
+#define NAND_DEFAULT_FTIM2 U(0x03808034)
+#define NAND_DEFAULT_FTIM3 U(0x2c000000)
+
+#define NAND_CSOR_ECC_MODE_DISABLE U(0x00000000)
+#define NAND_CSOR_ECC_MODE0 U(0x84000000)
+#define NAND_CSOR_ECC_MODE1 U(0x94000000)
+#define NAND_CSOR_ECC_MODE2 U(0xa4000000)
+#define NAND_CSOR_ECC_MODE3 U(0xb4000000)
+#define NAND_CSOR_PAGE_SIZE_2K (0x1 << 19)
+#define NAND_CSOR_PAGE_SIZE_4K (0x2 << 19)
+#define NAND_CSOR_PAGE_SIZE_8K (0x3 << 19)
+#define NAND_CSOR_PAGE_SIZE_16K (0x4 << 19)
+#define NAND_CSOR_PPB_64 (0x1 << 8)
+#define NAND_CSOR_PPB_128 (0x2 << 8)
+#define NAND_CSOR_PPB_256 (0x3 << 8)
+#define NAND_CSOR_PPB_512 (0x4 << 8)
+
+/* BBI INDICATOR for NAND_2K(CFG_RCW_SRC[1]) for
+ * devices greater than 2K page size(CFG_RCW_SRC[3])
+ */
+#define RCW_SRC_NAND_BBI_MASK U(0x00000008)
+#define RCW_SRC_NAND_BBI_MASK_NAND_2K U(0x00000002)
+#define NAND_BBI_ONFI_2K (0x1 << 1)
+#define NAND_BBI_ONFI (0x1 << 3)
+
+#define RCW_SRC_NAND_PAGE_MASK U(0x00000070)
+#define RCW_SRC_NAND_PAGE_MASK_NAND_2K U(0x0000000C)
+#define NAND_2K_XXX 0x00
+#define NAND_2K_64 0x04
+#define NAND_2K_128 0x08
+#define NAND_4K_128 0x10
+#define NAND_4K_256 0x20
+#define NAND_4K_512 0x30
+#define NAND_8K_128 0x40
+#define NAND_8K_256 0x50
+#define NAND_8K_512 0x60
+#define NAND_16K_512 0x70
+#define BLOCK_LEN_2K 2048
+
+#define RCW_SRC_NAND_ECC_MASK U(0x00000007)
+#define RCW_SRC_NAND_ECC_MASK_NAND_2K U(0x00000001)
+#define NAND_ECC_DISABLE 0x0
+#define NAND_ECC_4_520 0x1
+#define NAND_ECC_8_528 0x5
+#define NAND_ECC_24_1K 0x6
+#define NAND_ECC_40_1K 0x7
+
+#define NAND_SPARE_2K U(0x00000040)
+#define NAND_SPARE_4K_ECC_M0 U(0x00000080)
+#define NAND_SPARE_4K_ECC_M1 U(0x000000D2)
+#define NAND_SPARE_4K_ECC_M2 U(0x000000B0)
+#define NAND_SPARE_4K_ECC_M3 U(0x00000120)
+#define NAND_SPARE_8K_ECC_M0 U(0x00000088)
+#define NAND_SPARE_8K_ECC_M1 U(0x00000108)
+#define NAND_SPARE_8K_ECC_M2 U(0x00000158)
+#define NAND_SPARE_8K_ECC_M3 U(0x00000238)
+#define NAND_SPARE_16K_ECC_M0 U(0x00000108)
+#define NAND_SPARE_16K_ECC_M1 U(0x00000208)
+#define NAND_SPARE_16K_ECC_M2 U(0x000002A8)
+#define NAND_SPARE_16K_ECC_M3 U(0x00000468)
+
+struct nand_info {
+ uintptr_t ifc_register_addr;
+ uintptr_t ifc_region_addr;
+ uint32_t page_size;
+ uint32_t port_size;
+ uint32_t blk_size;
+ uint32_t ppb;
+ uint32_t pi_width; /* Bits Required to index a page in block */
+ uint32_t ral;
+ uint32_t ibr_flow;
+ uint32_t bbt[BBT_SIZE];
+ uint32_t lgb; /* Last Good Block */
+ uint32_t bbt_max; /* Total entries in bbt */
+ uint32_t bzero_good;
+ uint8_t bbs;
+ uint8_t bad_marker_loc;
+ uint8_t onfi_dev_flag;
+ uint8_t init_time_boot_flag;
+ uint8_t *buf;
+};
+
+struct ifc_regs {
+ uint32_t ext_cspr;
+ uint32_t cspr;
+ uint32_t csor;
+ uint32_t ext_csor;
+};
+
+struct sec_nand_info {
+ uint32_t cspr_port_size;
+ uint32_t csor_ecc_mode;
+ uint32_t csor_page_size;
+ uint32_t csor_ppb;
+ uint32_t ext_csor_spare_size;
+ uint32_t onfi_flag;
+};
+
+struct sec_nor_info {
+ uint32_t cspr_port_size;
+ uint32_t csor_nor_mode;
+ uint32_t csor_adm_shift;
+ uint32_t port_size;
+ uint32_t addr_bits;
+};
+
+enum ifc_chip_sel {
+ IFC_CS0,
+ IFC_CS1,
+ IFC_CS2,
+ IFC_CS3,
+ IFC_CS4,
+ IFC_CS5,
+ IFC_CS6,
+ IFC_CS7,
+};
+
+enum ifc_ftims {
+ IFC_FTIM0,
+ IFC_FTIM1,
+ IFC_FTIM2,
+ IFC_FTIM3,
+};
+
+#ifdef NXP_IFC_BE
+#define nand_in32(a) bswap32(mmio_read_32((uintptr_t)a))
+#define nand_out32(a, v) mmio_write_32((uintptr_t)a, bswap32(v))
+#else
+#define nand_in32(a) mmio_read_32((uintptr_t)a)
+#define nand_out32(a, v) mmio_write_32((uintptr_t)a, v)
+#endif
+
+/* Read Write on IFC registers */
+static inline void write_reg(struct nand_info *nand, uint32_t reg, uint32_t val)
+{
+ nand_out32(nand->ifc_register_addr + reg, val);
+}
+
+static inline uint32_t read_reg(struct nand_info *nand, uint32_t reg)
+{
+ return nand_in32(nand->ifc_register_addr + reg);
+}
+
+#endif /* IFC_H */
diff --git a/drivers/nxp/ifc/nand/ifc_nand.c b/drivers/nxp/ifc/nand/ifc_nand.c
new file mode 100644
index 0000000000..df7ec85795
--- /dev/null
+++ b/drivers/nxp/ifc/nand/ifc_nand.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright 2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include "ifc.h"
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <nxp_timer.h>
+
+/* Private structure for NAND driver data */
+static struct nand_info nand_drv_data;
+
+static int update_bbt(uint32_t idx, uint32_t blk, uint32_t *updated,
+ struct nand_info *nand);
+
+static int nand_wait(struct nand_info *nand)
+{
+ int timeout = 1;
+ uint32_t neesr;
+ unsigned long start_time;
+
+ start_time = get_timer_val(0);
+
+ while (get_timer_val(start_time) < NAND_TIMEOUT_MS) {
+ /* clear the OPC event */
+ neesr = read_reg(nand, NAND_EVTER_STAT);
+ if (neesr & NAND_EVTER_STAT_OPC_DN) {
+ write_reg(nand, NAND_EVTER_STAT, neesr);
+ timeout = 0;
+
+ /* check for other errors */
+ if (neesr & NAND_EVTER_STAT_FTOER) {
+ ERROR("%s NAND_EVTER_STAT_FTOER occurs\n",
+ __func__);
+ return -1;
+ } else if (neesr & NAND_EVTER_STAT_ECCER) {
+ ERROR("%s NAND_EVTER_STAT_ECCER occurs\n",
+ __func__);
+ return -1;
+ } else if (neesr & NAND_EVTER_STAT_DQSER) {
+ ERROR("%s NAND_EVTER_STAT_DQSER occurs\n",
+ __func__);
+ return -1;
+ }
+
+ break;
+ }
+ }
+
+ if (timeout) {
+ ERROR("%s ERROR_NAND_TIMEOUT occurs\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint32_t nand_get_port_size(struct nand_info *nand)
+{
+ uint32_t port_size = U(0);
+ uint32_t cs_reg;
+ uint32_t cur_cs;
+
+ cur_cs = U(0);
+ cs_reg = CSPR(cur_cs);
+ port_size = (read_reg(nand, cs_reg) & CSPR_PS) >> CSPR_PS_SHIFT;
+ switch (port_size) {
+ case CSPR_PS_8:
+ port_size = U(8);
+ break;
+ case CSPR_PS_16:
+ port_size = U(16);
+ break;
+ case CSPR_PS_32:
+ port_size = U(32);
+ break;
+ default:
+ port_size = U(8);
+ }
+
+ return port_size;
+}
+
+static uint32_t nand_get_page_size(struct nand_info *nand)
+{
+ uint32_t pg_size;
+ uint32_t cs_reg;
+ uint32_t cur_cs;
+
+ cur_cs = 0;
+ cs_reg = CSOR(cur_cs);
+ pg_size = read_reg(nand, cs_reg) & CSOR_NAND_PGS;
+ switch (pg_size) {
+ case CSOR_NAND_PGS_2K:
+ pg_size = U(2048);
+ break;
+ case CSOR_NAND_PGS_4K:
+ pg_size = U(4096);
+ break;
+ case CSOR_NAND_PGS_8K:
+ pg_size = U(8192);
+ break;
+ case CSOR_NAND_PGS_16K:
+ pg_size = U(16384);
+ break;
+ default:
+ pg_size = U(512);
+ }
+
+ return pg_size;
+}
+
+static uint32_t nand_get_pages_per_blk(struct nand_info *nand)
+{
+ uint32_t pages_per_blk;
+ uint32_t cs_reg;
+ uint32_t cur_cs;
+
+ cur_cs = 0;
+ cs_reg = CSOR(cur_cs);
+ pages_per_blk = (read_reg(nand, cs_reg) & CSOR_NAND_PB);
+ switch (pages_per_blk) {
+ case CSOR_NAND_PB_32:
+ pages_per_blk = U(32);
+ break;
+ case CSOR_NAND_PB_64:
+ pages_per_blk = U(64);
+ break;
+ case CSOR_NAND_PB_128:
+ pages_per_blk = U(128);
+ break;
+ case CSOR_NAND_PB_256:
+ pages_per_blk = U(256);
+ break;
+ case CSOR_NAND_PB_512:
+ pages_per_blk = U(512);
+ break;
+ case CSOR_NAND_PB_1024:
+ pages_per_blk = U(1024);
+ break;
+ case CSOR_NAND_PB_2048:
+ pages_per_blk = U(2048);
+ break;
+ default:
+ pages_per_blk = U(0);
+ }
+
+ return pages_per_blk;
+}
+
+static uint32_t get_page_index_width(uint32_t ppb)
+{
+ switch (ppb) {
+ case CSOR_NAND_PPB_32:
+ return U(5);
+ case CSOR_NAND_PPB_64:
+ return U(6);
+ case CSOR_NAND_PPB_128:
+ return U(7);
+ case CSOR_NAND_PPB_256:
+ return U(8);
+ case CSOR_NAND_PPB_512:
+ return U(9);
+ case CSOR_NAND_PPB_1024:
+ return U(10);
+ case CSOR_NAND_PPB_2048:
+ return U(11);
+ default:
+ return U(5);
+ }
+}
+
+static void nand_get_params(struct nand_info *nand)
+{
+ nand->port_size = nand_get_port_size(nand);
+
+ nand->page_size = nand_get_page_size(nand);
+
+ /*
+ * Set Bad marker Location for LP / SP
+ * Small Page : 8 Bit : 0x5
+ * Small Page : 16 Bit : 0xa
+ * Large Page : 8 /16 Bit : 0x0
+ */
+ nand->bad_marker_loc = (nand->page_size == 512) ?
+ ((nand->port_size == 8) ? 0x5 : 0xa) : 0;
+
+ /* check for the device is ONFI compliant or not */
+ nand->onfi_dev_flag =
+ (read_reg(nand, NAND_EVTER_STAT) & NAND_EVTER_STAT_BBI_SRCH_SEL)
+ ? 1 : 0;
+
+ /* NAND Blk serached count for incremental Bad block search cnt */
+ nand->bbs = 0;
+
+ /* pages per Block */
+ nand->ppb = nand_get_pages_per_blk(nand);
+
+ /* Blk size */
+ nand->blk_size = nand->page_size * nand->ppb;
+
+ /* get_page_index_width */
+ nand->pi_width = get_page_index_width(nand->ppb);
+
+ /* bad block table init */
+ nand->lgb = 0;
+ nand->bbt_max = 0;
+ nand->bzero_good = 0;
+ memset(nand->bbt, EMPTY_VAL, BBT_SIZE * sizeof(nand->bbt[0]));
+}
+
+static int nand_init(struct nand_info *nand)
+{
+ uint32_t ncfgr = 0;
+
+ /* Get nand Parameters from IFC */
+ nand_get_params(nand);
+
+ /* Clear all errors */
+ write_reg(nand, NAND_EVTER_STAT, U(0xffffffff));
+
+ /*
+ * Disable autoboot in NCFGR. Mapping will change from
+ * physical to logical for SRAM buffer
+ */
+ ncfgr = read_reg(nand, NCFGR);
+ write_reg(nand, NCFGR, (ncfgr & ~NCFGR_BOOT));
+
+ return 0;
+}
+
+static int nand_read_data(
+ uintptr_t ifc_region_addr,
+ uint32_t row_add,
+ uint32_t col_add,
+ uint32_t byte_cnt,
+ uint8_t *data,
+ uint32_t main_spare,
+ struct nand_info *nand)
+{
+ uint32_t page_size_add_bits = U(0);
+ uint32_t page_add_in_actual, page_add;
+ uintptr_t sram_addr_calc;
+ int ret;
+ uint32_t col_val;
+
+ /* Programming MS bit to read from spare area.*/
+ col_val = (main_spare << NAND_COL_MS_SHIFT) | col_add;
+
+ write_reg(nand, NAND_BC, byte_cnt);
+
+ write_reg(nand, ROW0, row_add);
+ write_reg(nand, COL0, col_val);
+
+ /* Program FCR for small Page */
+ if (nand->page_size == U(512)) {
+ if (byte_cnt == 0 ||
+ (byte_cnt != 0 && main_spare == 0 && col_add <= 255)) {
+ write_reg(nand, NAND_FCR0,
+ (NAND_CMD_READ0 << FCR_CMD0_SHIFT));
+ } else if (main_spare == 0) {
+ write_reg(nand, NAND_FCR0,
+ (NAND_CMD_READ1 << FCR_CMD0_SHIFT));
+ } else {
+ write_reg(nand, NAND_FCR0,
+ (NAND_CMD_READOOB << FCR_CMD0_SHIFT));
+ }
+
+ } else {
+ /* Program FCR for Large Page */
+ write_reg(nand, NAND_FCR0, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
+ (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+ }
+ if (nand->page_size == U(512)) {
+ write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA0 << FIR_OP1_SHIFT) |
+ (FIR_OP_RA0 << FIR_OP2_SHIFT) |
+ (FIR_OP_BTRD << FIR_OP3_SHIFT) |
+ (FIR_OP_NOP << FIR_OP4_SHIFT)));
+ write_reg(nand, NAND_FIR1, U(0x00000000));
+ } else {
+ write_reg(nand, NAND_FIR0, ((FIR_OP_CW0 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA0 << FIR_OP1_SHIFT) |
+ (FIR_OP_RA0 << FIR_OP2_SHIFT) |
+ (FIR_OP_CMD1 << FIR_OP3_SHIFT) |
+ (FIR_OP_BTRD << FIR_OP4_SHIFT)));
+
+ write_reg(nand, NAND_FIR1, (FIR_OP_NOP << FIR_OP5_SHIFT));
+ }
+ write_reg(nand, NANDSEQ_STRT, NAND_SEQ_STRT_FIR_STRT);
+
+ ret = nand_wait(nand);
+ if (ret != 0)
+ return ret;
+
+ /* calculate page_size_add_bits i.e bits
+ * in sram address corresponding to area
+ * within a page for sram
+ */
+ if (nand->page_size == U(512))
+ page_size_add_bits = U(10);
+ else if (nand->page_size == U(2048))
+ page_size_add_bits = U(12);
+ else if (nand->page_size == U(4096))
+ page_size_add_bits = U(13);
+ else if (nand->page_size == U(8192))
+ page_size_add_bits = U(14);
+ else if (nand->page_size == U(16384))
+ page_size_add_bits = U(15);
+
+ page_add = row_add;
+
+ page_add_in_actual = (page_add << page_size_add_bits) & U(0x0000FFFF);
+
+ if (byte_cnt == 0)
+ col_add = U(0);
+
+ /* Calculate SRAM address for main and spare area */
+ if (main_spare == 0)
+ sram_addr_calc = ifc_region_addr | page_add_in_actual | col_add;
+ else
+ sram_addr_calc = ifc_region_addr | page_add_in_actual |
+ (col_add + nand->page_size);
+
+ /* Depending Byte_count copy full page or partial page from SRAM */
+ if (byte_cnt == 0)
+ memcpy(data, (void *)sram_addr_calc,
+ nand->page_size);
+ else
+ memcpy(data, (void *)sram_addr_calc, byte_cnt);
+
+ return 0;
+}
+
+static int nand_read(struct nand_info *nand, int32_t src_addr,
+ uintptr_t dst, uint32_t size)
+{
+ uint32_t log_blk = U(0);
+ uint32_t pg_no = U(0);
+ uint32_t col_off = U(0);
+ uint32_t row_off = U(0);
+ uint32_t byte_cnt = U(0);
+ uint32_t read_cnt = U(0);
+ uint32_t i = U(0);
+ uint32_t updated = U(0);
+
+ int ret = 0;
+ uint8_t *out = (uint8_t *)dst;
+
+ uint32_t pblk;
+
+ /* loop till size */
+ while (size) {
+ log_blk = (src_addr / nand->blk_size);
+ pg_no = ((src_addr - (log_blk * nand->blk_size)) /
+ nand->page_size);
+ pblk = log_blk;
+
+ // iterate the bbt to find the block
+ for (i = 0; i <= nand->bbt_max; i++) {
+ if (nand->bbt[i] == EMPTY_VAL_CHECK) {
+ ret = update_bbt(i, pblk, &updated, nand);
+
+ if (ret != 0)
+ return ret;
+ /*
+ * if table not updated and we reached
+ * end of table
+ */
+ if (!updated)
+ break;
+ }
+
+ if (pblk < nand->bbt[i])
+ break;
+ else if (pblk >= nand->bbt[i])
+ pblk++;
+ }
+
+ col_off = (src_addr % nand->page_size);
+ if (col_off) {
+ if ((col_off + size) < nand->page_size)
+ byte_cnt = size;
+ else
+ byte_cnt = nand->page_size - col_off;
+
+ row_off = (pblk << nand->pi_width) | pg_no;
+
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_off,
+ col_off,
+ byte_cnt, out, MAIN, nand);
+
+ if (ret != 0)
+ return ret;
+ } else {
+ /*
+ * fullpage/Partial Page
+ * if byte_cnt = 0 full page
+ * else partial page
+ */
+ if (size < nand->page_size) {
+ byte_cnt = size;
+ read_cnt = size;
+ } else {
+ byte_cnt = nand->page_size;
+ read_cnt = 0;
+ }
+ row_off = (pblk << nand->pi_width) | pg_no;
+
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_off,
+ 0,
+ read_cnt, out, MAIN, nand);
+
+ if (ret != 0) {
+ ERROR("Error from nand-read_data %d\n", ret);
+ return ret;
+ }
+ }
+ src_addr += byte_cnt;
+ out += byte_cnt;
+ size -= byte_cnt;
+ }
+ return 0;
+}
+
+static int isgoodblock(uint32_t blk, uint32_t *gb, struct nand_info *nand)
+{
+ uint8_t buf[2];
+ int ret;
+ uint32_t row_add;
+
+ *gb = 0;
+
+ /* read Page 0 of blk */
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ blk << nand->pi_width,
+ nand->bad_marker_loc,
+ 0x2, buf, 1, nand);
+
+ if (ret != 0)
+ return ret;
+
+ /* For ONFI devices check Page 0 and Last page of block for
+ * Bad Marker and for NON-ONFI Page 0 and 1 for Bad Marker
+ */
+ row_add = (blk << nand->pi_width);
+ if (nand->port_size == 8) {
+ /* port size is 8 Bit */
+ /* check if page 0 has 0xff */
+ if (buf[0] == 0xff) {
+ /* check page 1 */
+ if (nand->onfi_dev_flag)
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | (nand->ppb - 1),
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+ else
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | 1,
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+
+ if (ret != 0)
+ return ret;
+
+ if (buf[0] == 0xff)
+ *gb = GOOD_BLK;
+ else
+ *gb = BAD_BLK;
+ } else {
+ /* no, so it is bad blk */
+ *gb = BAD_BLK;
+ }
+ } else {
+ /* Port size 16-Bit */
+ /* check if page 0 has 0xffff */
+ if ((buf[0] == 0xff) &&
+ (buf[1] == 0xff)) {
+ /* check page 1 for 0xffff */
+ if (nand->onfi_dev_flag) {
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | (nand->ppb - 1),
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+ } else {
+ ret = nand_read_data(
+ nand->ifc_region_addr,
+ row_add | 1,
+ nand->bad_marker_loc,
+ 0x2, buf, SPARE, nand);
+ }
+
+ if (ret != 0)
+ return ret;
+
+ if ((buf[0] == 0xff) &&
+ (buf[1] == 0xff)) {
+ *gb = GOOD_BLK;
+ } else {
+ *gb = BAD_BLK;
+ }
+ } else {
+ /* no, so it is bad blk */
+ *gb = BAD_BLK;
+ }
+ }
+ return 0;
+}
+
+static int update_bbt(uint32_t idx, uint32_t blk,
+ uint32_t *updated, struct nand_info *nand)
+{
+ uint32_t sblk;
+ uint32_t lgb;
+ int ret;
+
+ if (nand->bzero_good && blk == 0)
+ return 0;
+
+ /* special case for lgb == 0 */
+ /* if blk <= lgb return */
+ if (nand->lgb != 0 && blk <= nand->lgb)
+ return 0;
+
+ *updated = 0;
+
+ /* if blk is more than lgb, iterate from lgb till a good block
+ * is found for blk
+ */
+
+ if (nand->lgb < blk)
+ sblk = nand->lgb;
+ else
+ /* this is when lgb = 0 */
+ sblk = blk;
+
+
+ lgb = nand->lgb;
+
+ /* loop from blk to find a good block */
+ while (1) {
+ while (lgb <= sblk) {
+ uint32_t gb = 0;
+
+ ret = isgoodblock(lgb, &gb, nand);
+ if (ret != 0)
+ return ret;
+
+ /* special case block 0 is good then set this flag */
+ if (lgb == 0 && gb == GOOD_BLK)
+ nand->bzero_good = 1;
+
+ if (gb == BAD_BLK) {
+ if (idx >= BBT_SIZE) {
+ ERROR("NAND BBT Table full\n");
+ return -1;
+ }
+ *updated = 1;
+ nand->bbt[idx] = lgb;
+ idx++;
+ blk++;
+ sblk++;
+ if (idx > nand->bbt_max)
+ nand->bbt_max = idx;
+ }
+ lgb++;
+ }
+ /* the access block found */
+ if (sblk == blk) {
+ /* when good block found update lgb */
+ nand->lgb = blk;
+ break;
+ }
+ sblk++;
+ }
+
+ return 0;
+}
+
+static size_t ifc_nand_read(int lba, uintptr_t buf, size_t size)
+{
+ int ret;
+ uint32_t page_size;
+ uint32_t src_addr;
+ struct nand_info *nand = &nand_drv_data;
+
+ page_size = nand_get_page_size(nand);
+ src_addr = lba * page_size;
+ ret = nand_read(nand, src_addr, buf, size);
+ return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec ifc_nand_spec = {
+ .buffer = {
+ .offset = 0,
+ .length = 0,
+ },
+ .ops = {
+ .read = ifc_nand_read,
+ },
+ /*
+ * Default block size assumed as 2K
+ * Would be updated based on actual size
+ */
+ .block_size = UL(2048),
+};
+
+int ifc_nand_init(uintptr_t *block_dev_spec,
+ uintptr_t ifc_region_addr,
+ uintptr_t ifc_register_addr,
+ size_t ifc_sram_size,
+ uintptr_t ifc_nand_blk_offset,
+ size_t ifc_nand_blk_size)
+{
+ struct nand_info *nand = NULL;
+ int ret;
+
+ nand = &nand_drv_data;
+ memset(nand, 0, sizeof(struct nand_info));
+
+ nand->ifc_region_addr = ifc_region_addr;
+ nand->ifc_register_addr = ifc_register_addr;
+
+ VERBOSE("nand_init\n");
+ ret = nand_init(nand);
+ if (ret) {
+ ERROR("nand init failed\n");
+ return ret;
+ }
+
+ ifc_nand_spec.buffer.offset = ifc_nand_blk_offset;
+ ifc_nand_spec.buffer.length = ifc_nand_blk_size;
+
+ ifc_nand_spec.block_size = nand_get_page_size(nand);
+
+ VERBOSE("Page size is %ld\n", ifc_nand_spec.block_size);
+
+ *block_dev_spec = (uintptr_t)&ifc_nand_spec;
+
+ /* Adding NAND SRAM< Buffer in XLAT Table */
+ mmap_add_region(ifc_region_addr, ifc_region_addr,
+ ifc_sram_size, MT_DEVICE | MT_RW);
+
+ return 0;
+}
diff --git a/drivers/nxp/ifc/nand/ifc_nand.mk b/drivers/nxp/ifc/nand/ifc_nand.mk
new file mode 100644
index 0000000000..890fd23c3c
--- /dev/null
+++ b/drivers/nxp/ifc/nand/ifc_nand.mk
@@ -0,0 +1,29 @@
+#
+# Copyright 2022 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${NAND_ADDED},)
+
+NAND_ADDED := 1
+
+NAND_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/ifc/nand
+
+NAND_SOURCES := $(NAND_DRIVERS_PATH)/ifc_nand.c \
+ drivers/io/io_block.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ifc
+
+ifeq (${BL_COMM_IFC_NAND_NEEDED},yes)
+BL_COMMON_SOURCES += ${NAND_SOURCES}
+else
+ifeq (${BL2_IFC_NAND_NEEDED},yes)
+BL2_SOURCES += ${NAND_SOURCES}
+endif
+ifeq (${BL31_IFC_NAND_NEEDED},yes)
+BL31_SOURCES += ${NAND_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/ifc/nor/ifc_nor.c b/drivers/nxp/ifc/nor/ifc_nor.c
new file mode 100644
index 0000000000..24fc308e1f
--- /dev/null
+++ b/drivers/nxp/ifc/nor/ifc_nor.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+int ifc_nor_init(uintptr_t flash_addr, size_t flash_size)
+{
+ /* Adding NOR Memory Map in XLAT Table */
+ mmap_add_region(flash_addr, flash_addr, flash_size, MT_MEMORY | MT_RW);
+
+ return 0;
+}
diff --git a/drivers/nxp/ifc/nor/ifc_nor.mk b/drivers/nxp/ifc/nor/ifc_nor.mk
new file mode 100644
index 0000000000..0022a81562
--- /dev/null
+++ b/drivers/nxp/ifc/nor/ifc_nor.mk
@@ -0,0 +1,28 @@
+#
+# Copyright 2020-2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${NOR_ADDED},)
+
+NOR_ADDED := 1
+
+NOR_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/ifc/nor
+
+NOR_SOURCES := $(NOR_DRIVERS_PATH)/ifc_nor.c
+
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/ifc
+
+ifeq (${BL_COMM_IFC_NOR_NEEDED},yes)
+BL_COMMON_SOURCES += ${NOR_SOURCES}
+else
+ifeq (${BL2_IFC_NOR_NEEDED},yes)
+BL2_SOURCES += ${NOR_SOURCES}
+endif
+ifeq (${BL31_IFC_NOR_NEEDED},yes)
+BL31_SOURCES += ${NOR_SOURCES}
+endif
+endif
+
+endif
diff --git a/drivers/nxp/interconnect/interconnect.mk b/drivers/nxp/interconnect/interconnect.mk
index 81e3fa9721..aa51be4cba 100644
--- a/drivers/nxp/interconnect/interconnect.mk
+++ b/drivers/nxp/interconnect/interconnect.mk
@@ -1,4 +1,4 @@
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -12,7 +12,7 @@
ifeq (${ADD_INTERCONNECT},)
ADD_INTERCONNECT := 1
-PLAT_INCLUDES += -I${PLAT_DRIVERS_PATH}/interconnect
+PLAT_INCLUDES += -I${PLAT_DRIVERS_INCLUDE_PATH}/interconnect
ifeq (, $(filter $(INTERCONNECT), CCI400 CCN502 CCN504 CCN508))
$(error -> Interconnect type not set!)
diff --git a/drivers/nxp/interconnect/ls_interconnect.h b/drivers/nxp/interconnect/ls_interconnect.h
deleted file mode 100644
index 26787fb4d5..0000000000
--- a/drivers/nxp/interconnect/ls_interconnect.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef LS_INTERCONNECT_H
-#define LS_INTERCONNECT_H
-
-#if (INTERCONNECT == CCI400)
-#define CCI_TERMINATE_BARRIER_TX 0x8
-#endif
-
-/* Interconnect CCI/CCN functions */
-void plat_ls_interconnect_enter_coherency(unsigned int num_clusters);
-void plat_ls_interconnect_exit_coherency(void);
-
-#endif
diff --git a/drivers/nxp/pmu/pmu.h b/drivers/nxp/pmu/pmu.h
deleted file mode 100644
index 28199e852b..0000000000
--- a/drivers/nxp/pmu/pmu.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef PMU_H
-#define PMU_H
-
-/* PMU Registers' OFFSET */
-#define PMU_PCPW20SR_OFFSET 0x830
-#define PMU_CLL2FLUSHSETR_OFFSET 0x1110
-#define PMU_CLSL2FLUSHCLRR_OFFSET 0x1114
-#define PMU_CLL2FLUSHSR_OFFSET 0x1118
-#define PMU_POWMGTCSR_VAL (1 << 20)
-
-/* PMU Registers */
-#define CORE_TIMEBASE_ENBL_OFFSET 0x8A0
-#define CLUST_TIMER_BASE_ENBL_OFFSET 0x18A0
-
-#define PMU_IDLE_CLUSTER_MASK 0x2
-#define PMU_FLUSH_CLUSTER_MASK 0x2
-#define PMU_IDLE_CORE_MASK 0xfe
-
-/* pmu register offsets and bitmaps */
-#define PMU_POWMGTDCR0_OFFSET 0xC20
-#define PMU_POWMGTCSR_OFFSET 0x4000
-#define PMU_CLAINACTSETR_OFFSET 0x1100
-#define PMU_CLAINACTCLRR_OFFSET 0x1104
-#define PMU_CLSINACTSETR_OFFSET 0x1108
-#define PMU_CLSINACTCLRR_OFFSET 0x110C
-#define PMU_CLL2FLUSHSETR_OFFSET 0x1110
-#define PMU_CLL2FLUSHCLRR_OFFSET 0x1114
-#define PMU_IPPDEXPCR0_OFFSET 0x4040
-#define PMU_IPPDEXPCR1_OFFSET 0x4044
-#define PMU_IPPDEXPCR2_OFFSET 0x4048
-#define PMU_IPPDEXPCR3_OFFSET 0x404C
-#define PMU_IPPDEXPCR4_OFFSET 0x4050
-#define PMU_IPPDEXPCR5_OFFSET 0x4054
-#define PMU_IPPDEXPCR6_OFFSET 0x4058
-#define PMU_IPSTPCR0_OFFSET 0x4120
-#define PMU_IPSTPCR1_OFFSET 0x4124
-#define PMU_IPSTPCR2_OFFSET 0x4128
-#define PMU_IPSTPCR3_OFFSET 0x412C
-#define PMU_IPSTPCR4_OFFSET 0x4130
-#define PMU_IPSTPCR5_OFFSET 0x4134
-#define PMU_IPSTPCR6_OFFSET 0x4138
-#define PMU_IPSTPACKSR0_OFFSET 0x4140
-#define PMU_IPSTPACKSR1_OFFSET 0x4144
-#define PMU_IPSTPACKSR2_OFFSET 0x4148
-#define PMU_IPSTPACKSR3_OFFSET 0x414C
-#define PMU_IPSTPACKSR4_OFFSET 0x4150
-#define PMU_IPSTPACKSR5_OFFSET 0x4154
-#define PMU_IPSTPACKSR6_OFFSET 0x4158
-
-#define CLAINACT_DISABLE_ACP 0xFF
-#define CLSINACT_DISABLE_SKY 0xFF
-#define POWMGTDCR_STP_OV_EN 0x1
-#define POWMGTCSR_LPM20_REQ 0x00100000
-
-/* Used by PMU */
-#define DEVDISR1_MASK 0x024F3504
-#define DEVDISR2_MASK 0x0003FFFF
-#define DEVDISR3_MASK 0x0000303F
-#define DEVDISR4_MASK 0x0000FFFF
-#define DEVDISR5_MASK 0x00F07603
-#define DEVDISR6_MASK 0x00000001
-
-#ifndef __ASSEMBLER__
-void enable_timer_base_to_cluster(uintptr_t nxp_pmu_addr);
-void enable_core_tb(uintptr_t nxp_pmu_addr);
-#endif /* __ASSEMBLER__ */
-
-#endif
diff --git a/drivers/nxp/pmu/pmu.mk b/drivers/nxp/pmu/pmu.mk
index 56b04229e3..8d2ef07c44 100644
--- a/drivers/nxp/pmu/pmu.mk
+++ b/drivers/nxp/pmu/pmu.mk
@@ -8,11 +8,9 @@ ifeq (${PMU_ADDED},)
PMU_ADDED := 1
-PMU_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/pmu
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/pmu
-PLAT_INCLUDES += -I$(PMU_DRIVERS_PATH)
-
-PMU_SOURCES += $(PMU_DRIVERS_PATH)/pmu.c
+PMU_SOURCES += $(PLAT_DRIVERS_PATH)/pmu/pmu.c
ifeq (${BL_COMM_PMU_NEEDED},yes)
BL_COMMON_SOURCES += ${PMU_SOURCES}
diff --git a/drivers/nxp/qspi/qspi.h b/drivers/nxp/qspi/qspi.h
deleted file mode 100644
index db11c3bc69..0000000000
--- a/drivers/nxp/qspi/qspi.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef QSPI_H
-#define QSPI_H
-
-#include <endian.h>
-#include <lib/mmio.h>
-
-#define CHS_QSPI_MCR 0x01550000
-#define CHS_QSPI_64LE 0xC
-
-#ifdef NXP_QSPI_BE
-#define qspi_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define qspi_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#elif defined(NXP_QSPI_LE)
-#define qspi_in32(a) mmio_read_32((uintptr_t)(a))
-#define qspi_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
-#else
-#error Please define CCSR QSPI register endianness
-#endif
-
-int qspi_io_setup(uintptr_t nxp_qspi_flash_addr,
- size_t nxp_qspi_flash_size,
- uintptr_t fip_offset);
-#endif /* __QSPI_H__ */
diff --git a/drivers/nxp/qspi/qspi.mk b/drivers/nxp/qspi/qspi.mk
index 3e2c7350a1..450aeca602 100644
--- a/drivers/nxp/qspi/qspi.mk
+++ b/drivers/nxp/qspi/qspi.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,11 +8,9 @@ ifeq (${QSPI_ADDED},)
QSPI_ADDED := 1
-QSPI_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/qspi
+QSPI_SOURCES := $(PLAT_DRIVERS_PATH)/qspi/qspi.c
-QSPI_SOURCES := $(QSPI_DRIVERS_PATH)/qspi.c
-
-PLAT_INCLUDES += -I$(QSPI_DRIVERS_PATH)
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/qspi
ifeq (${BL_COMM_QSPI_NEEDED},yes)
BL_COMMON_SOURCES += ${QSPI_SOURCES}
diff --git a/drivers/nxp/sd/sd_mmc.c b/drivers/nxp/sd/sd_mmc.c
index f7f48e7233..48b27c1642 100644
--- a/drivers/nxp/sd/sd_mmc.c
+++ b/drivers/nxp/sd/sd_mmc.c
@@ -344,7 +344,7 @@ static int esdhc_wait_response(struct mmc *mmc, uint32_t *response)
* Function : mmc_switch_to_high_frquency
* Arguments : mmc - Pointer to mmc struct
* Return : SUCCESS or Error Code
- * Description : mmc card bellow ver 4.0 does not support high speed
+ * Description : mmc card below ver 4.0 does not support high speed
* freq = 20 MHz
* Send CMD6 (CMD_SWITCH_FUNC) With args 0x03B90100
* Send CMD13 (CMD_SEND_STATUS)
@@ -358,7 +358,7 @@ static int mmc_switch_to_high_frquency(struct mmc *mmc)
uint64_t start_time;
mmc->card.bus_freq = MMC_SS_20MHZ;
- /* mmc card bellow ver 4.0 does not support high speed */
+ /* mmc card below ver 4.0 does not support high speed */
if (mmc->card.version < MMC_CARD_VERSION_4_X) {
return 0;
}
@@ -463,7 +463,7 @@ static int esdhc_set_data_attributes(struct mmc *mmc, uint32_t *dest_ptr,
/***************************************************************************
* Function : esdhc_read_data_nodma
* Arguments : mmc - Pointer to mmc struct
- * dest_ptr - Bufffer where read data is to be copied
+ * dest_ptr - Buffer where read data is to be copied
* len - Length of Data to be read
* Return : SUCCESS or Error Code
* Description : Read data from the sdhc buffer without using DMA
@@ -698,7 +698,7 @@ static int esdhc_write_data_dma(struct mmc *mmc, uint32_t len)
/***************************************************************************
* Function : esdhc_read_data
* Arguments : mmc - Pointer to mmc struct
- * dest_ptr - Bufffer where read data is to be copied
+ * dest_ptr - Buffer where read data is to be copied
* len - Length of Data to be read
* Return : SUCCESS or Error Code
* Description : Calls esdhc_read_data_nodma and clear interrupt status
diff --git a/drivers/nxp/sd/sd_mmc.h b/drivers/nxp/sd/sd_mmc.h
deleted file mode 100644
index 29ad32873e..0000000000
--- a/drivers/nxp/sd/sd_mmc.h
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (c) 2015, 2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2020 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef SD_MMC_H
-#define SD_MMC_H
-
-#include <lib/mmio.h>
-
-/* operating freq */
-#define CARD_IDENTIFICATION_FREQ 400000
-#define SD_SS_25MHZ 20000000
-#define SD_HS_50MHZ 40000000
-#define MMC_SS_20MHZ 15000000
-#define MMC_HS_26MHZ 20000000
-#define MMC_HS_52MHZ 40000000
-
-/* Need to check this value ? */
-#define MAX_PLATFORM_CLOCK 800000000
-
-/* eSDHC system control register defines */
-#define ESDHC_SYSCTL_DTOCV(t) (((t) & 0xF) << 16)
-#define ESDHC_SYSCTL_SDCLKFS(f) (((f) & 0xFF) << 8)
-#define ESDHC_SYSCTL_DVS(d) (((d) & 0xF) << 4)
-#define ESDHC_SYSCTL_SDCLKEN (0x00000008)
-#define ESDHC_SYSCTL_RSTA (0x01000000)
-
-/* Data timeout counter value. SDHC_CLK x 227 */
-#define TIMEOUT_COUNTER_SDCLK_2_27 0xE
-#define ESDHC_SYSCTL_INITA 0x08000000
-
-/* eSDHC interrupt status enable register defines */
-#define ESDHC_IRQSTATEN_CINS 0x00000040
-#define ESDHC_IRQSTATEN_BWR 0x00000010
-
-/* eSDHC interrupt status register defines */
-#define ESDHC_IRQSTAT_DMAE (0x10000000)
-#define ESDHC_IRQSTAT_AC12E (0x01000000)
-#define ESDHC_IRQSTAT_DEBE (0x00400000)
-#define ESDHC_IRQSTAT_DCE (0x00200000)
-#define ESDHC_IRQSTAT_DTOE (0x00100000)
-#define ESDHC_IRQSTAT_CIE (0x00080000)
-#define ESDHC_IRQSTAT_CEBE (0x00040000)
-#define ESDHC_IRQSTAT_CCE (0x00020000)
-#define ESDHC_IRQSTAT_CTOE (0x00010000)
-#define ESDHC_IRQSTAT_CINT (0x00000100)
-#define ESDHC_IRQSTAT_CRM (0x00000080)
-#define ESDHC_IRQSTAT_CINS (0x00000040)
-#define ESDHC_IRQSTAT_BRR (0x00000020)
-#define ESDHC_IRQSTAT_BWR (0x00000010)
-#define ESDHC_IRQSTAT_DINT (0x00000008)
-#define ESDHC_IRQSTAT_BGE (0x00000004)
-#define ESDHC_IRQSTAT_TC (0x00000002)
-#define ESDHC_IRQSTAT_CC (0x00000001)
-#define ESDHC_IRQSTAT_CMD_ERR (ESDHC_IRQSTAT_CIE |\
- ESDHC_IRQSTAT_CEBE |\
- ESDHC_IRQSTAT_CCE)
-#define ESDHC_IRQSTAT_DATA_ERR (ESDHC_IRQSTAT_DEBE |\
- ESDHC_IRQSTAT_DCE |\
- ESDHC_IRQSTAT_DTOE)
-#define ESDHC_IRQSTAT_CLEAR_ALL (0xFFFFFFFF)
-
-/* eSDHC present state register defines */
-#define ESDHC_PRSSTAT_CLSL 0x00800000
-#define ESDHC_PRSSTAT_WPSPL 0x00080000
-#define ESDHC_PRSSTAT_CDPL 0x00040000
-#define ESDHC_PRSSTAT_CINS 0x00010000
-#define ESDHC_PRSSTAT_BREN 0x00000800
-#define ESDHC_PRSSTAT_BWEN 0x00000400
-#define ESDHC_PRSSTAT_RTA 0x00000200
-#define ESDHC_PRSSTAT_WTA 0x00000100
-#define ESDHC_PRSSTAT_SDOFF 0x00000080
-#define ESDHC_PRSSTAT_PEROFF 0x00000040
-#define ESDHC_PRSSTAT_HCKOFF 0x00000020
-#define ESDHC_PRSSTAT_IPGOFF 0x00000010
-#define ESDHC_PRSSTAT_DLA 0x00000004
-#define ESDHC_PRSSTAT_CDIHB 0x00000002
-#define ESDHC_PRSSTAT_CIHB 0x00000001
-
-/* eSDHC protocol control register defines */
-#define ESDHC_PROCTL_EMODE_LE 0x00000020
-#define ESDHC_PROCTL_DTW_1BIT 0x00000000
-#define ESDHC_PROCTL_DTW_4BIT 0x00000002
-#define ESDHC_PROCTL_DTW_8BIT 0x00000004
-
-/* Watermark Level Register (WML) */
-#define ESDHC_WML_RD_WML(w) ((w) & 0x7F)
-#define ESDHC_WML_WR_WML(w) (((w) & 0x7F) << 16)
-#define ESDHC_WML_RD_BRST(w) (((w) & 0xF) << 8)
-#define ESDHC_WML_WR_BRST(w) (((w) & 0xF) << 24)
-#define ESDHC_WML_WR_BRST_MASK (0x0F000000)
-#define ESDHC_WML_RD_BRST_MASK (0x00000F00)
-#define ESDHC_WML_RD_WML_MASK (0x0000007F)
-#define ESDHC_WML_WR_WML_MASK (0x007F0000)
-#define WML_512_BYTES (0x0)
-#define BURST_128_BYTES (0x0)
-
-/* eSDHC control register define */
-#define ESDHC_DCR_SNOOP 0x00000040
-
-/* ESDHC Block attributes register */
-#define ESDHC_BLKATTR_BLKCNT(c) (((c) & 0xffff) << 16)
-#define ESDHC_BLKATTR_BLKSZE(s) ((s) & 0xfff)
-
-/* Transfer Type Register */
-#define ESDHC_XFERTYP_CMD(c) (((c) & 0x3F) << 24)
-#define ESDHC_XFERTYP_CMDTYP_NORMAL (0x0)
-#define ESDHC_XFERTYP_CMDTYP_SUSPEND (0x00400000)
-#define ESDHC_XFERTYP_CMDTYP_RESUME (0x00800000)
-#define ESDHC_XFERTYP_CMDTYP_ABORT (0x00C00000)
-#define ESDHC_XFERTYP_DPSEL (0x00200000)
-#define ESDHC_XFERTYP_CICEN (0x00100000)
-#define ESDHC_XFERTYP_CCCEN (0x00080000)
-#define ESDHC_XFERTYP_RSPTYP_NONE (0x0)
-#define ESDHC_XFERTYP_RSPTYP_136 (0x00010000)
-#define ESDHC_XFERTYP_RSPTYP_48 (0x00020000)
-#define ESDHC_XFERTYP_RSPTYP_48_BUSY (0x00030000)
-#define ESDHC_XFERTYP_MSBSEL (0x00000020)
-#define ESDHC_XFERTYP_DTDSEL (0x00000010)
-#define ESDHC_XFERTYP_AC12EN (0x00000004)
-#define ESDHC_XFERTYP_BCEN (0x00000002)
-#define ESDHC_XFERTYP_DMAEN (0x00000001)
-
-#define MMC_VDD_HIGH_VOLTAGE 0x00000100
-
-/* command index */
-#define CMD0 0
-#define CMD1 1
-#define CMD2 2
-#define CMD3 3
-#define CMD5 5
-#define CMD6 6
-#define CMD7 7
-#define CMD8 8
-#define CMD9 9
-#define CMD12 12
-#define CMD13 13
-#define CMD14 14
-#define CMD16 16
-#define CMD17 17
-#define CMD18 18
-#define CMD19 19
-#define CMD24 24
-#define CMD41 41
-#define CMD42 42
-#define CMD51 51
-#define CMD55 55
-#define CMD56 56
-#define ACMD6 CMD6
-#define ACMD13 CMD13
-#define ACMD41 CMD41
-#define ACMD42 CMD42
-#define ACMD51 CMD51
-
-/* commands abbreviations */
-#define CMD_GO_IDLE_STATE CMD0
-#define CMD_MMC_SEND_OP_COND CMD1
-#define CMD_ALL_SEND_CID CMD2
-#define CMD_SEND_RELATIVE_ADDR CMD3
-#define CMD_SET_DSR CMD4
-#define CMD_SWITCH_FUNC CMD6
-#define CMD_SELECT_CARD CMD7
-#define CMD_DESELECT_CARD CMD7
-#define CMD_SEND_IF_COND CMD8
-#define CMD_MMC_SEND_EXT_CSD CMD8
-#define CMD_SEND_CSD CMD9
-#define CMD_SEND_CID CMD10
-#define CMD_STOP_TRANSMISSION CMD12
-#define CMD_SEND_STATUS CMD13
-#define CMD_BUS_TEST_R CMD14
-#define CMD_GO_INACTIVE_STATE CMD15
-#define CMD_SET_BLOCKLEN CMD16
-#define CMD_READ_SINGLE_BLOCK CMD17
-#define CMD_READ_MULTIPLE_BLOCK CMD18
-#define CMD_WRITE_SINGLE_BLOCK CMD24
-#define CMD_BUS_TEST_W CMD19
-#define CMD_APP_CMD CMD55
-#define CMD_GEN_CMD CMD56
-#define CMD_SET_BUS_WIDTH ACMD6
-#define CMD_SD_STATUS ACMD13
-#define CMD_SD_SEND_OP_COND ACMD41
-#define CMD_SET_CLR_CARD_DETECT ACMD42
-#define CMD_SEND_SCR ACMD51
-
-/* MMC card spec version */
-#define MMC_CARD_VERSION_1_2 0
-#define MMC_CARD_VERSION_1_4 1
-#define MMC_CARD_VERSION_2_X 2
-#define MMC_CARD_VERSION_3_X 3
-#define MMC_CARD_VERSION_4_X 4
-
-/* SD Card Spec Version */
-/* May need to add version 3 here? */
-#define SD_CARD_VERSION_1_0 0
-#define SD_CARD_VERSION_1_10 1
-#define SD_CARD_VERSION_2_0 2
-
-/* card types */
-#define MMC_CARD 0
-#define SD_CARD 1
-#define NOT_SD_CARD MMC_CARD
-
-/* Card rca */
-#define SD_MMC_CARD_RCA 0x1
-#define BLOCK_LEN_512 512
-
-/* card state */
-#define STATE_IDLE 0
-#define STATE_READY 1
-#define STATE_IDENT 2
-#define STATE_STBY 3
-#define STATE_TRAN 4
-#define STATE_DATA 5
-#define STATE_RCV 6
-#define STATE_PRG 7
-#define STATE_DIS 8
-
-/* Card OCR register */
-/* VDD voltage window 1,65 to 1.95 */
-#define MMC_OCR_VDD_165_195 0x00000080
-/* VDD voltage window 2.7-2.8 */
-#define MMC_OCR_VDD_FF8 0x00FF8000
-#define MMC_OCR_CCS 0x40000000/* Card Capacity */
-#define MMC_OCR_BUSY 0x80000000/* busy bit */
-#define SD_OCR_HCS 0x40000000/* High capacity host */
-#define MMC_OCR_SECTOR_MODE 0x40000000/* Access Mode as Sector */
-
-/* mmc Switch function */
-#define SET_EXT_CSD_HS_TIMING 0x03B90100/* set High speed */
-
-/* check supports switching or not */
-#define SD_SWITCH_FUNC_CHECK_MODE 0x00FFFFF1
-#define SD_SWITCH_FUNC_SWITCH_MODE 0x80FFFFF1/* switch */
-#define SD_SWITCH_FUNC_HIGH_SPEED 0x02/* HIGH SPEED FUNC */
-#define SWITCH_ERROR 0x00000080
-
-/* errors in sending commands */
-#define RESP_TIMEOUT 0x1
-#define COMMAND_ERROR 0x2
-/* error in response */
-#define R1_ERROR (1 << 19)
-#define R1_CURRENT_STATE(x) (((x) & 0x00001E00) >> 9)
-
-/* Host Controller Capabilities */
-#define ESDHC_HOSTCAPBLT_DMAS (0x00400000)
-
-
-/* SD/MMC memory map */
-struct esdhc_regs {
- uint32_t dsaddr; /* dma system address */
- uint32_t blkattr; /* Block attributes */
- uint32_t cmdarg; /* Command argument */
- uint32_t xfertyp; /* Command transfer type */
- uint32_t cmdrsp[4]; /* Command response0,1,2,3 */
- uint32_t datport; /* Data buffer access port */
- uint32_t prsstat; /* Present state */
- uint32_t proctl; /* Protocol control */
- uint32_t sysctl; /* System control */
- uint32_t irqstat; /* Interrupt status */
- uint32_t irqstaten; /* Interrupt status enable */
- uint32_t irqsigen; /* Interrupt signal enable */
- uint32_t autoc12err; /* Auto CMD12 status */
- uint32_t hostcapblt; /* Host controller capabilities */
- uint32_t wml; /* Watermark level */
- uint32_t res1[2];
- uint32_t fevt; /* Force event */
- uint32_t res2;
- uint32_t adsaddrl;
- uint32_t adsaddrh;
- uint32_t res3[39];
- uint32_t hostver; /* Host controller version */
- uint32_t res4;
- uint32_t dmaerr; /* DMA error address */
- uint32_t dmaerrh; /* DMA error address high */
- uint32_t dmaerrattr; /* DMA error atrribute */
- uint32_t res5;
- uint32_t hostcapblt2;/* Host controller capabilities2 */
- uint32_t res6[2];
- uint32_t tcr; /* Tuning control */
- uint32_t res7[7];
- uint32_t dirctrl; /* Direction control */
- uint32_t ccr; /* Clock control */
- uint32_t res8[177];
- uint32_t ctl; /* Control register */
-};
-
-/* SD/MMC card attributes */
-struct card_attributes {
- uint32_t type; /* sd or mmc card */
- uint32_t version; /* version */
- uint32_t block_len; /* block length */
- uint32_t bus_freq; /* sdhc bus frequency */
- uint16_t rca; /* relative card address */
- uint8_t is_high_capacity; /* high capacity */
-};
-
-struct mmc {
- struct esdhc_regs *esdhc_regs;
- struct card_attributes card;
-
- uint32_t block_len;
- uint32_t voltages_caps; /* supported voltaes */
- uint32_t dma_support; /* DMA support */
-};
-
-enum cntrl_num {
- SDHC1 = 0,
- SDHC2
-};
-
-int sd_emmc_init(uintptr_t *block_dev_spec,
- uintptr_t nxp_esdhc_addr,
- size_t nxp_sd_block_offset,
- size_t nxp_sd_block_size,
- bool card_detect);
-
-int esdhc_emmc_init(struct mmc *mmc, bool card_detect);
-int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst,
- size_t size);
-int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
- size_t size);
-
-#ifdef NXP_ESDHC_BE
-#define esdhc_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define esdhc_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#elif defined(NXP_ESDHC_LE)
-#define esdhc_in32(a) mmio_read_32((uintptr_t)(a))
-#define esdhc_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
-#else
-#error Please define CCSR ESDHC register endianness
-#endif
-
-#endif /*SD_MMC_H*/
diff --git a/drivers/nxp/sd/sd_mmc.mk b/drivers/nxp/sd/sd_mmc.mk
index af91b1f145..c83b1bd18c 100644
--- a/drivers/nxp/sd/sd_mmc.mk
+++ b/drivers/nxp/sd/sd_mmc.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,12 +8,10 @@ ifeq (${ADD_SD_MMC},)
ADD_SD_MMC := 1
-SD_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/sd
-
-SD_MMC_BOOT_SOURCES += ${SD_DRIVERS_PATH}/sd_mmc.c \
+SD_MMC_BOOT_SOURCES += ${PLAT_DRIVERS_PATH}/sd/sd_mmc.c \
drivers/io/io_block.c
-PLAT_INCLUDES += -I$(SD_DRIVERS_PATH)
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/sd
ifeq (${BL_COMM_SD_MMC_NEEDED},yes)
BL_COMMON_SOURCES += ${SD_MMC_BOOT_SOURCES}
diff --git a/drivers/nxp/sec_mon/sec_mon.mk b/drivers/nxp/sec_mon/sec_mon.mk
index 51e3e8636c..aaac53f88c 100644
--- a/drivers/nxp/sec_mon/sec_mon.mk
+++ b/drivers/nxp/sec_mon/sec_mon.mk
@@ -8,11 +8,9 @@ ifeq (${ADD_SNVS},)
ADD_SNVS := 1
-SNVS_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/sec_mon
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/sec_mon
-PLAT_INCLUDES += -I$(SNVS_DRIVERS_PATH)
-
-SNVS_SOURCES += $(SNVS_DRIVERS_PATH)/snvs.c
+SNVS_SOURCES += $(PLAT_DRIVERS_PATH)/sec_mon/snvs.c
ifeq (${BL_COMM_SNVS_NEEDED},yes)
BL_COMMON_SOURCES += ${SNVS_SOURCES}
diff --git a/drivers/nxp/sec_mon/snvs.h b/drivers/nxp/sec_mon/snvs.h
deleted file mode 100644
index 4455383e3a..0000000000
--- a/drivers/nxp/sec_mon/snvs.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef SNVS_H
-#define SNVS_H
-
-
-#ifndef __ASSEMBLER__
-
-#include <endian.h>
-#include <stdbool.h>
-
-#include <lib/mmio.h>
-
-struct snvs_regs {
- uint32_t reserved1;
- uint32_t hp_com; /* 0x04 SNVS_HP Command Register */
- uint32_t reserved2[3];
- uint32_t hp_stat; /* 0x14 SNVS_HP Status Register */
-};
-
-#ifdef NXP_SNVS_BE
-#define snvs_read32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define snvs_write32(a, v) mmio_write_32((uintptr_t)(a), bswap32((v)))
-#elif defined(NXP_SNVS_LE)
-#define snvs_read32(a) mmio_read_32((uintptr_t)(a))
-#define snvs_write32(a, v) mmio_write_32((uintptr_t)(a), (v))
-#else
-#error Please define CCSR SNVS register endianness
-#endif
-
-void snvs_init(uintptr_t nxp_snvs_addr);
-uint32_t get_snvs_state(void);
-void transition_snvs_non_secure(void);
-void transition_snvs_soft_fail(void);
-uint32_t transition_snvs_trusted(void);
-uint32_t transition_snvs_secure(void);
-
-uint32_t snvs_read_lp_gpr_bit(uint32_t offset, uint32_t bit_pos);
-void snvs_write_lp_gpr_bit(uint32_t offset, uint32_t bit_pos, bool flag_val);
-
-void snvs_disable_zeroize_lp_gpr(void);
-
-#if defined(NXP_NV_SW_MAINT_LAST_EXEC_DATA) && defined(NXP_COINED_BB)
-uint32_t snvs_read_app_data(void);
-uint32_t snvs_read_app_data_bit(uint32_t bit_pos);
-void snvs_clear_app_data(void);
-void snvs_write_app_data_bit(uint32_t bit_pos);
-#endif
-
-#endif /* __ASSEMBLER__ */
-
-/* SSM_ST field in SNVS status reg */
-#define HPSTS_CHECK_SSM_ST 0x900 /* SNVS is in check state */
-#define HPSTS_NON_SECURE_SSM_ST 0xb00 /* SNVS is in non secure state */
-#define HPSTS_TRUST_SSM_ST 0xd00 /* SNVS is in trusted state */
-#define HPSTS_SECURE_SSM_ST 0xf00 /* SNVS is in secure state */
-#define HPSTS_SOFT_FAIL_SSM_ST 0x300 /* SNVS is in soft fail state */
-#define HPSTS_MASK_SSM_ST 0xf00 /* SSM_ST field mask in SNVS reg */
-
-/* SNVS register bits */
-#define HPCOM_SW_SV 0x100 /* Security Violation bit */
-#define HPCOM_SW_FSV 0x200 /* Fatal Security Violation bit */
-#define HPCOM_SSM_ST 0x1 /* SSM_ST field in SNVS command reg */
-#define HPCOM_SSM_ST_DIS 0x2 /* Disable Secure to Trusted State */
-#define HPCOM_SSM_SFNS_DIS 0x4 /* Disable Soft Fail to Non-Secure */
-
-#define NXP_LP_GPR0_OFFSET 0x90
-#define NXP_LPCR_OFFSET 0x38
-#define NXP_GPR_Z_DIS_BIT 24
-
-#ifdef NXP_COINED_BB
-
-#ifndef NXP_APP_DATA_LP_GPR_OFFSET
-#define NXP_APP_DATA_LP_GPR_OFFSET NXP_LP_GPR0_OFFSET
-#endif
-
-#define NXP_LPGPR_ZEROTH_BIT 0
-
-#endif /* NXP_COINED_BB */
-
-#endif /* SNVS_H */
diff --git a/drivers/nxp/sfp/fuse_prov.c b/drivers/nxp/sfp/fuse_prov.c
index 4d30f5f28d..165474fb8a 100644
--- a/drivers/nxp/sfp/fuse_prov.c
+++ b/drivers/nxp/sfp/fuse_prov.c
@@ -326,7 +326,7 @@ static int prog_ospr1(struct fuse_hdr_t *fuse_hdr,
struct sfp_ccsr_regs_t *sfp_ccsr_regs)
{
int ret;
- uint32_t mask;
+ uint32_t mask = 0;
#ifdef NXP_SFP_VER_3_4
if (((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) {
diff --git a/drivers/nxp/sfp/fuse_prov.h b/drivers/nxp/sfp/fuse_prov.h
deleted file mode 100644
index e015318daa..0000000000
--- a/drivers/nxp/sfp/fuse_prov.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#if !defined(FUSE_PROV_H) && defined(POLICY_FUSE_PROVISION)
-#define FUSE_PROV_H
-
-#include <endian.h>
-#include <lib/mmio.h>
-
-#define MASK_NONE U(0xFFFFFFFF)
-#define ERROR_WRITE U(0xA)
-#define ERROR_ALREADY_BLOWN U(0xB)
-
-/* Flag bit shifts */
-#define FLAG_POVDD_SHIFT U(0)
-#define FLAG_SYSCFG_SHIFT U(1)
-#define FLAG_SRKH_SHIFT U(2)
-#define FLAG_MC_SHIFT U(3)
-#define FLAG_DCV0_SHIFT U(4)
-#define FLAG_DCV1_SHIFT U(5)
-#define FLAG_DRV0_SHIFT U(6)
-#define FLAG_DRV1_SHIFT U(7)
-#define FLAG_OUID0_SHIFT U(8)
-#define FLAG_OUID1_SHIFT U(9)
-#define FLAG_OUID2_SHIFT U(10)
-#define FLAG_OUID3_SHIFT U(11)
-#define FLAG_OUID4_SHIFT U(12)
-#define FLAG_DBG_LVL_SHIFT U(13)
-#define FLAG_OTPMK_SHIFT U(16)
-#define FLAG_OUID_MASK U(0x1F)
-#define FLAG_DEBUG_MASK U(0xF)
-#define FLAG_OTPMK_MASK U(0xF)
-
-/* OTPMK flag values */
-#define PROG_OTPMK_MIN U(0x0)
-#define PROG_OTPMK_RANDOM U(0x1)
-#define PROG_OTPMK_USER U(0x2)
-#define PROG_OTPMK_RANDOM_MIN U(0x5)
-#define PROG_OTPMK_USER_MIN U(0x6)
-#define PROG_NO_OTPMK U(0x8)
-
-#define OTPMK_MIM_BITS_MASK U(0xF0000000)
-
-/* System configuration bit shifts */
-#define SCB_WP_SHIFT U(0)
-#define SCB_ITS_SHIFT U(2)
-#define SCB_NSEC_SHIFT U(4)
-#define SCB_ZD_SHIFT U(5)
-#define SCB_K0_SHIFT U(15)
-#define SCB_K1_SHIFT U(14)
-#define SCB_K2_SHIFT U(13)
-#define SCB_K3_SHIFT U(12)
-#define SCB_K4_SHIFT U(11)
-#define SCB_K5_SHIFT U(10)
-#define SCB_K6_SHIFT U(9)
-#define SCB_FR0_SHIFT U(30)
-#define SCB_FR1_SHIFT U(31)
-
-/* Fuse Header Structure */
-struct fuse_hdr_t {
- uint8_t barker[4]; /* 0x00 Barker code */
- uint32_t flags; /* 0x04 Script flags */
- uint32_t povdd_gpio; /* 0x08 GPIO for POVDD */
- uint32_t otpmk[8]; /* 0x0C-0x2B OTPMK */
- uint32_t srkh[8]; /* 0x2C-0x4B SRKH */
- uint32_t oem_uid[5]; /* 0x4C-0x5F OEM unique id's */
- uint32_t dcv[2]; /* 0x60-0x67 Debug Challenge */
- uint32_t drv[2]; /* 0x68-0x6F Debug Response */
- uint32_t ospr1; /* 0x70 OSPR1 */
- uint32_t sc; /* 0x74 OSPR0 (System Configuration) */
- uint32_t reserved[2]; /* 0x78-0x7F Reserved */
-};
-
-/* Function to do fuse provisioning */
-int provision_fuses(unsigned long long fuse_scr_addr,
- bool en_povdd_status);
-
-#define EFUSE_POWERUP_DELAY_mSec U(25)
-#endif /* FUSE_PROV_H */
diff --git a/drivers/nxp/sfp/sfp.h b/drivers/nxp/sfp/sfp.h
deleted file mode 100644
index 2cb4c7db51..0000000000
--- a/drivers/nxp/sfp/sfp.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef SFP_H
-#define SFP_H
-
-#include <endian.h>
-#include <lib/mmio.h>
-
-/* SFP Configuration Register Offsets */
-#define SFP_INGR_OFFSET U(0x20)
-#define SFP_SVHESR_OFFSET U(0x24)
-#define SFP_SFPCR_OFFSET U(0x28)
-#define SFP_VER_OFFSET U(0x38)
-
-/* SFP Hamming register masks for OTPMK and DRV */
-#define SFP_SVHESR_DRV_MASK U(0x7F)
-#define SFP_SVHESR_OTPMK_MASK U(0x7FC00)
-
-/* SFP commands */
-#define SFP_INGR_READFB_CMD U(0x1)
-#define SFP_INGR_PROGFB_CMD U(0x2)
-#define SFP_INGR_ERROR_MASK U(0x100)
-
-/* SFPCR Masks */
-#define SFP_SFPCR_WD U(0x80000000)
-#define SFP_SFPCR_WDL U(0x40000000)
-
-/* SFPCR Masks */
-#define SFP_SFPCR_WD U(0x80000000)
-#define SFP_SFPCR_WDL U(0x40000000)
-
-#define SFP_FUSE_REGS_OFFSET U(0x200)
-
-#ifdef NXP_SFP_VER_3_4
-#define OSPR0_SC_MASK U(0xC000FE35)
-#elif defined(NXP_SFP_VER_3_2)
-#define OSPR0_SC_MASK U(0x0000E035)
-#endif
-
-#if defined(NXP_SFP_VER_3_4)
-#define OSPR_KEY_REVOC_SHIFT U(9)
-#define OSPR_KEY_REVOC_MASK U(0x0000fe00)
-#elif defined(NXP_SFP_VER_3_2)
-#define OSPR_KEY_REVOC_SHIFT U(13)
-#define OSPR_KEY_REVOC_MASK U(0x0000e000)
-#endif /* NXP_SFP_VER_3_4 */
-
-#define OSPR1_MC_MASK U(0xFFFF0000)
-#define OSPR1_DBG_LVL_MASK U(0x00000007)
-
-#define OSPR_ITS_MASK U(0x00000004)
-#define OSPR_WP_MASK U(0x00000001)
-
-#define MAX_OEM_UID U(5)
-#define SRK_HASH_SIZE U(32)
-
-/* SFP CCSR Register Map */
-struct sfp_ccsr_regs_t {
- uint32_t ospr; /* 0x200 OSPR0 */
- uint32_t ospr1; /* 0x204 OSPR1 */
- uint32_t dcv[2]; /* 0x208 Debug Challenge Value */
- uint32_t drv[2]; /* 0x210 Debug Response Value */
- uint32_t fswpr; /* 0x218 FSL Section Write Protect */
- uint32_t fsl_uid[2]; /* 0x21c FSL UID 0 */
- uint32_t isbcr; /* 0x224 ISBC Configuration */
- uint32_t fsspr[3]; /* 0x228 FSL Scratch Pad */
- uint32_t otpmk[8]; /* 0x234 OTPMK */
- uint32_t srk_hash[SRK_HASH_SIZE/sizeof(uint32_t)];
- /* 0x254 Super Root Key Hash */
- uint32_t oem_uid[MAX_OEM_UID]; /* 0x274 OEM UID 0 */
-};
-
-uintptr_t get_sfp_addr(void);
-void sfp_init(uintptr_t nxp_sfp_addr);
-uint32_t *get_sfp_srk_hash(void);
-int sfp_check_its(void);
-int sfp_check_oem_wp(void);
-uint32_t get_key_revoc(void);
-void set_sfp_wr_disable(void);
-int sfp_program_fuses(void);
-
-uint32_t sfp_read_oem_uid(uint8_t oem_uid);
-uint32_t sfp_write_oem_uid(uint8_t oem_uid, uint32_t sfp_val);
-
-#ifdef NXP_SFP_BE
-#define sfp_read32(a) bswap32(mmio_read_32((uintptr_t)(a)))
-#define sfp_write32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
-#elif defined(NXP_SFP_LE)
-#define sfp_read32(a) mmio_read_32((uintptr_t)(a))
-#define sfp_write32(a, v) mmio_write_32((uintptr_t)(a), (v))
-#else
-#error Please define CCSR SFP register endianness
-#endif
-
-#endif/* SFP_H */
diff --git a/drivers/nxp/sfp/sfp.mk b/drivers/nxp/sfp/sfp.mk
index 2546dc2812..de708c5df3 100644
--- a/drivers/nxp/sfp/sfp.mk
+++ b/drivers/nxp/sfp/sfp.mk
@@ -1,5 +1,5 @@
#
-# Copyright 2020 NXP
+# Copyright 2021 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,14 +9,12 @@ ifeq (${SFP_ADDED},)
SFP_ADDED := 1
$(eval $(call add_define, NXP_SFP_ENABLED))
-SFP_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/sfp
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/sfp
-PLAT_INCLUDES += -I$(SFP_DRIVERS_PATH)
-
-SFP_SOURCES += $(SFP_DRIVERS_PATH)/sfp.c
+SFP_SOURCES += $(PLAT_DRIVERS_PATH)/sfp/sfp.c
ifeq (${FUSE_PROG}, 1)
-SFP_BL2_SOURCES += $(SFP_DRIVERS_PATH)/fuse_prov.c
+SFP_BL2_SOURCES += $(PLAT_DRIVERS_PATH)/sfp/fuse_prov.c
endif
ifeq (${BL_COMM_SFP_NEEDED},yes)
diff --git a/drivers/nxp/sfp/sfp_error_codes.h b/drivers/nxp/sfp/sfp_error_codes.h
deleted file mode 100644
index 7be7a274de..0000000000
--- a/drivers/nxp/sfp/sfp_error_codes.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef SFP_ERROR_CODES_H
-#define SFP_ERROR_CODES_H
-
- /* Error codes */
-#define ERROR_FUSE_BARKER 0x1
-#define ERROR_READFB_CMD 0x2
-#define ERROR_PROGFB_CMD 0x3
-#define ERROR_SRKH_ALREADY_BLOWN 0x4
-#define ERROR_SRKH_WRITE 0x5
-#define ERROR_OEMUID_ALREADY_BLOWN 0x6
-#define ERROR_OEMUID_WRITE 0x7
-#define ERROR_DCV_ALREADY_BLOWN 0x8
-#define ERROR_DCV_WRITE 0x9
-#define ERROR_DRV_ALREADY_BLOWN 0xa
-#define ERROR_DRV_HAMMING_ERROR 0xb
-#define ERROR_DRV_WRITE 0x18
-#define ERROR_OTPMK_ALREADY_BLOWN 0xc
-#define ERROR_OTPMK_HAMMING_ERROR 0xd
-#define ERROR_OTPMK_USER_MIN 0xe
-#define ERROR_OSPR1_ALREADY_BLOWN 0xf
-#define ERROR_OSPR1_WRITE 0x10
-#define ERROR_SC_ALREADY_BLOWN 0x11
-#define ERROR_SC_WRITE 0x12
-#define ERROR_POVDD_GPIO_FAIL 0x13
-#define ERROR_GPIO_SET_FAIL 0x14
-#define ERROR_GPIO_RESET_FAIL 0x15
-#define ERROR_OTPMK_SEC_DISABLED 0x16
-#define ERROR_OTPMK_SEC_ERROR 0x17
-#define ERROR_OTPMK_WRITE 0x19
-#define PLAT_ERROR_ENABLE_POVDD 0x20
-#define PLAT_ERROR_DISABLE_POVDD 0x21
-
-#endif /* SFP_ERROR_CODES_H */
diff --git a/drivers/nxp/timer/nxp_timer.c b/drivers/nxp/timer/nxp_timer.c
index 8eecd2e99b..448c0ba93e 100644
--- a/drivers/nxp/timer/nxp_timer.c
+++ b/drivers/nxp/timer/nxp_timer.c
@@ -59,7 +59,7 @@ static uint32_t timer_get_value(void)
static void delay_timer_init_args(uint32_t mult, uint32_t div)
{
- ops.get_timer_value = timer_get_value,
+ ops.get_timer_value = timer_get_value;
ops.clk_mult = mult;
ops.clk_div = div;
diff --git a/drivers/nxp/timer/nxp_timer.h b/drivers/nxp/timer/nxp_timer.h
deleted file mode 100644
index 280e5b27fc..0000000000
--- a/drivers/nxp/timer/nxp_timer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#
-#ifndef NXP_TIMER_H
-#define NXP_TIMER_H
-
- /* System Counter Offset and Bit Mask */
-#define SYS_COUNTER_CNTCR_OFFSET 0x0
-#define SYS_COUNTER_CNTCR_EN 0x00000001
-#define CNTCR_EN_MASK 0x1
-
-#ifndef __ASSEMBLER__
-uint64_t get_timer_val(uint64_t start);
-
-#ifdef IMAGE_BL31
-void ls_configure_sys_timer(uintptr_t ls_sys_timctl_base,
- uint8_t ls_config_cntacr,
- uint8_t plat_ls_ns_timer_frame_id);
-void enable_init_timer(void);
-#endif
-
-/*
- * Initialise the nxp on-chip free rolling usec counter as the delay
- * timer.
- */
-void delay_timer_init(uintptr_t nxp_timer_addr);
-void ls_bl31_timer_init(uintptr_t nxp_timer_addr);
-#endif /* __ASSEMBLER__ */
-
-#endif /* NXP_TIMER_H */
diff --git a/drivers/nxp/timer/timer.mk b/drivers/nxp/timer/timer.mk
index b9e298f2fd..d658d19f15 100644
--- a/drivers/nxp/timer/timer.mk
+++ b/drivers/nxp/timer/timer.mk
@@ -8,10 +8,8 @@ ifeq (${ADD_TIMER},)
ADD_TIMER := 1
-TIMER_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/timer
-
-PLAT_INCLUDES += -I$(TIMER_DRIVERS_PATH)
-TIMER_SOURCES += drivers/delay_timer/delay_timer.c \
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/timer
+TIMER_SOURCES += drivers/delay_timer/delay_timer.c \
$(PLAT_DRIVERS_PATH)/timer/nxp_timer.c
ifeq (${BL_COMM_TIMER_NEEDED},yes)
diff --git a/drivers/nxp/trdc/imx_trdc.c b/drivers/nxp/trdc/imx_trdc.c
new file mode 100644
index 0000000000..ab665852c3
--- /dev/null
+++ b/drivers/nxp/trdc/imx_trdc.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2022-2023 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/nxp/trdc/imx_trdc.h>
+#include <lib/mmio.h>
+
+
+int trdc_mda_set_cpu(uintptr_t trdc_base, uint32_t mda_inst,
+ uint32_t mda_reg, uint8_t sa, uint8_t dids,
+ uint8_t did, uint8_t pe, uint8_t pidm, uint8_t pid)
+{
+ uint32_t val = mmio_read_32(trdc_base + MDAC_W_X(mda_inst, mda_reg));
+ /* invalid: config non-cpu master with cpu config format. */
+ if ((val & MDA_DFMT) != 0U) {
+ return -EINVAL;
+ }
+
+ val = MDA_VLD | MDA_DFMT0_DID(pid) | MDA_DFMT0_PIDM(pidm) | MDA_DFMT0_PE(pe) |
+ MDA_DFMT0_SA(sa) | MDA_DFMT0_DIDS(dids) | MDA_DFMT0_DID(did);
+
+ mmio_write_32(trdc_base + MDAC_W_X(mda_inst, mda_reg), val);
+
+ return 0;
+}
+
+int trdc_mda_set_noncpu(uintptr_t trdc_base, uint32_t mda_inst,
+ bool did_bypass, uint8_t sa, uint8_t pa,
+ uint8_t did)
+{
+ uint32_t val = mmio_read_32(trdc_base + MDAC_W_X(mda_inst, 0));
+
+ /* invalid: config cpu master with non-cpu config format. */
+ if ((val & MDA_DFMT) == 0U) {
+ return -EINVAL;
+ }
+
+ val = MDA_VLD | MDA_DFMT1_SA(sa) | MDA_DFMT1_PA(pa) | MDA_DFMT1_DID(did) |
+ MDA_DFMT1_DIDB(did_bypass ? 1U : 0U);
+
+ mmio_write_32(trdc_base + MDAC_W_X(mda_inst, 0), val);
+
+ return 0;
+}
+
+static uintptr_t trdc_get_mbc_base(uintptr_t trdc_reg, uint32_t mbc_x)
+{
+ struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
+ uint32_t mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
+
+ if (mbc_x >= mbc_num) {
+ return 0U;
+ }
+
+ return trdc_reg + 0x10000 + 0x2000 * mbc_x;
+}
+
+static uintptr_t trdc_get_mrc_base(uintptr_t trdc_reg, uint32_t mrc_x)
+{
+ struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg;
+ uint32_t mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0);
+ uint32_t mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0);
+
+ if (mrc_x >= mrc_num) {
+ return 0U;
+ }
+
+ return trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x;
+}
+
+uint32_t trdc_mbc_blk_num(uintptr_t trdc_reg, uint32_t mbc_x, uint32_t mem_x)
+{
+ uint32_t glbcfg;
+ struct mbc_mem_dom *mbc_dom;
+ struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
+
+ if (mbc_base == NULL) {
+ return 0;
+ }
+
+ /* only first dom has the glbcfg */
+ mbc_dom = &mbc_base->mem_dom[0];
+ glbcfg = mmio_read_32((uintptr_t)&mbc_dom->mem_glbcfg[mem_x]);
+
+ return MBC_BLK_NUM(glbcfg);
+}
+
+uint32_t trdc_mrc_rgn_num(uintptr_t trdc_reg, uint32_t mrc_x)
+{
+ uint32_t glbcfg;
+ struct mrc_rgn_dom *mrc_dom;
+ struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
+
+ if (mrc_base == NULL) {
+ return 0;
+ }
+
+ /* only first dom has the glbcfg */
+ mrc_dom = &mrc_base->mrc_dom[0];
+ glbcfg = mmio_read_32((uintptr_t)&mrc_dom->mrc_glbcfg[0]);
+
+ return MBC_BLK_NUM(glbcfg);
+}
+
+int trdc_mbc_set_control(uintptr_t trdc_reg, uint32_t mbc_x,
+ uint32_t glbac_id, uint32_t glbac_val)
+{
+ struct mbc_mem_dom *mbc_dom;
+ struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
+
+ if (mbc_base == NULL || glbac_id >= GLBAC_NUM) {
+ return -EINVAL;
+ }
+
+ /* only first dom has the glbac */
+ mbc_dom = &mbc_base->mem_dom[0];
+
+ mmio_write_32((uintptr_t)&mbc_dom->memn_glbac[glbac_id], glbac_val);
+
+ return 0;
+}
+
+int trdc_mbc_blk_config(uintptr_t trdc_reg, uint32_t mbc_x,
+ uint32_t dom_x, uint32_t mem_x, uint32_t blk_x,
+ bool sec_access, uint32_t glbac_id)
+{
+ uint32_t *cfg_w;
+ uint32_t index, offset, val;
+ struct mbc_mem_dom *mbc_dom;
+ struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x);
+
+ if (mbc_base == NULL || glbac_id >= GLBAC_NUM) {
+ return -EINVAL;
+ }
+
+ mbc_dom = &mbc_base->mem_dom[dom_x];
+
+ switch (mem_x) {
+ case 0:
+ cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8];
+ break;
+ case 1:
+ cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8];
+ break;
+ case 2:
+ cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8];
+ break;
+ case 3:
+ cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8];
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ index = blk_x % 8;
+ offset = index * 4;
+
+ val = mmio_read_32((uintptr_t)cfg_w);
+ val &= ~(0xF << offset);
+
+ /*
+ * MBC0-3
+ * Global 0, 0x7777 secure pri/user read/write/execute,
+ * S400 has already set it. So select MBC0_MEMN_GLBAC0
+ */
+ if (sec_access) {
+ val |= ((0x0 | (glbac_id & 0x7)) << offset);
+ mmio_write_32((uintptr_t)cfg_w, val);
+ } else {
+ /* nse bit set */
+ val |= ((0x8 | (glbac_id & 0x7)) << offset);
+ mmio_write_32((uintptr_t)cfg_w, val);
+ }
+
+ return 0;
+}
+
+int trdc_mrc_set_control(uintptr_t trdc_reg, uint32_t mrc_x,
+ uint32_t glbac_id, uint32_t glbac_val)
+{
+ struct mrc_rgn_dom *mrc_dom;
+ struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
+
+ if (mrc_base == NULL || glbac_id >= GLBAC_NUM) {
+ return -EINVAL;
+ }
+
+ /* only first dom has the glbac */
+ mrc_dom = &mrc_base->mrc_dom[0];
+
+ mmio_write_32((uintptr_t)&mrc_dom->memn_glbac[glbac_id], glbac_val);
+
+ return 0;
+}
+
+int trdc_mrc_rgn_config(uintptr_t trdc_reg, uint32_t mrc_x,
+ uint32_t dom_x, uint32_t rgn_id,
+ uint32_t addr_start, uint32_t addr_size,
+ bool sec_access, uint32_t glbac_id)
+{
+ uint32_t *desc_w;
+ uint32_t addr_end;
+ struct mrc_rgn_dom *mrc_dom;
+ struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x);
+
+ if (mrc_base == NULL || glbac_id >= GLBAC_NUM || rgn_id >= MRC_REG_ALL) {
+ return -EINVAL;
+ }
+
+ mrc_dom = &mrc_base->mrc_dom[dom_x];
+
+ addr_end = addr_start + addr_size - 1;
+ addr_start &= ~0x3fff;
+ addr_end &= ~0x3fff;
+
+ desc_w = &mrc_dom->rgn_desc_words[rgn_id][0];
+
+ if (sec_access) {
+ mmio_write_32((uintptr_t)desc_w, addr_start | (glbac_id & 0x7));
+ mmio_write_32((uintptr_t)(desc_w + 1), addr_end | 0x1);
+ } else {
+ mmio_write_32((uintptr_t)desc_w, addr_start | (glbac_id & 0x7));
+ mmio_write_32((uintptr_t)(desc_w + 1), (addr_end | 0x1 | 0x10));
+ }
+
+ return 0;
+}
+
+bool trdc_mrc_enabled(uintptr_t mrc_base)
+{
+ return (mmio_read_32(mrc_base) & BIT(15));
+}
+
+bool trdc_mbc_enabled(uintptr_t mbc_base)
+{
+ return (mmio_read_32(mbc_base) & BIT(14));
+}
+
+static bool is_trdc_mgr_slot(uintptr_t trdc_base, uint8_t mbc_id,
+ uint8_t mem_id, uint16_t blk_id)
+{
+ unsigned int i;
+
+ for (i = 0U; i < trdc_mgr_num; i++) {
+ if (trdc_mgr_blks[i].trdc_base == trdc_base) {
+ if (mbc_id == trdc_mgr_blks[i].mbc_id &&
+ mem_id == trdc_mgr_blks[i].mbc_mem_id &&
+ (blk_id == trdc_mgr_blks[i].blk_mgr ||
+ blk_id == trdc_mgr_blks[i].blk_mc)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * config the TRDC MGR & MC's access policy. only the secure privilege
+ * mode SW can access it.
+ */
+void trdc_mgr_mbc_setup(struct trdc_mgr_info *mgr)
+{
+ unsigned int i;
+
+ /*
+ * If the MBC is global enabled, need to cconfigure the MBCs of
+ * TRDC MGR & MC correctly.
+ */
+ if (trdc_mbc_enabled(mgr->trdc_base)) {
+ /* ONLY secure privilige can access */
+ trdc_mbc_set_control(mgr->trdc_base, mgr->mbc_id, 7, 0x6000);
+ for (i = 0U; i < 16U; i++) {
+ trdc_mbc_blk_config(mgr->trdc_base, mgr->mbc_id, i,
+ mgr->mbc_mem_id, mgr->blk_mgr, true, 7);
+
+ trdc_mbc_blk_config(mgr->trdc_base, mgr->mbc_id, i,
+ mgr->mbc_mem_id, mgr->blk_mc, true, 7);
+ }
+ }
+}
+
+/*
+ * Set up the TRDC access policy for all the resources under
+ * the TRDC control.
+ */
+void trdc_setup(struct trdc_config_info *cfg)
+{
+ unsigned int i, j, num;
+ bool is_mgr;
+
+ /* config the MRCs */
+ if (trdc_mrc_enabled(cfg->trdc_base)) {
+ /* set global access policy */
+ for (i = 0U; i < cfg->num_mrc_glbac; i++) {
+ trdc_mrc_set_control(cfg->trdc_base,
+ cfg->mrc_glbac[i].mbc_mrc_id,
+ cfg->mrc_glbac[i].glbac_id,
+ cfg->mrc_glbac[i].glbac_val);
+ }
+
+ /* set each MRC region access policy */
+ for (i = 0U; i < cfg->num_mrc_cfg; i++) {
+ trdc_mrc_rgn_config(cfg->trdc_base, cfg->mrc_cfg[i].mrc_id,
+ cfg->mrc_cfg[i].dom_id,
+ cfg->mrc_cfg[i].region_id,
+ cfg->mrc_cfg[i].region_start,
+ cfg->mrc_cfg[i].region_size,
+ cfg->mrc_cfg[i].secure,
+ cfg->mrc_cfg[i].glbac_id);
+ }
+ }
+
+ /* config the MBCs */
+ if (trdc_mbc_enabled(cfg->trdc_base)) {
+ /* set MBC global access policy */
+ for (i = 0U; i < cfg->num_mbc_glbac; i++) {
+ trdc_mbc_set_control(cfg->trdc_base,
+ cfg->mbc_glbac[i].mbc_mrc_id,
+ cfg->mbc_glbac[i].glbac_id,
+ cfg->mbc_glbac[i].glbac_val);
+ }
+
+ for (i = 0U; i < cfg->num_mbc_cfg; i++) {
+ if (cfg->mbc_cfg[i].blk_id == MBC_BLK_ALL) {
+ num = trdc_mbc_blk_num(cfg->trdc_base,
+ cfg->mbc_cfg[i].mbc_id,
+ cfg->mbc_cfg[i].mem_id);
+
+ for (j = 0U; j < num; j++) {
+ /* Skip mgr and mc */
+ is_mgr = is_trdc_mgr_slot(cfg->trdc_base,
+ cfg->mbc_cfg[i].mbc_id,
+ cfg->mbc_cfg[i].mem_id, j);
+ if (is_mgr) {
+ continue;
+ }
+
+ trdc_mbc_blk_config(cfg->trdc_base,
+ cfg->mbc_cfg[i].mbc_id,
+ cfg->mbc_cfg[i].dom_id,
+ cfg->mbc_cfg[i].mem_id, j,
+ cfg->mbc_cfg[i].secure,
+ cfg->mbc_cfg[i].glbac_id);
+ }
+ } else {
+ trdc_mbc_blk_config(cfg->trdc_base,
+ cfg->mbc_cfg[i].mbc_id,
+ cfg->mbc_cfg[i].dom_id,
+ cfg->mbc_cfg[i].mem_id,
+ cfg->mbc_cfg[i].blk_id,
+ cfg->mbc_cfg[i].secure,
+ cfg->mbc_cfg[i].glbac_id);
+ }
+ }
+ }
+}
diff --git a/drivers/nxp/tzc/plat_tzc380.c b/drivers/nxp/tzc/plat_tzc380.c
new file mode 100644
index 0000000000..5b275635cb
--- /dev/null
+++ b/drivers/nxp/tzc/plat_tzc380.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2018-2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat_tzc380.h>
+
+#pragma weak populate_tzc380_reg_list
+
+#ifdef DEFAULT_TZASC_CONFIG
+/*
+ * Typical Memory map of DRAM0
+ * |-----------NXP_NS_DRAM_ADDR ( = NXP_DRAM0_ADDR)----------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * | |
+ * |------- (NXP_NS_DRAM_ADDR + NXP_NS_DRAM_SIZE - 1) -------|
+ * |-----------------NXP_SECURE_DRAM_ADDR--------------------|
+ * | |
+ * | |
+ * | |
+ * | SECURE REGION (= 64MB) |
+ * | |
+ * | |
+ * | |
+ * |--- (NXP_SECURE_DRAM_ADDR + NXP_SECURE_DRAM_SIZE - 1)----|
+ * |-----------------NXP_SP_SHRD_DRAM_ADDR-------------------|
+ * | |
+ * | Secure EL1 Payload SHARED REGION (= 2MB) |
+ * | |
+ * |-----------(NXP_DRAM0_ADDR + NXP_DRAM0_SIZE - 1)---------|
+ *
+ *
+ *
+ * Typical Memory map of DRAM1
+ * |---------------------NXP_DRAM1_ADDR----------------------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * |---(NXP_DRAM1_ADDR + Dynamically calculated Size - 1) ---|
+ *
+ *
+ * Typical Memory map of DRAM2
+ * |---------------------NXP_DRAM2_ADDR----------------------|
+ * | |
+ * | |
+ * | Non-SECURE REGION |
+ * | |
+ * | |
+ * |---(NXP_DRAM2_ADDR + Dynamically calculated Size - 1) ---|
+ */
+
+/*****************************************************************************
+ * This function sets up access permissions on memory regions
+ *
+ * Input:
+ * tzc380_reg_list : TZC380 Region List
+ * dram_idx : DRAM index
+ * list_idx : TZC380 Region List Index
+ * dram_start_addr : Start address of DRAM at dram_idx.
+ * dram_size : Size of DRAM at dram_idx.
+ * secure_dram_sz : Secure DRAM Size
+ * shrd_dram_sz : Shared DRAM Size
+ *
+ * Out:
+ * list_idx : last populated index + 1
+ *
+ ****************************************************************************/
+int populate_tzc380_reg_list(struct tzc380_reg *tzc380_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz)
+{
+ /* Region 0: Default region marked as Non-Secure */
+ if (list_idx == 0) {
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_NS_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_DISABLE;
+ tzc380_reg_list[list_idx].addr = UL(0x0);
+ tzc380_reg_list[list_idx].size = 0x0;
+ tzc380_reg_list[list_idx].sub_mask = 0x0; /* all enabled */
+ list_idx++;
+ }
+ /* Continue with list entries for index > 0 */
+ if (dram_idx == 0) {
+ /*
+ * Region 1: Secure Region on DRAM 1 for 2MB out of 2MB,
+ * excluding 0 sub-region(=256KB).
+ */
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_S_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_ENABLE;
+ tzc380_reg_list[list_idx].addr = dram_start_addr + dram_size;
+ tzc380_reg_list[list_idx].size = TZC_REGION_SIZE_2M;
+ tzc380_reg_list[list_idx].sub_mask = 0x0; /* all enabled */
+ list_idx++;
+
+ /*
+ * Region 2: Secure Region on DRAM 1 for 54MB out of 64MB,
+ * excluding 1 sub-rgion(=8MB) of 8MB.
+ */
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_S_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_ENABLE;
+ tzc380_reg_list[list_idx].addr = dram_start_addr + dram_size + shrd_dram_sz;
+ tzc380_reg_list[list_idx].size = TZC_REGION_SIZE_64M;
+ tzc380_reg_list[list_idx].sub_mask = 0x80; /* Disable sub-region 7 */
+ list_idx++;
+
+ /*
+ * Region 3: Secure Region on DRAM 1 for 6MB out of 8MB,
+ * excluding 2 sub-rgion(=1MB) of 2MB.
+ */
+ tzc380_reg_list[list_idx].secure = TZC_ATTR_SP_S_RW;
+ tzc380_reg_list[list_idx].enabled = TZC_ATTR_REGION_ENABLE;
+ tzc380_reg_list[list_idx].addr = dram_start_addr + dram_size + secure_dram_sz;
+ tzc380_reg_list[list_idx].size = TZC_REGION_SIZE_8M;
+ tzc380_reg_list[list_idx].sub_mask = 0xC0; /* Disable sub-region 6 & 7 */
+ list_idx++;
+
+ }
+
+ return list_idx;
+}
+#else
+int populate_tzc380_reg_list(struct tzc380_reg *tzc380_reg_list,
+ int dram_idx, int list_idx,
+ uint64_t dram_start_addr,
+ uint64_t dram_size,
+ uint32_t secure_dram_sz,
+ uint32_t shrd_dram_sz)
+{
+ ERROR("tzc380_reg_list used is not a default list\n");
+ ERROR("%s needs to be over-written.\n", __func__);
+ return 0;
+}
+#endif /* DEFAULT_TZASC_CONFIG */
+
+
+void mem_access_setup(uintptr_t base, uint32_t total_regions,
+ struct tzc380_reg *tzc380_reg_list)
+{
+ uint32_t indx = 0;
+ unsigned int attr_value;
+
+ VERBOSE("Configuring TrustZone Controller tzc380\n");
+
+ tzc380_init(base);
+
+ tzc380_set_action(TZC_ACTION_NONE);
+
+ for (indx = 0; indx < total_regions; indx++) {
+ attr_value = tzc380_reg_list[indx].secure |
+ TZC_ATTR_SUBREG_DIS(tzc380_reg_list[indx].sub_mask) |
+ TZC_ATTR_REGION_SIZE(tzc380_reg_list[indx].size) |
+ tzc380_reg_list[indx].enabled;
+
+ tzc380_configure_region(indx, tzc380_reg_list[indx].addr,
+ attr_value);
+ }
+
+ tzc380_set_action(TZC_ACTION_ERR);
+}
diff --git a/drivers/nxp/tzc/plat_tzc400.h b/drivers/nxp/tzc/plat_tzc400.h
deleted file mode 100644
index 1b8e3a4da1..0000000000
--- a/drivers/nxp/tzc/plat_tzc400.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2021 NXP
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#if !defined(PLAT_TZC400_H) && defined(IMAGE_BL2)
-#define PLAT_TZC400_H
-
-#include <tzc400.h>
-
-/* Structure to configure TZC Regions' boundaries and attributes. */
-struct tzc400_reg {
- uint8_t reg_filter_en;
- unsigned long long start_addr;
- unsigned long long end_addr;
- unsigned int sec_attr;
- unsigned int nsaid_permissions;
-};
-
-#define TZC_REGION_NS_NONE 0x00000000U
-
-/* NXP Platforms do not support NS Access ID (NSAID) based non-secure access.
- * Supports only non secure through generic NS ACCESS ID
- */
-#define TZC_NS_ACCESS_ID 0xFFFFFFFFU
-
-/* Number of DRAM regions to be configured
- * for the platform can be over-written.
- *
- * Array tzc400_reg_list too, needs be over-written
- * if there is any changes to default DRAM region
- * configuration.
- */
-#ifndef MAX_NUM_TZC_REGION
-/* 3 regions:
- * Region 0(default),
- * Region 1 (DRAM0, Secure Memory),
- * Region 2 (DRAM0, Shared memory)
- */
-#define MAX_NUM_TZC_REGION NUM_DRAM_REGIONS + 3
-#define DEFAULT_TZASC_CONFIG 1
-#endif
-
-void mem_access_setup(uintptr_t base, uint32_t total_regions,
- struct tzc400_reg *tzc400_reg_list);
-int populate_tzc400_reg_list(struct tzc400_reg *tzc400_reg_list,
- int dram_idx, int list_idx,
- uint64_t dram_start_addr,
- uint64_t dram_size,
- uint32_t secure_dram_sz,
- uint32_t shrd_dram_sz);
-
-#endif /* PLAT_TZC400_H */
diff --git a/drivers/nxp/tzc/tzc.mk b/drivers/nxp/tzc/tzc.mk
index 830d78ed51..4418bfc10b 100644
--- a/drivers/nxp/tzc/tzc.mk
+++ b/drivers/nxp/tzc/tzc.mk
@@ -8,18 +8,23 @@ ifeq (${ADD_TZASC},)
ADD_TZASC := 1
-TZASC_DRIVERS_PATH := ${PLAT_DRIVERS_PATH}/tzc
-
-PLAT_INCLUDES += -I$(TZASC_DRIVERS_PATH)
+PLAT_INCLUDES += -I$(PLAT_DRIVERS_INCLUDE_PATH)/tzc
ifeq ($(TZC_ID), TZC400)
TZASC_SOURCES += drivers/arm/tzc/tzc400.c\
- $(TZASC_DRIVERS_PATH)/plat_tzc400.c
-else ifeq ($(TZC_ID), NONE)
+ $(PLAT_DRIVERS_PATH)/tzc/plat_tzc400.c
+else
+ifeq ($(TZC_ID), TZC380)
+TZASC_SOURCES += drivers/arm/tzc/tzc380.c\
+ $(PLAT_DRIVERS_PATH)/tzc/plat_tzc380.c
+else
+ifeq ($(TZC_ID), NONE)
$(info -> No TZC present on platform)
else
$(error -> TZC type not set!)
endif
+endif
+endif
ifeq (${BL_COMM_TZASC_NEEDED},yes)
BL_COMMON_SOURCES += ${TZASC_SOURCES}
diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c
index 1b804deef6..8b1046d007 100644
--- a/drivers/partition/gpt.c
+++ b/drivers/partition/gpt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,7 @@
#include <string.h>
#include <common/debug.h>
+#include <drivers/partition/efi.h>
#include <drivers/partition/gpt.h>
#include <lib/utils.h>
@@ -25,14 +26,16 @@ static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out)
/* check whether the unicode string is valid */
for (i = 1; i < (EFI_NAMELEN << 1); i += 2) {
- if (name[i] != '\0')
+ if (name[i] != '\0') {
return -EINVAL;
+ }
}
/* convert the unicode string to ascii string */
for (i = 0; i < (EFI_NAMELEN << 1); i += 2) {
str_out[i >> 1] = name[i];
- if (name[i] == '\0')
+ if (name[i] == '\0') {
break;
+ }
}
return 0;
}
@@ -57,5 +60,8 @@ int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry)
entry->length = (uint64_t)(gpt_entry->last_lba -
gpt_entry->first_lba + 1) *
PLAT_PARTITION_BLOCK_SIZE;
+ guidcpy(&entry->part_guid, &gpt_entry->unique_uuid);
+ guidcpy(&entry->type_guid, &gpt_entry->type_uuid);
+
return 0;
}
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
index 68133eaf4f..888a824307 100644
--- a/drivers/partition/partition.c
+++ b/drivers/partition/partition.c
@@ -1,15 +1,18 @@
/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
+#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <common/debug.h>
+#include <common/tf_crc32.h>
#include <drivers/io/io_storage.h>
+#include <drivers/partition/efi.h>
#include <drivers/partition/partition.h>
#include <drivers/partition/gpt.h>
#include <drivers/partition/mbr.h>
@@ -31,7 +34,7 @@ static void dump_entries(int num)
name[len + j] = ' ';
}
name[EFI_NAMELEN - 1] = '\0';
- VERBOSE("%d: %s %llx-%llx\n", i + 1, name, list.list[i].start,
+ VERBOSE("%d: %s %" PRIx64 "-%" PRIx64 "\n", i + 1, name, list.list[i].start,
list.list[i].start + list.list[i].length - 4);
}
}
@@ -46,67 +49,108 @@ static void dump_entries(int num)
static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
{
size_t bytes_read;
- uintptr_t offset;
int result;
+ mbr_entry_t *tmp;
assert(mbr_entry != NULL);
/* MBR partition table is in LBA0. */
result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
if (result != 0) {
- WARN("Failed to seek (%i)\n", result);
+ VERBOSE("Failed to seek (%i)\n", result);
return result;
}
result = io_read(image_handle, (uintptr_t)&mbr_sector,
PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
- if (result != 0) {
- WARN("Failed to read data (%i)\n", result);
+ if ((result != 0) || (bytes_read != PLAT_PARTITION_BLOCK_SIZE)) {
+ VERBOSE("Failed to read data (%i)\n", result);
return result;
}
/* Check MBR boot signature. */
if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
(mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+ VERBOSE("MBR boot signature failure\n");
return -ENOENT;
}
- offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
- memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
+
+ tmp = (mbr_entry_t *)(&mbr_sector[MBR_PRIMARY_ENTRY_OFFSET]);
+
+ if (tmp->first_lba != 1) {
+ VERBOSE("MBR header may have an invalid first LBA\n");
+ return -EINVAL;
+ }
+
+ if ((tmp->sector_nums == 0) || (tmp->sector_nums == UINT32_MAX)) {
+ VERBOSE("MBR header entry has an invalid number of sectors\n");
+ return -EINVAL;
+ }
+
+ memcpy(mbr_entry, tmp, sizeof(mbr_entry_t));
return 0;
}
/*
- * Load GPT header and check the GPT signature.
+ * Load GPT header and check the GPT signature and header CRC.
* If partition numbers could be found, check & update it.
*/
-static int load_gpt_header(uintptr_t image_handle)
+static int load_gpt_header(uintptr_t image_handle, size_t header_offset,
+ gpt_header_t *header)
{
- gpt_header_t header;
size_t bytes_read;
int result;
+ uint32_t header_crc, calc_crc;
- result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
+ result = io_seek(image_handle, IO_SEEK_SET, header_offset);
if (result != 0) {
+ VERBOSE("Failed to seek into the GPT image at offset (%zu)\n",
+ header_offset);
return result;
}
- result = io_read(image_handle, (uintptr_t)&header,
+ result = io_read(image_handle, (uintptr_t)header,
sizeof(gpt_header_t), &bytes_read);
if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
+ VERBOSE("GPT header read error(%i) or read mismatch occurred,"
+ "expected(%zu) and actual(%zu)\n", result,
+ sizeof(gpt_header_t), bytes_read);
return result;
}
- if (memcmp(header.signature, GPT_SIGNATURE,
- sizeof(header.signature)) != 0) {
+ if (memcmp(header->signature, GPT_SIGNATURE,
+ sizeof(header->signature)) != 0) {
+ VERBOSE("GPT header signature failure\n");
+ return -EINVAL;
+ }
+
+ /*
+ * UEFI Spec 2.8 March 2019 Page 119: HeaderCRC32 value is
+ * computed by setting this field to 0, and computing the
+ * 32-bit CRC for HeaderSize bytes.
+ */
+ header_crc = header->header_crc;
+ header->header_crc = 0U;
+
+ calc_crc = tf_crc32(0U, (uint8_t *)header, sizeof(gpt_header_t));
+ if (header_crc != calc_crc) {
+ ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n",
+ header_crc, calc_crc);
return -EINVAL;
}
+ header->header_crc = header_crc;
+
/* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
- list.entry_count = header.list_num;
+ list.entry_count = header->list_num;
if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
}
+
return 0;
}
+/*
+ * Load a single MBR entry based on details from MBR header.
+ */
static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry,
- int part_number)
+ int part_number)
{
size_t bytes_read;
uintptr_t offset;
@@ -116,19 +160,20 @@ static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry,
/* MBR partition table is in LBA0. */
result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
if (result != 0) {
- WARN("Failed to seek (%i)\n", result);
+ VERBOSE("Failed to seek (%i)\n", result);
return result;
}
result = io_read(image_handle, (uintptr_t)&mbr_sector,
PLAT_PARTITION_BLOCK_SIZE, &bytes_read);
if (result != 0) {
- WARN("Failed to read data (%i)\n", result);
+ VERBOSE("Failed to read data (%i)\n", result);
return result;
}
/* Check MBR boot signature. */
if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
(mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+ VERBOSE("MBR Entry boot signature failure\n");
return -ENOENT;
}
offset = (uintptr_t)&mbr_sector +
@@ -139,14 +184,17 @@ static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry,
return 0;
}
+/*
+ * Load MBR entries based on max number of partition entries.
+ */
static int load_mbr_entries(uintptr_t image_handle)
{
mbr_entry_t mbr_entry;
- int i;
+ unsigned int i;
list.entry_count = MBR_PRIMARY_ENTRY_NUMBER;
- for (i = 0; i < list.entry_count; i++) {
+ for (i = 0U; i < list.entry_count; i++) {
load_mbr_entry(image_handle, &mbr_entry, i);
list.list[i].start = mbr_entry.first_lba * 512;
list.list[i].length = mbr_entry.sector_nums * 512;
@@ -156,35 +204,76 @@ static int load_mbr_entries(uintptr_t image_handle)
return 0;
}
+/*
+ * Try to read and load a single GPT entry.
+ */
static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
{
- size_t bytes_read;
+ size_t bytes_read = 0U;
int result;
assert(entry != NULL);
result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
- &bytes_read);
- if (sizeof(gpt_entry_t) != bytes_read)
+ &bytes_read);
+ if ((result != 0) || (sizeof(gpt_entry_t) != bytes_read)) {
+ VERBOSE("GPT Entry read error(%i) or read mismatch occurred,"
+ "expected(%zu) and actual(%zu)\n", result,
+ sizeof(gpt_entry_t), bytes_read);
return -EINVAL;
+ }
+
return result;
}
-static int verify_partition_gpt(uintptr_t image_handle)
+/*
+ * Retrieve each entry in the partition table, parse the data from each
+ * entry and store them in the list of partition table entries.
+ */
+static int load_partition_gpt(uintptr_t image_handle, gpt_header_t header)
{
+ const signed long long gpt_entry_offset = LBA(header.part_lba);
gpt_entry_t entry;
- int result, i;
+ int result;
+ unsigned int i;
+ uint32_t calc_crc = 0U;
- for (i = 0; i < list.entry_count; i++) {
+ result = io_seek(image_handle, IO_SEEK_SET, gpt_entry_offset);
+ if (result != 0) {
+ VERBOSE("Failed to seek (%i), Failed loading GPT partition"
+ "table entries\n", result);
+ return result;
+ }
+
+ for (i = 0U; i < list.entry_count; i++) {
result = load_gpt_entry(image_handle, &entry);
- assert(result == 0);
+ if (result != 0) {
+ VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n",
+ i, result);
+ return result;
+ }
+
result = parse_gpt_entry(&entry, &list.list[i]);
if (result != 0) {
+ result = io_seek(image_handle, IO_SEEK_SET,
+ (gpt_entry_offset + (i * sizeof(gpt_entry_t))));
+ if (result != 0) {
+ VERBOSE("Failed to seek (%i)\n", result);
+ return result;
+ }
break;
}
+
+ /*
+ * Calculate CRC of Partition entry array to compare with CRC
+ * value in header
+ */
+ calc_crc = tf_crc32(calc_crc, (uint8_t *)&entry, sizeof(gpt_entry_t));
}
if (i == 0) {
+ VERBOSE("No Valid GPT Entries found\n");
return -EINVAL;
}
+
/*
* Only records the valid partition number that is loaded from
* partition table.
@@ -192,9 +281,121 @@ static int verify_partition_gpt(uintptr_t image_handle)
list.entry_count = i;
dump_entries(list.entry_count);
+ /*
+ * If there are less valid entries than the possible number of entries
+ * from the header, continue to load the partition entry table to
+ * calculate the full CRC in order to check against the partition CRC
+ * from the header for validation.
+ */
+ for (; i < header.list_num; i++) {
+ result = load_gpt_entry(image_handle, &entry);
+ if (result != 0) {
+ VERBOSE("Failed to load gpt entry data(%u) error is (%i)\n",
+ i, result);
+ return result;
+ }
+
+ calc_crc = tf_crc32(calc_crc, (uint8_t *)&entry, sizeof(gpt_entry_t));
+ }
+
+ if (header.part_crc != calc_crc) {
+ ERROR("Invalid GPT Partition Array Entry CRC: Expected 0x%x"
+ " but got 0x%x.\n", header.part_crc, calc_crc);
+ return -EINVAL;
+ }
+
return 0;
}
+/*
+ * Try retrieving and parsing the backup-GPT header and backup GPT entries.
+ * Last 33 blocks contains the backup-GPT entries and header.
+ */
+static int load_backup_gpt(unsigned int image_id, unsigned int sector_nums)
+{
+ int result;
+ gpt_header_t header;
+ size_t gpt_header_offset;
+ uintptr_t dev_handle, image_spec, image_handle;
+ io_block_spec_t *block_spec;
+ int part_num_entries;
+
+ result = plat_get_image_source(image_id, &dev_handle, &image_spec);
+ if (result != 0) {
+ VERBOSE("Failed to obtain reference to image id=%u (%i)\n",
+ image_id, result);
+ return result;
+ }
+
+ block_spec = (io_block_spec_t *)image_spec;
+ /*
+ * We need to read 32 blocks of GPT entries and one block of GPT header
+ * try mapping only last 33 last blocks from the image to read the
+ * Backup-GPT header and its entries.
+ */
+ part_num_entries = (PLAT_PARTITION_MAX_ENTRIES / 4);
+ /* Move the offset base to LBA-33 */
+ block_spec->offset += LBA(sector_nums - part_num_entries);
+ /*
+ * Set length as LBA-33, 32 blocks of backup-GPT entries and one
+ * block of backup-GPT header.
+ */
+ block_spec->length = LBA(part_num_entries + 1);
+
+ result = io_open(dev_handle, image_spec, &image_handle);
+ if (result != 0) {
+ VERBOSE("Failed to access image id (%i)\n", result);
+ return result;
+ }
+
+ INFO("Trying to retrieve back-up GPT header\n");
+ /* Last block is backup-GPT header, after the end of GPT entries */
+ gpt_header_offset = LBA(part_num_entries);
+ result = load_gpt_header(image_handle, gpt_header_offset, &header);
+ if ((result != 0) || (header.part_lba == 0)) {
+ ERROR("Failed to retrieve Backup GPT header,"
+ "Partition maybe corrupted\n");
+ goto out;
+ }
+
+ /*
+ * Note we mapped last 33 blocks(LBA-33), first block here starts with
+ * entries while last block was header.
+ */
+ header.part_lba = 0;
+ result = load_partition_gpt(image_handle, header);
+
+out:
+ io_close(image_handle);
+ return result;
+}
+
+/*
+ * Load a GPT partition, Try retrieving and parsing the primary GPT header,
+ * if its corrupted try loading backup GPT header and then retrieve list
+ * of partition table entries found from the GPT.
+ */
+static int load_primary_gpt(uintptr_t image_handle, unsigned int first_lba)
+{
+ int result;
+ size_t gpt_header_offset;
+ gpt_header_t header;
+
+ /* Try to load Primary GPT header from LBA1 */
+ gpt_header_offset = LBA(first_lba);
+ result = load_gpt_header(image_handle, gpt_header_offset, &header);
+ if ((result != 0) || (header.part_lba == 0)) {
+ VERBOSE("Failed to retrieve Primary GPT header,"
+ "trying to retrieve back-up GPT header\n");
+ return result;
+ }
+
+ return load_partition_gpt(image_handle, header);
+}
+
+/*
+ * Load the partition table info based on the image id provided.
+ */
int load_partition_table(unsigned int image_id)
{
uintptr_t dev_handle, image_handle, image_spec = 0;
@@ -203,41 +404,46 @@ int load_partition_table(unsigned int image_id)
result = plat_get_image_source(image_id, &dev_handle, &image_spec);
if (result != 0) {
- WARN("Failed to obtain reference to image id=%u (%i)\n",
+ VERBOSE("Failed to obtain reference to image id=%u (%i)\n",
image_id, result);
return result;
}
result = io_open(dev_handle, image_spec, &image_handle);
if (result != 0) {
- WARN("Failed to access image id=%u (%i)\n", image_id, result);
+ VERBOSE("Failed to access image id=%u (%i)\n", image_id, result);
return result;
}
result = load_mbr_header(image_handle, &mbr_entry);
if (result != 0) {
- WARN("Failed to access image id=%u (%i)\n", image_id, result);
- return result;
+ VERBOSE("Failed to access image id=%u (%i)\n", image_id, result);
+ goto out;
}
if (mbr_entry.type == PARTITION_TYPE_GPT) {
- result = load_gpt_header(image_handle);
- assert(result == 0);
- result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
- assert(result == 0);
- result = verify_partition_gpt(image_handle);
+ result = load_primary_gpt(image_handle, mbr_entry.first_lba);
+ if (result != 0) {
+ io_close(image_handle);
+ return load_backup_gpt(BKUP_GPT_IMAGE_ID,
+ mbr_entry.sector_nums);
+ }
} else {
result = load_mbr_entries(image_handle);
}
+out:
io_close(image_handle);
return result;
}
+/*
+ * Try retrieving a partition table entry based on the name of the partition.
+ */
const partition_entry_t *get_partition_entry(const char *name)
{
- int i;
+ unsigned int i;
- for (i = 0; i < list.entry_count; i++) {
+ for (i = 0U; i < list.entry_count; i++) {
if (strcmp(name, list.list[i].name) == 0) {
return &list.list[i];
}
@@ -245,12 +451,66 @@ const partition_entry_t *get_partition_entry(const char *name)
return NULL;
}
+/*
+ * Try retrieving a partition table entry based on the partition type GUID.
+ */
+const partition_entry_t *get_partition_entry_by_type(
+ const struct efi_guid *type_guid)
+{
+ unsigned int i;
+
+ for (i = 0U; i < list.entry_count; i++) {
+ if (guidcmp(type_guid, &list.list[i].type_guid) == 0) {
+ return &list.list[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Try retrieving a partition table entry based on the unique partition GUID.
+ */
+const partition_entry_t *get_partition_entry_by_guid(
+ const struct efi_guid *part_guid)
+{
+ unsigned int i;
+
+ for (i = 0U; i < list.entry_count; i++) {
+ if (guidcmp(part_guid, &list.list[i].part_guid) == 0) {
+ return &list.list[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Return entry to the list of partition table entries.
+ */
const partition_entry_list_t *get_partition_entry_list(void)
{
return &list;
}
+/*
+ * Try loading partition table info for the given image ID.
+ */
void partition_init(unsigned int image_id)
{
- load_partition_table(image_id);
+ int ret;
+
+ ret = load_partition_table(image_id);
+ if (ret != 0) {
+ ERROR("Failed to parse partition with image id = %u\n",
+ image_id);
+ }
+}
+
+/*
+ * Load a GPT based image.
+ */
+int gpt_partition_init(void)
+{
+ return load_partition_table(GPT_IMAGE_ID);
}
diff --git a/drivers/renesas/common/common.c b/drivers/renesas/common/common.c
index 9b7c1eb16c..a0aa4808d6 100644
--- a/drivers/renesas/common/common.c
+++ b/drivers/renesas/common/common.c
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2018-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
+#include "cpg_registers.h"
#include "rcar_private.h"
#if IMAGE_BL31
@@ -16,7 +17,7 @@ void cpg_write(uintptr_t regadr, uint32_t regval)
{
uint32_t value = regval;
- mmio_write_32((uintptr_t) RCAR_CPGWPR, ~value);
+ mmio_write_32(CPG_CPGWPR, ~value);
mmio_write_32(regadr, value);
}
diff --git a/drivers/renesas/common/console/rcar_console.S b/drivers/renesas/common/console/rcar_console.S
index 29baa67a4a..b683d7bfb9 100644
--- a/drivers/renesas/common/console/rcar_console.S
+++ b/drivers/renesas/common/console/rcar_console.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -63,7 +63,7 @@ endfunc console_rcar_register
* ---------------------------------------------
*/
func console_rcar_init
- mov w0, #0
+ mov w0, #1
ret
endfunc console_rcar_init
diff --git a/drivers/renesas/common/console/rcar_printf.c b/drivers/renesas/common/console/rcar_printf.c
index ad074fe059..6af10eeca2 100644
--- a/drivers/renesas/common/console/rcar_printf.c
+++ b/drivers/renesas/common/console/rcar_printf.c
@@ -24,7 +24,7 @@
/*
* The log is initialized and used before BL31 xlat tables are initialized,
* therefore the log memory is a device memory at that point. Make sure the
- * memory is correclty aligned and accessed only with up-to 32bit, aligned,
+ * memory is correctly aligned and accessed only with up-to 32bit, aligned,
* writes.
*/
CASSERT((RCAR_BL31_LOG_BASE & 0x7) == 0, assert_bl31_log_base_unaligned);
diff --git a/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c b/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c
index a49510ed5d..f0113f1110 100644
--- a/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c
+++ b/drivers/renesas/common/ddr/ddr_a/ddr_init_d3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, Renesas Electronics Corporation.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -11,7 +11,11 @@
#include "rcar_def.h"
#include "../ddr_regs.h"
-#define RCAR_DDR_VERSION "rev.0.01"
+#define RCAR_DDR_VERSION "rev.0.02"
+
+/* Average periodic refresh interval[ns]. Support 3900,7800 */
+#define REFRESH_RATE 3900
+
#if RCAR_LSI != RCAR_D3
#error "Don't have DDR initialize routine."
@@ -44,7 +48,7 @@ static void init_ddr_d3_1866(void)
mmio_write_32(DBSC_DBTR16, 0x09210507);
mmio_write_32(DBSC_DBTR17, 0x040E0000);
mmio_write_32(DBSC_DBTR18, 0x00000200);
- mmio_write_32(DBSC_DBTR19, 0x012B004B);
+ mmio_write_32(DBSC_DBTR19, 0x0129004B);
mmio_write_32(DBSC_DBTR20, 0x020000FB);
mmio_write_32(DBSC_DBTR21, 0x00040004);
mmio_write_32(DBSC_DBBL, 0x00000000);
@@ -54,8 +58,8 @@ static void init_ddr_d3_1866(void)
mmio_write_32(DBSC_DBDFICNT_0, 0x00000010);
mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
mmio_write_32(DBSC_DBSCHRW1, 0x00000046);
- mmio_write_32(DBSC_SCFCTST0, 0x0D020D04);
- mmio_write_32(DBSC_SCFCTST1, 0x0306040C);
+ mmio_write_32(DBSC_SCFCTST0, 0x0C050B03);
+ mmio_write_32(DBSC_SCFCTST1, 0x0305030C);
mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A);
mmio_write_32(DBSC_DBCMD, 0x01000001);
@@ -101,7 +105,9 @@ static void init_ddr_d3_1866(void)
;
mmio_write_32(DBSC_DBPDRGA_0, 0x00000004);
- mmio_write_32(DBSC_DBPDRGD_0, 0x0A206F89);
+ mmio_write_32(DBSC_DBPDRGD_0,
+ (uint32_t) (REFRESH_RATE * 928 / 125) - 400
+ + 0x0A300000);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000022);
mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000023);
@@ -117,7 +123,11 @@ static void init_ddr_d3_1866(void)
mmio_write_32(DBSC_DBPDRGA_0, 0x00000028);
mmio_write_32(DBSC_DBPDRGD_0, 0x00000046);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000029);
- mmio_write_32(DBSC_DBPDRGD_0, 0x000000A0);
+ if (REFRESH_RATE > 3900) {
+ mmio_write_32(DBSC_DBPDRGD_0, 0x00000020);
+ } else {
+ mmio_write_32(DBSC_DBPDRGD_0, 0x000000A0);
+ }
mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C);
mmio_write_32(DBSC_DBPDRGD_0, 0x81003047);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000020);
@@ -225,8 +235,10 @@ static void init_ddr_d3_1866(void)
mmio_write_32(DBSC_DBPDRGA_0, 0x000000AF);
r2 = mmio_read_32(DBSC_DBPDRGD_0);
+ mmio_write_32(DBSC_DBPDRGA_0, 0x000000AF);
mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF);
+ mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF);
r2 = mmio_read_32(DBSC_DBPDRGD_0);
mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
@@ -296,8 +308,10 @@ static void init_ddr_d3_1866(void)
mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E);
mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
- mmio_write_32(DBSC_DBCALCNF, 0x0100401B);
- mmio_write_32(DBSC_DBRFCNF1, 0x00080E23);
+ mmio_write_32(DBSC_DBCALCNF,
+ (uint32_t) (64000000 / REFRESH_RATE) + 0x01000000);
+ mmio_write_32(DBSC_DBRFCNF1,
+ (uint32_t) (REFRESH_RATE * 116 / 125) + 0x00080000);
mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
mmio_write_32(DBSC_DBRFEN, 0x00000001);
@@ -346,6 +360,19 @@ static void init_ddr_d3_1600(void)
{
uint32_t i, r2, r3, r5, r6, r7, r12;
+ mmio_write_32(CPG_CPGWPR, 0x5A5AFFFF);
+ mmio_write_32(CPG_CPGWPCR, 0xA5A50000);
+
+ mmio_write_32(CPG_SRCR4, 0x20000000);
+
+ mmio_write_32(0xE61500DC, 0xe2200000);
+ while (!(mmio_read_32(CPG_PLLECR) & BIT(11)))
+ ;
+
+ mmio_write_32(CPG_SRSTCLR4, 0x20000000);
+
+ mmio_write_32(CPG_CPGWPCR, 0xA5A50001);
+
mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
mmio_write_32(DBSC_DBKIND, 0x00000007);
mmio_write_32(DBSC_DBMEMCONF_0_0, 0x0f030a01);
@@ -363,14 +390,14 @@ static void init_ddr_d3_1600(void)
mmio_write_32(DBSC_DBTR10, 0x0000000C);
mmio_write_32(DBSC_DBTR11, 0x0000000A);
mmio_write_32(DBSC_DBTR12, 0x00120012);
- mmio_write_32(DBSC_DBTR13, 0x000000D0);
+ mmio_write_32(DBSC_DBTR13, 0x000000CE);
mmio_write_32(DBSC_DBTR14, 0x00140005);
mmio_write_32(DBSC_DBTR15, 0x00050004);
mmio_write_32(DBSC_DBTR16, 0x071F0305);
mmio_write_32(DBSC_DBTR17, 0x040C0000);
mmio_write_32(DBSC_DBTR18, 0x00000200);
mmio_write_32(DBSC_DBTR19, 0x01000040);
- mmio_write_32(DBSC_DBTR20, 0x020000D8);
+ mmio_write_32(DBSC_DBTR20, 0x020000D6);
mmio_write_32(DBSC_DBTR21, 0x00040004);
mmio_write_32(DBSC_DBBL, 0x00000000);
mmio_write_32(DBSC_DBODT0, 0x00000001);
@@ -379,8 +406,8 @@ static void init_ddr_d3_1600(void)
mmio_write_32(DBSC_DBDFICNT_0, 0x00000010);
mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
mmio_write_32(DBSC_DBSCHRW1, 0x00000046);
- mmio_write_32(DBSC_SCFCTST0, 0x0D020C04);
- mmio_write_32(DBSC_SCFCTST1, 0x0305040C);
+ mmio_write_32(DBSC_SCFCTST0, 0x0D050B03);
+ mmio_write_32(DBSC_SCFCTST1, 0x0306030C);
mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A);
mmio_write_32(DBSC_DBCMD, 0x01000001);
@@ -426,13 +453,14 @@ static void init_ddr_d3_1600(void)
;
mmio_write_32(DBSC_DBPDRGA_0, 0x00000004);
- mmio_write_32(DBSC_DBPDRGD_0, 0x08C05FF0);
+ mmio_write_32(DBSC_DBPDRGD_0,
+ (uint32_t) (REFRESH_RATE * 792 / 125) - 400 + 0x08B00000);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000022);
mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000023);
mmio_write_32(DBSC_DBPDRGD_0, 0x2D9C0B66);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000024);
- mmio_write_32(DBSC_DBPDRGD_0, 0x2A88C400);
+ mmio_write_32(DBSC_DBPDRGD_0, 0x2A88B400);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000025);
mmio_write_32(DBSC_DBPDRGD_0, 0x30005200);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000026);
@@ -442,7 +470,11 @@ static void init_ddr_d3_1600(void)
mmio_write_32(DBSC_DBPDRGA_0, 0x00000028);
mmio_write_32(DBSC_DBPDRGD_0, 0x00000046);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000029);
- mmio_write_32(DBSC_DBPDRGD_0, 0x00000098);
+ if (REFRESH_RATE > 3900) {
+ mmio_write_32(DBSC_DBPDRGD_0, 0x00000018);
+ } else {
+ mmio_write_32(DBSC_DBPDRGD_0, 0x00000098);
+ }
mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C);
mmio_write_32(DBSC_DBPDRGD_0, 0x81003047);
mmio_write_32(DBSC_DBPDRGA_0, 0x00000020);
@@ -549,9 +581,11 @@ static void init_ddr_d3_1600(void)
mmio_write_32(DBSC_DBPDRGA_0, 0x000000AF);
r2 = mmio_read_32(DBSC_DBPDRGD_0);
+ mmio_write_32(DBSC_DBPDRGA_0, 0x000000AF);
mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF);
r2 = mmio_read_32(DBSC_DBPDRGD_0);
+ mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF);
mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0);
@@ -620,8 +654,10 @@ static void init_ddr_d3_1600(void)
mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E);
mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
- mmio_write_32(DBSC_DBCALCNF, 0x0100401B);
- mmio_write_32(DBSC_DBRFCNF1, 0x00080C30);
+ mmio_write_32(DBSC_DBCALCNF,
+ (uint32_t) (64000000 / REFRESH_RATE) + 0x01000000);
+ mmio_write_32(DBSC_DBRFCNF1,
+ (uint32_t) (REFRESH_RATE * 99 / 125) + 0x00080000);
mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
mmio_write_32(DBSC_DBRFEN, 0x00000001);
@@ -693,7 +729,7 @@ int32_t rcar_dram_init(void)
ddr_mbps = 1600;
}
- NOTICE("BL2: DDR%d\n", ddr_mbps);
+ NOTICE("BL2: DDR%d(%s)\n", ddr_mbps, RCAR_DDR_VERSION);
return 0;
}
diff --git a/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c b/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c
index aa3bc245b7..3f6a9484de 100644
--- a/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c
+++ b/drivers/renesas/common/ddr/ddr_b/boot_init_dram.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2021, Renesas Electronics Corporation.
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -1180,6 +1180,11 @@ static void regif_pll_wa(void)
ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
_reg_PHY_LP4_BOOT_TOP_PLL_CTRL
));
+ if (ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_LP4_BOOT_LOW_FREQ_SEL)) {
+ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LP4_BOOT_LOW_FREQ_SEL),
+ _cnf_DDR_PHY_ADR_G_REGSET[0x7f & ddr_regdef_adr(
+ _reg_PHY_LP4_BOOT_LOW_FREQ_SEL)]);
+ }
}
reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LPDDR3_CS),
@@ -2856,6 +2861,16 @@ static uint32_t pll3_freq(uint32_t on)
timeout = wait_freqchgreq(1);
+ if ((!((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11))) && (on)) {
+ if (((1600U * ddr_mbpsdiv) < ddr_mbps) || (prr_product == PRR_PRODUCT_M3)) {
+ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL), 0x01421142U);
+ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL_CA), 0x00000142U);
+ } else {
+ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL), 0x03421342U);
+ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL_CA), 0x00000342U);
+ }
+ }
+
if (timeout) {
return 1;
}
@@ -4147,7 +4162,13 @@ int32_t rcar_dram_init(void)
}
/* THCTR Bit6: PONM=0 , Bit0: THSST=0 */
- data_l = mmio_read_32(THS1_THCTR) & 0xFFFFFFBE;
+ data_l = mmio_read_32(THS1_THCTR);
+ if (data_l & 0x00000040U) {
+ data_l = data_l & 0xFFFFFFBEU;
+ } else {
+ data_l = data_l | BIT(1);
+ }
+
mmio_write_32(THS1_THCTR, data_l);
/* Judge product and cut */
diff --git a/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c
index 45b6b088c1..bbb0200866 100644
--- a/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c
+++ b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_config.c
@@ -12,6 +12,9 @@
#if (RZG_SOC == 1)
#define BOARDNUM 4
#else
+
+#include <board.h>
+
#define BOARDNUM 22
#endif /* RZG_SOC == 1 */
#define BOARD_JUDGE_AUTO
@@ -1967,6 +1970,44 @@ static uint32_t rzg2_board_judge(void)
}
#endif /* RZG_SOC == 1 */
+#if (RZG_SOC == 0) && (RCAR_DRAM_LPDDR4_MEMCONF != 0)
+static uint32_t ddr_rank_judge(void)
+{
+ uint32_t brd;
+
+#if (RCAR_DRAM_MEMRANK == 0)
+ int32_t ret;
+ uint32_t type = 0U;
+ uint32_t rev = 0U;
+
+ brd = 99U;
+ ret = rcar_get_board_type(&type, &rev);
+ if ((ret == 0) && (rev != 0xFFU)) {
+ if (type == (uint32_t)BOARD_SALVATOR_XS) {
+ if (rev == 0x11U) {
+ brd = 14U;
+ } else {
+ brd = 8U;
+ }
+ } else if (type == (uint32_t)BOARD_STARTER_KIT_PRE) {
+ if (rev == 0x21U) {
+ brd = 14U;
+ } else {
+ brd = 8U;
+ }
+ }
+ }
+#elif (RCAR_DRAM_MEMRANK == 1)
+ brd = 14U;
+#elif (RCAR_DRAM_MEMRANK == 2)
+ brd = 8U;
+#else
+#error Invalid value was set to RCAR_DRAM_MEMRANK
+#endif /* (RCAR_DRAM_MEMRANK == 0) */
+ return brd;
+}
+#endif /* (RCAR_DRAM_LPDDR4_MEMCONF != 0) */
+
static uint32_t _board_judge(void)
{
uint32_t brd;
@@ -1985,7 +2026,7 @@ static uint32_t _board_judge(void)
#if (RCAR_DRAM_LPDDR4_MEMCONF == 0)
brd = 7;
#else
- brd = 8;
+ brd = ddr_rank_judge();
#endif
}
} else if (prr_product == PRR_PRODUCT_M3) {
@@ -2039,7 +2080,7 @@ static uint32_t _board_judge(void)
#if (RCAR_DRAM_LPDDR4_MEMCONF == 0)
brd = 7;
#else
- brd = 8;
+ brd = ddr_rank_judge();
#endif
}
} else if (prr_product == PRR_PRODUCT_M3N) {
diff --git a/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h
index 56363eb997..328adbfe4c 100644
--- a/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h
+++ b/drivers/renesas/common/ddr/ddr_b/boot_init_dram_regdef.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation.
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#define RCAR_DDR_VERSION "rev.0.40"
+#define RCAR_DDR_VERSION "rev.0.42"
#define DRAM_CH_CNT 0x04
#define SLICE_CNT 0x04
#define CS_CNT 0x02
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h
index e5258af6c6..5a662ec313 100644
--- a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_h3ver2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, Renesas Electronics Corporation.
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -230,8 +230,8 @@ static const uint32_t
/*0693*/ 0x00000000,
/*0694*/ 0x00000000,
/*0695*/ 0x00005064,
- /*0696*/ 0x01421142,
- /*0697*/ 0x00000142,
+ /*0696*/ 0x05421542,
+ /*0697*/ 0x00000542,
/*0698*/ 0x00000000,
/*0699*/ 0x000f1100,
/*069a*/ 0x0f110f11,
@@ -240,12 +240,12 @@ static const uint32_t
/*069d*/ 0x0002c000,
/*069e*/ 0x02c002c0,
/*069f*/ 0x000002c0,
- /*06a0*/ 0x03421342,
- /*06a1*/ 0x00000342,
+ /*06a0*/ 0x05421542,
+ /*06a1*/ 0x00000542,
/*06a2*/ 0x00000000,
/*06a3*/ 0x00000000,
/*06a4*/ 0x05020000,
- /*06a5*/ 0x14000000,
+ /*06a5*/ 0x14000001,
/*06a6*/ 0x027f6e00,
/*06a7*/ 0x047f027f,
/*06a8*/ 0x00027f6e,
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h
index b491f0e917..482a2a5ce7 100644
--- a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, Renesas Electronics Corporation.
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -210,8 +210,8 @@ static const uint32_t DDR_PHY_ADR_G_REGSET_M3[DDR_PHY_ADR_G_REGSET_NUM_M3] = {
/*0b8b*/ 0x01010100,
/*0b8c*/ 0x00000600,
/*0b8d*/ 0x50640000,
- /*0b8e*/ 0x01421142,
- /*0b8f*/ 0x00000142,
+ /*0b8e*/ 0x03421342,
+ /*0b8f*/ 0x00000342,
/*0b90*/ 0x00000000,
/*0b91*/ 0x000f1600,
/*0b92*/ 0x0f160f16,
diff --git a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h
index fb3032deeb..436c1a0bb1 100644
--- a/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h
+++ b/drivers/renesas/common/ddr/ddr_b/init_dram_tbl_m3n.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation.
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -230,8 +230,8 @@ static const uint32_t DDR_PHY_ADR_G_REGSET_M3N[DDR_PHY_ADR_G_REGSET_NUM_M3N] = {
/*0b93*/ 0x00000000,
/*0b94*/ 0x00000000,
/*0b95*/ 0x00005064,
- /*0b96*/ 0x01421142,
- /*0b97*/ 0x00000142,
+ /*0b96*/ 0x05421542,
+ /*0b97*/ 0x00000542,
/*0b98*/ 0x00000000,
/*0b99*/ 0x000f1600,
/*0b9a*/ 0x0f160f16,
@@ -241,12 +241,12 @@ static const uint32_t DDR_PHY_ADR_G_REGSET_M3N[DDR_PHY_ADR_G_REGSET_NUM_M3N] = {
/*0b9e*/ 0x02c002c0,
/*0b9f*/ 0x000002c0,
/*0ba0*/ 0x08040201,
- /*0ba1*/ 0x03421342,
- /*0ba2*/ 0x00000342,
+ /*0ba1*/ 0x05421542,
+ /*0ba2*/ 0x00000542,
/*0ba3*/ 0x00000000,
/*0ba4*/ 0x00000000,
/*0ba5*/ 0x05030000,
- /*0ba6*/ 0x00010700,
+ /*0ba6*/ 0x00010701,
/*0ba7*/ 0x00000014,
/*0ba8*/ 0x00027f6e,
/*0ba9*/ 0x047f027f,
diff --git a/drivers/renesas/common/emmc/emmc_cmd.c b/drivers/renesas/common/emmc/emmc_cmd.c
index d255bffc9f..02fc26bba9 100644
--- a/drivers/renesas/common/emmc/emmc_cmd.c
+++ b/drivers/renesas/common/emmc/emmc_cmd.c
@@ -254,8 +254,7 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
(SD_INFO2_ALL_ERR | SD_INFO2_CLEAR));
state = ESTATE_ISSUE_CMD;
- /* through */
-
+ /* fallthrough */
case ESTATE_ISSUE_CMD:
/* ARG */
SETR_32(SD_ARG, mmc_drv_obj.cmd_info.arg);
@@ -454,8 +453,8 @@ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
SETR_32(SD_STOP, 0x00000000U);
mmc_drv_obj.during_dma_transfer = FALSE;
}
- /* through */
+ /* fallthrough */
case ESTATE_ERROR:
if (err_not_care_flag == TRUE) {
mmc_drv_obj.during_cmd_processing = FALSE;
diff --git a/drivers/renesas/common/emmc/emmc_hal.h b/drivers/renesas/common/emmc/emmc_hal.h
index 0a8551719f..4e6942fafd 100644
--- a/drivers/renesas/common/emmc/emmc_hal.h
+++ b/drivers/renesas/common/emmc/emmc_hal.h
@@ -512,7 +512,7 @@ typedef struct {
/* maximum block count which can be transferred at once */
uint32_t max_block_count;
- /* maximum clock frequence in Hz supported by HW */
+ /* maximum clock frequency in Hz supported by HW */
uint32_t max_clock_freq;
/* maximum data bus width supported by HW */
diff --git a/drivers/renesas/common/emmc/emmc_init.c b/drivers/renesas/common/emmc/emmc_init.c
index 354aa3c82a..c0ec600f5f 100644
--- a/drivers/renesas/common/emmc/emmc_init.c
+++ b/drivers/renesas/common/emmc/emmc_init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,6 +14,7 @@
#include "emmc_registers.h"
#include "emmc_def.h"
#include "rcar_private.h"
+#include "cpg_registers.h"
st_mmc_base mmc_drv_obj;
@@ -87,11 +88,11 @@ static EMMC_ERROR_CODE emmc_dev_finalize(void)
SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */
SETR_32(SD_CLK_CTRL, 0x00000000U); /* MMC clock stop */
- dataL = mmio_read_32(CPG_SMSTPCR3);
+ dataL = mmio_read_32(SMSTPCR3);
if ((dataL & CPG_MSTP_MMC) == 0U) {
dataL |= (CPG_MSTP_MMC);
mmio_write_32(CPG_CPGWPR, (~dataL));
- mmio_write_32(CPG_SMSTPCR3, dataL);
+ mmio_write_32(SMSTPCR3, dataL);
}
return result;
@@ -100,7 +101,7 @@ static EMMC_ERROR_CODE emmc_dev_finalize(void)
static EMMC_ERROR_CODE emmc_dev_init(void)
{
/* Enable clock supply to eMMC. */
- mstpcr_write(CPG_SMSTPCR3, CPG_MSTPSR3, CPG_MSTP_MMC);
+ mstpcr_write(SMSTPCR3, CPG_MSTPSR3, CPG_MSTP_MMC);
/* Set SD clock */
mmio_write_32(CPG_CPGWPR, ~((uint32_t) (BIT9 | BIT0))); /* SD phy 200MHz */
diff --git a/drivers/renesas/common/emmc/emmc_registers.h b/drivers/renesas/common/emmc/emmc_registers.h
index 7fae5e4063..67d285d0a0 100644
--- a/drivers/renesas/common/emmc/emmc_registers.h
+++ b/drivers/renesas/common/emmc/emmc_registers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -50,19 +50,6 @@
#define BIT30 (0x40000000U)
#define BIT31 (0x80000000U)
-/* Clock Pulse Generator (CPG) registers */
-#define CPG_BASE (0xE6150000U)
-/* Module stop status register 3 */
-#define CPG_MSTPSR3 (CPG_BASE + 0x0048U)
-/* System module stop control register 3 */
-#define CPG_SMSTPCR3 (CPG_BASE + 0x013CU)
-/* SDHI2 clock frequency control register */
-#define CPG_SD2CKCR (CPG_BASE + 0x0268U)
-/* SDHI3 clock frequency control register */
-#define CPG_SD3CKCR (CPG_BASE + 0x026CU)
-/* CPG Write Protect Register */
-#define CPG_CPGWPR (CPG_BASE + 0x0900U)
-
#if USE_MMC_CH == MMC_CH0
#define CPG_SDxCKCR (CPG_SD2CKCR) /* SDHI2/MMC0 */
#else /* USE_MMC_CH == MMC_CH0 */
diff --git a/drivers/renesas/common/iic_dvfs/iic_dvfs.c b/drivers/renesas/common/iic_dvfs/iic_dvfs.c
index e1c9a5bd4d..bf80697285 100644
--- a/drivers/renesas/common/iic_dvfs/iic_dvfs.c
+++ b/drivers/renesas/common/iic_dvfs/iic_dvfs.c
@@ -517,7 +517,7 @@ RCAR_DVFS_API(send, uint8_t slave, uint8_t reg_addr, uint8_t reg_data)
uint32_t err = 0U;
mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
- mmio_write_8(IIC_DVFS_REG_ICCR, 0U);
+ mmio_write_8(IIC_DVFS_REG_ICCR, 1U);
again:
switch (state) {
case DVFS_START:
@@ -557,7 +557,7 @@ RCAR_DVFS_API(receive, uint8_t slave, uint8_t reg, uint8_t *data)
uint32_t err = 0U;
mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
- mmio_write_8(IIC_DVFS_REG_ICCR, 0U);
+ mmio_write_8(IIC_DVFS_REG_ICCR, 1U);
again:
switch (state) {
case DVFS_START:
diff --git a/drivers/renesas/common/io/io_rcar.c b/drivers/renesas/common/io/io_rcar.c
index c3e8319de4..66662c111f 100644
--- a/drivers/renesas/common/io/io_rcar.c
+++ b/drivers/renesas/common/io/io_rcar.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -84,6 +84,29 @@ typedef struct {
#define RCAR_COUNT_LOAD_BL33 (2U)
#define RCAR_COUNT_LOAD_BL33X (3U)
+#define CHECK_IMAGE_AREA_CNT (7U)
+#define BOOT_BL2_ADDR (0xE6304000U)
+#define BOOT_BL2_LENGTH (0x19000U)
+
+typedef struct {
+ uintptr_t dest;
+ uintptr_t length;
+} addr_loaded_t;
+
+static addr_loaded_t addr_loaded[CHECK_IMAGE_AREA_CNT] = {
+ [0] = {BOOT_BL2_ADDR, BOOT_BL2_LENGTH},
+ [1] = {BL31_BASE, RCAR_TRUSTED_SRAM_SIZE},
+#ifndef SPD_NONE
+ [2] = {BL32_BASE, BL32_SIZE}
+#endif
+};
+
+#ifndef SPD_NONE
+static uint32_t addr_loaded_cnt = 3;
+#else
+static uint32_t addr_loaded_cnt = 2;
+#endif
+
static const plat_rcar_name_offset_t name_offset[] = {
{BL31_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(0, 0, 0)},
@@ -151,6 +174,9 @@ int32_t rcar_get_certificate(const int32_t name, uint32_t *cert)
return -EINVAL;
}
+#define MFISBTSTSR (0xE6260604U)
+#define MFISBTSTSR_BOOT_PARTITION (0x00000010U)
+
static int32_t file_to_offset(const int32_t name, uintptr_t *offset,
uint32_t *cert, uint32_t *no_load,
uintptr_t *partition)
@@ -169,6 +195,9 @@ static int32_t file_to_offset(const int32_t name, uintptr_t *offset,
}
*offset = rcar_image_header[addr];
+
+ if (mmio_read_32(MFISBTSTSR) & MFISBTSTSR_BOOT_PARTITION)
+ *offset += 0x800000;
*cert = RCAR_CERT_SIZE;
*cert *= RCAR_ATTR_GET_CERTOFF(name_offset[i].attr);
*cert += RCAR_SDRAM_certESS;
@@ -238,8 +267,16 @@ void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *dst)
dstl = cert + RCAR_CERT_INFO_DST_OFFSET;
break;
}
+ val = mmio_read_32(size);
+ if (val > (UINT32_MAX / 4)) {
+ ERROR("BL2: %s[%d] uint32 overflow!\n",
+ __func__, __LINE__);
+ *dst = 0;
+ *len = 0;
+ return;
+ }
- *len = mmio_read_32(size) * 4U;
+ *len = val * 4U;
dsth = dstl + 4U;
*dst = ((uintptr_t) mmio_read_32(dsth) << 32) +
((uintptr_t) mmio_read_32(dstl));
@@ -247,7 +284,14 @@ void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *dst)
}
size = cert + RCAR_CERT_INFO_SIZE_OFFSET;
- *len = mmio_read_32(size) * 4U;
+ val = mmio_read_32(size);
+ if (val > (UINT32_MAX / 4)) {
+ ERROR("BL2: %s[%d] uint32 overflow!\n", __func__, __LINE__);
+ *dst = 0;
+ *len = 0;
+ return;
+ }
+ *len = val * 4U;
dstl = cert + RCAR_CERT_INFO_DST_OFFSET;
dsth = dstl + 4U;
*dst = ((uintptr_t) mmio_read_32(dsth) << 32) +
@@ -260,17 +304,18 @@ static int32_t check_load_area(uintptr_t dst, uintptr_t len)
uintptr_t dram_start, dram_end;
uintptr_t prot_start, prot_end;
int32_t result = IO_SUCCESS;
+ int n;
- dram_start = legacy ? DRAM1_BASE : DRAM_40BIT_BASE;
+ dram_start = legacy ? DRAM1_NS_BASE : DRAM_40BIT_BASE;
- dram_end = legacy ? DRAM1_BASE + DRAM1_SIZE :
+ dram_end = legacy ? DRAM1_NS_BASE + DRAM1_NS_SIZE :
DRAM_40BIT_BASE + DRAM_40BIT_SIZE;
prot_start = legacy ? DRAM_PROTECTED_BASE : DRAM_40BIT_PROTECTED_BASE;
prot_end = prot_start + DRAM_PROTECTED_SIZE;
- if (dst < dram_start || dst > dram_end - len) {
+ if (dst < dram_start || len > dram_end || dst > dram_end - len) {
ERROR("BL2: dst address is on the protected area.\n");
result = IO_FAIL;
goto done;
@@ -280,12 +325,54 @@ static int32_t check_load_area(uintptr_t dst, uintptr_t len)
if (dst >= prot_start && dst < prot_end) {
ERROR("BL2: dst address is on the protected area.\n");
result = IO_FAIL;
+ goto done;
}
- if (dst < prot_start && dst > prot_start - len) {
- ERROR("BL2: loaded data is on the protected area.\n");
+ if (len > prot_start || (dst < prot_start && dst > prot_start - len)) {
+ ERROR("BL2: %s[%d] loaded data is on the protected area.\n",
+ __func__, __LINE__);
result = IO_FAIL;
+ goto done;
+ }
+
+ if (addr_loaded_cnt >= CHECK_IMAGE_AREA_CNT) {
+ ERROR("BL2: max loadable non secure images reached\n");
+ result = IO_FAIL;
+ goto done;
}
+
+ addr_loaded[addr_loaded_cnt].dest = dst;
+ addr_loaded[addr_loaded_cnt].length = len;
+ for (n = 0; n < addr_loaded_cnt; n++) {
+ /*
+ * Check if next image invades a previous loaded image
+ *
+ * IMAGE n: area from previous image: dest| IMAGE n |length
+ * IMAGE n+1: area from next image: dst | IMAGE n |len
+ *
+ * 1. check:
+ * | IMAGE n |
+ * | IMAGE n+1 |
+ * 2. check:
+ * | IMAGE n |
+ * | IMAGE n+1 |
+ * 3. check:
+ * | IMAGE n |
+ * | IMAGE n+1 |
+ */
+ if (((dst >= addr_loaded[n].dest) &&
+ (dst <= addr_loaded[n].dest + addr_loaded[n].length)) ||
+ ((dst + len >= addr_loaded[n].dest) &&
+ (dst + len <= addr_loaded[n].dest + addr_loaded[n].length)) ||
+ ((dst <= addr_loaded[n].dest) &&
+ (dst + len >= addr_loaded[n].dest + addr_loaded[n].length))) {
+ ERROR("BL2: next image overlap a previous image area.\n");
+ result = IO_FAIL;
+ goto done;
+ }
+ }
+ addr_loaded_cnt++;
+
done:
if (result == IO_FAIL) {
ERROR("BL2: Out of range : dst=0x%lx len=0x%lx\n", dst, len);
@@ -374,7 +461,7 @@ static int32_t load_bl33x(void)
static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name)
{
- uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {0UL};
+ static uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {0UL};
uintptr_t handle;
ssize_t offset;
uint32_t i;
@@ -417,35 +504,35 @@ static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name)
WARN("Firmware Image Package header failed to seek\n");
goto error;
}
-#if RCAR_BL2_DCACHE == 1
- inv_dcache_range((uint64_t) header, sizeof(header));
-#endif
+
rc = io_read(handle, (uintptr_t) &header, sizeof(header), &cnt);
if (rc != IO_SUCCESS) {
WARN("Firmware Image Package header failed to read\n");
goto error;
}
- rcar_image_number = header[0];
- for (i = 0; i < rcar_image_number + 2; i++) {
- rcar_image_header[i] = header[i * 2 + 1];
- rcar_image_header_prttn[i] = header[i * 2 + 2];
- }
+#if RCAR_BL2_DCACHE == 1
+ inv_dcache_range((uint64_t) header, sizeof(header));
+#endif
+ rcar_image_number = header[0];
if (rcar_image_number == 0 || rcar_image_number > RCAR_MAX_BL3X_IMAGE) {
WARN("Firmware Image Package header check failed.\n");
+ rc = IO_FAIL;
goto error;
}
+ for (i = 0; i < rcar_image_number + 2; i++) {
+ rcar_image_header[i] = header[i * 2 + 1];
+ rcar_image_header_prttn[i] = header[i * 2 + 2];
+ }
+
rc = io_seek(handle, IO_SEEK_SET, offset + RCAR_SECTOR6_CERT_OFFSET);
if (rc != IO_SUCCESS) {
WARN("Firmware Image Package header failed to seek cert\n");
goto error;
}
-#if RCAR_BL2_DCACHE == 1
- inv_dcache_range(RCAR_SDRAM_certESS,
- RCAR_CERT_SIZE * (2 + rcar_image_number));
-#endif
+
rc = io_read(handle, RCAR_SDRAM_certESS,
RCAR_CERT_SIZE * (2 + rcar_image_number), &cnt);
if (rc != IO_SUCCESS) {
@@ -453,6 +540,11 @@ static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name)
goto error;
}
+#if RCAR_BL2_DCACHE == 1
+ inv_dcache_range(RCAR_SDRAM_certESS,
+ RCAR_CERT_SIZE * (2 + rcar_image_number));
+#endif
+
rcar_cert_load = RCAR_CERT_LOAD;
error:
@@ -506,13 +598,6 @@ static int32_t rcar_file_open(io_dev_info_t *info, const uintptr_t file_spec,
rcar_read_certificate((uint64_t) cert, &len, &dst);
- /* Baylibre: HACK */
- if (spec->offset == BL31_IMAGE_ID && len < RCAR_TRUSTED_SRAM_SIZE) {
- WARN("%s,%s\n", "r-car ignoring the BL31 size from certificate",
- "using RCAR_TRUSTED_SRAM_SIZE instead");
- len = RCAR_TRUSTED_SRAM_SIZE;
- }
-
current_file.partition = partition;
current_file.no_load = noload;
current_file.offset = offset;
diff --git a/drivers/renesas/common/pfc_regs.h b/drivers/renesas/common/pfc_regs.h
index 418773366c..36084f5502 100644
--- a/drivers/renesas/common/pfc_regs.h
+++ b/drivers/renesas/common/pfc_regs.h
@@ -146,10 +146,10 @@
#define GPIO_OUTDTL7 (GPIO_BASE + 0x5848U)
#define GPIO_BOTHEDGE7 (GPIO_BASE + 0x584CU)
-/* Pin functon base address */
+/* Pin function base address */
#define PFC_BASE (0xE6060000U)
-/* Pin functon registers */
+/* Pin function registers */
#define PFC_PMMR (PFC_BASE + 0x0000U)
#define PFC_GPSR0 (PFC_BASE + 0x0100U)
#define PFC_GPSR1 (PFC_BASE + 0x0104U)
diff --git a/drivers/renesas/common/pwrc/pwrc.c b/drivers/renesas/common/pwrc/pwrc.c
index c0f015f04b..b60ccab276 100644
--- a/drivers/renesas/common/pwrc/pwrc.c
+++ b/drivers/renesas/common/pwrc/pwrc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -20,6 +20,7 @@
#include "pwrc.h"
#include "rcar_def.h"
#include "rcar_private.h"
+#include "cpg_registers.h"
/*
* Someday there will be a generic power controller api. At the moment each
@@ -43,6 +44,7 @@ RCAR_INSTANTIATE_LOCK
#define CPU_PWR_OFF (0x00000003U)
#define RCAR_PSTR_MASK (0x00000003U)
#define ST_ALL_STANDBY (0x00003333U)
+#define SYSCEXTMASK_EXTMSK0 (0x00000001U)
/* Suspend to ram */
#define DBSC4_REG_BASE (0xE6790000U)
#define DBSC4_REG_DBSYSCNT0 (DBSC4_REG_BASE + 0x0100U)
@@ -154,7 +156,7 @@ IMPORT_SYM(unsigned long, __system_ram_end__, SYSTEM_RAM_END);
IMPORT_SYM(unsigned long, __SRAM_COPY_START__, SRAM_COPY_START);
#endif
-uint32_t rcar_pwrc_status(uint64_t mpidr)
+uint32_t rcar_pwrc_status(u_register_t mpidr)
{
uint32_t ret = 0;
uint64_t cm, cpu;
@@ -186,10 +188,12 @@ done:
return ret;
}
-static void scu_power_up(uint64_t mpidr)
+static void scu_power_up(u_register_t mpidr)
{
uintptr_t reg_pwrsr, reg_cpumcr, reg_pwron, reg_pwrer;
uint32_t c, sysc_reg_bit;
+ uint32_t lsi_product;
+ uint32_t lsi_cut;
c = rcar_pwrc_get_mpidr_cluster(mpidr);
reg_cpumcr = IS_CA57(c) ? RCAR_CA57CPUCMCR : RCAR_CA53CPUCMCR;
@@ -204,6 +208,17 @@ static void scu_power_up(uint64_t mpidr)
if (mmio_read_32(reg_cpumcr) != 0)
mmio_write_32(reg_cpumcr, 0);
+ lsi_product = mmio_read_32((uintptr_t)RCAR_PRR);
+ lsi_cut = lsi_product & PRR_CUT_MASK;
+ lsi_product &= PRR_PRODUCT_MASK;
+
+ if ((lsi_product == PRR_PRODUCT_M3 && lsi_cut >= PRR_PRODUCT_30) ||
+ lsi_product == PRR_PRODUCT_H3 ||
+ lsi_product == PRR_PRODUCT_M3N ||
+ lsi_product == PRR_PRODUCT_E3) {
+ mmio_setbits_32(RCAR_SYSCEXTMASK, SYSCEXTMASK_EXTMSK0);
+ }
+
mmio_setbits_32(RCAR_SYSCIER, sysc_reg_bit);
mmio_setbits_32(RCAR_SYSCIMR, sysc_reg_bit);
@@ -215,12 +230,20 @@ static void scu_power_up(uint64_t mpidr)
while ((mmio_read_32(RCAR_SYSCISR) & sysc_reg_bit) == 0)
;
- mmio_write_32(RCAR_SYSCISR, sysc_reg_bit);
+ mmio_write_32(RCAR_SYSCISCR, sysc_reg_bit);
+
+ if ((lsi_product == PRR_PRODUCT_M3 && lsi_cut >= PRR_PRODUCT_30) ||
+ lsi_product == PRR_PRODUCT_H3 ||
+ lsi_product == PRR_PRODUCT_M3N ||
+ lsi_product == PRR_PRODUCT_E3) {
+ mmio_clrbits_32(RCAR_SYSCEXTMASK, SYSCEXTMASK_EXTMSK0);
+ }
+
while ((mmio_read_32(reg_pwrsr) & STATUS_PWRUP) == 0)
;
}
-void rcar_pwrc_cpuon(uint64_t mpidr)
+void rcar_pwrc_cpuon(u_register_t mpidr)
{
uint32_t res_data, on_data;
uintptr_t res_reg, on_reg;
@@ -238,14 +261,14 @@ void rcar_pwrc_cpuon(uint64_t mpidr)
scu_power_up(mpidr);
cpu = mpidr & MPIDR_CPU_MASK;
on_data = 1 << cpu;
- mmio_write_32(RCAR_CPGWPR, ~on_data);
+ mmio_write_32(CPG_CPGWPR, ~on_data);
mmio_write_32(on_reg, on_data);
mmio_write_32(res_reg, res_data & (~(1 << (3 - cpu))));
rcar_lock_release();
}
-void rcar_pwrc_cpuoff(uint64_t mpidr)
+void rcar_pwrc_cpuoff(u_register_t mpidr)
{
uint32_t c;
uintptr_t reg;
@@ -260,13 +283,13 @@ void rcar_pwrc_cpuoff(uint64_t mpidr)
if (read_mpidr_el1() != mpidr)
panic();
- mmio_write_32(RCAR_CPGWPR, ~CPU_PWR_OFF);
+ mmio_write_32(CPG_CPGWPR, ~CPU_PWR_OFF);
mmio_write_32(reg + cpu * 0x0010, CPU_PWR_OFF);
rcar_lock_release();
}
-void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr)
+void rcar_pwrc_enable_interrupt_wakeup(u_register_t mpidr)
{
uint32_t c, shift_irq, shift_fiq;
uintptr_t reg;
@@ -281,12 +304,12 @@ void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr)
shift_irq = WUP_IRQ_SHIFT + cpu;
shift_fiq = WUP_FIQ_SHIFT + cpu;
- mmio_write_32(reg, ~((uint32_t) 1 << shift_irq) &
- ~((uint32_t) 1 << shift_fiq));
+ mmio_clrbits_32(reg, ((uint32_t) 1 << shift_irq) |
+ ((uint32_t) 1 << shift_fiq));
rcar_lock_release();
}
-void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr)
+void rcar_pwrc_disable_interrupt_wakeup(u_register_t mpidr)
{
uint32_t c, shift_irq, shift_fiq;
uintptr_t reg;
@@ -301,12 +324,35 @@ void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr)
shift_irq = WUP_IRQ_SHIFT + cpu;
shift_fiq = WUP_FIQ_SHIFT + cpu;
- mmio_write_32(reg, ((uint32_t) 1 << shift_irq) |
+ mmio_setbits_32(reg, ((uint32_t) 1 << shift_irq) |
((uint32_t) 1 << shift_fiq));
rcar_lock_release();
}
-void rcar_pwrc_clusteroff(uint64_t mpidr)
+void rcar_pwrc_all_disable_interrupt_wakeup(void)
+{
+ uint32_t cpu_num;
+ u_register_t cl, cpu, mpidr;
+
+ const uint32_t cluster[PLATFORM_CLUSTER_COUNT] = {
+ RCAR_CLUSTER_CA57,
+ RCAR_CLUSTER_CA53
+ };
+
+ for (cl = 0; cl < PLATFORM_CLUSTER_COUNT; cl++) {
+ cpu_num = rcar_pwrc_get_cpu_num(cluster[cl]);
+ for (cpu = 0; cpu < cpu_num; cpu++) {
+ mpidr = ((cl << MPIDR_AFFINITY_BITS) | cpu);
+ if (mpidr == rcar_boot_mpidr) {
+ rcar_pwrc_enable_interrupt_wakeup(mpidr);
+ } else {
+ rcar_pwrc_disable_interrupt_wakeup(mpidr);
+ }
+ }
+ }
+}
+
+void rcar_pwrc_clusteroff(u_register_t mpidr)
{
uint32_t c, product, cut, reg;
uintptr_t dst;
@@ -753,14 +799,14 @@ void rcar_pwrc_code_copy_to_system_ram(void)
memcpy((void *)sram.base, code.base, code.len);
flush_dcache_range((uint64_t) sram.base, code.len);
+ attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
+ ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
+ assert(ret == 0);
+
/* Invalidate instruction cache */
plat_invalidate_icache();
dsb();
isb();
-
- attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
- ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
- assert(ret == 0);
}
uint32_t rcar_pwrc_get_cluster(void)
@@ -778,7 +824,7 @@ uint32_t rcar_pwrc_get_cluster(void)
return RCAR_CLUSTER_A53A57;
}
-uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr)
+uint32_t rcar_pwrc_get_mpidr_cluster(u_register_t mpidr)
{
uint32_t c = rcar_pwrc_get_cluster();
@@ -831,7 +877,7 @@ done:
}
#endif
-int32_t rcar_pwrc_cpu_on_check(uint64_t mpidr)
+int32_t rcar_pwrc_cpu_on_check(u_register_t mpidr)
{
uint64_t i;
uint64_t j;
diff --git a/drivers/renesas/common/pwrc/pwrc.h b/drivers/renesas/common/pwrc/pwrc.h
index f73099b0b5..eefa62ff26 100644
--- a/drivers/renesas/common/pwrc/pwrc.h
+++ b/drivers/renesas/common/pwrc/pwrc.h
@@ -38,19 +38,22 @@
#define RCAR_CLUSTER_CA53 (1U)
#define RCAR_CLUSTER_CA57 (2U)
+extern u_register_t rcar_boot_mpidr;
+
#ifndef __ASSEMBLER__
-void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr);
-void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr);
-void rcar_pwrc_clusteroff(uint64_t mpidr);
-void rcar_pwrc_cpuoff(uint64_t mpidr);
-void rcar_pwrc_cpuon(uint64_t mpidr);
-int32_t rcar_pwrc_cpu_on_check(uint64_t mpidr);
+void rcar_pwrc_disable_interrupt_wakeup(u_register_t mpidr);
+void rcar_pwrc_enable_interrupt_wakeup(u_register_t mpidr);
+void rcar_pwrc_all_disable_interrupt_wakeup(void);
+void rcar_pwrc_clusteroff(u_register_t mpidr);
+void rcar_pwrc_cpuoff(u_register_t mpidr);
+void rcar_pwrc_cpuon(u_register_t mpidr);
+int32_t rcar_pwrc_cpu_on_check(u_register_t mpidr);
void rcar_pwrc_setup(void);
-uint32_t rcar_pwrc_get_cpu_wkr(uint64_t mpidr);
-uint32_t rcar_pwrc_status(uint64_t mpidr);
+uint32_t rcar_pwrc_get_cpu_wkr(u_register_t mpidr);
+uint32_t rcar_pwrc_status(u_register_t mpidr);
uint32_t rcar_pwrc_get_cluster(void);
-uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr);
+uint32_t rcar_pwrc_get_mpidr_cluster(u_register_t mpidr);
uint32_t rcar_pwrc_get_cpu_num(uint32_t cluster_type);
void rcar_pwrc_restore_timer_state(void);
void plat_secondary_reset(void);
diff --git a/drivers/renesas/common/rom/rom_api.c b/drivers/renesas/common/rom/rom_api.c
index fda28150e9..4eede17ce9 100644
--- a/drivers/renesas/common/rom/rom_api.c
+++ b/drivers/renesas/common/rom/rom_api.c
@@ -11,7 +11,7 @@
#include "rcar_def.h"
#include "rom_api.h"
-typedef uint32_t(*rom_secure_boot_api_f) (uint32_t *key, uint32_t *cert,
+typedef uint32_t(*rom_secure_boot_api_f) (uint32_t key, uint32_t cert,
rom_read_flash_f pFuncReadFlash);
typedef uint32_t(*rom_get_lcs_api_f) (uint32_t *lcs);
@@ -68,7 +68,7 @@ static uint32_t get_table_index(void)
return index;
}
-uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert,
+uint32_t rcar_rom_secure_boot_api(uint32_t key, uint32_t cert,
rom_read_flash_f read_flash)
{
static const uintptr_t rom_api_table[API_TABLE_MAX] = {
diff --git a/drivers/renesas/common/rom/rom_api.h b/drivers/renesas/common/rom/rom_api.h
index 1d5b03d7f5..4b1008032e 100644
--- a/drivers/renesas/common/rom/rom_api.h
+++ b/drivers/renesas/common/rom/rom_api.h
@@ -24,7 +24,7 @@
#define LCS_FA (0x7U)
typedef uint32_t(*rom_read_flash_f) (uint64_t src, uint8_t *dst, uint32_t len);
-uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert,
+uint32_t rcar_rom_secure_boot_api(uint32_t key, uint32_t cert,
rom_read_flash_f f);
uint32_t rcar_rom_get_lcs(uint32_t *lcs);
diff --git a/drivers/renesas/common/scif/scif.S b/drivers/renesas/common/scif/scif.S
index beb8dd8383..72b5b4bea0 100644
--- a/drivers/renesas/common/scif/scif.S
+++ b/drivers/renesas/common/scif/scif.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -79,7 +79,7 @@
SCSMR_STOP_1 + \
SCSMR_CKS_DIV1)
#define SCBRR_115200BPS (17)
-#define SCBRR_115200BPSON (16)
+#define SCBRR_115200BPS_D3_SSCG (16)
#define SCBRR_115200BPS_E3_SSCG (15)
#define SCBRR_230400BPS (8)
@@ -216,26 +216,38 @@ func console_rcar_init
and w1, w1, #PRR_PRODUCT_MASK
mov w2, #PRR_PRODUCT_D3
cmp w1, w2
- beq 4f
+ beq 5f
and w1, w1, #PRR_PRODUCT_MASK
mov w2, #PRR_PRODUCT_E3
cmp w1, w2
- bne 5f
+ bne 4f
+ /* When SSCG(MD12) on (E3) */
ldr x1, =RST_MODEMR
ldr w1, [x1]
and w1, w1, #MODEMR_MD12
mov w2, #MODEMR_MD12
cmp w1, w2
- bne 5f
+ bne 4f
+ /* When SSCG(MD12) on (E3) */
mov w1, #SCBRR_115200BPS_E3_SSCG
b 2f
5:
- mov w1, #SCBRR_115200BPS
+ /* In case of D3 */
+ ldr x1, =RST_MODEMR
+ ldr w1, [x1]
+ and w1, w1, #MODEMR_MD12
+ mov w2, #MODEMR_MD12
+ cmp w1, w2
+ bne 4f
+
+ /* When SSCG(MD12) on (D3) */
+ mov w1, #SCBRR_115200BPS_D3_SSCG
b 2f
4:
- mov w1, #SCBRR_115200BPSON
+ /* In case of H3/M3/M3N or when SSCG(MD12) is off in E3/D3 */
+ mov w1, #SCBRR_115200BPS
b 2f
3:
mov w1, #SCBRR_230400BPS
diff --git a/drivers/renesas/common/watchdog/swdt.c b/drivers/renesas/common/watchdog/swdt.c
index 1a351ca175..29ef6f4309 100644
--- a/drivers/renesas/common/watchdog/swdt.c
+++ b/drivers/renesas/common/watchdog/swdt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -78,7 +78,7 @@ static void swdt_disable(void)
void rcar_swdt_init(void)
{
uint32_t rmsk, sr;
-#if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RZ_G2E)
+#if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RZ_G2E)
uint32_t reg, val, product_cut, chk_data;
reg = mmio_read_32(RCAR_PRR);
@@ -96,6 +96,8 @@ void rcar_swdt_init(void)
#if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RZ_G2E)
mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k);
+#elif (RCAR_LSI == RCAR_D3)
+ mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_8p13k);
#else
val = WTCNT_UPPER_BYTE;
diff --git a/drivers/renesas/rcar/board/board.c b/drivers/renesas/rcar/board/board.c
index cd194ff9f7..dbbaed659e 100644
--- a/drivers/renesas/rcar/board/board.c
+++ b/drivers/renesas/rcar/board/board.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights
+ * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights
* reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -30,9 +30,9 @@
#define BOARD_CODE_SHIFT (0x03)
#define BOARD_ID_UNKNOWN (0xFF)
-#define SXS_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SXS_ID { 0x10U, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
#define SX_ID { 0x10U, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
-#define SKP_ID { 0x10U, 0x10U, 0x20U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SKP_ID { 0x10U, 0x10U, 0x20U, 0x21U, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
#define SK_ID { 0x10U, 0x30U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
#define EB4_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
#define EB_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
diff --git a/drivers/renesas/rcar/board/board.h b/drivers/renesas/rcar/board/board.h
index 51a8e306fb..23469114f3 100644
--- a/drivers/renesas/rcar/board/board.h
+++ b/drivers/renesas/rcar/board/board.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights
+ * Copyright (c) 2015-2023, Renesas Electronics Corporation. All rights
* reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -11,13 +11,13 @@
#define BOARD_SALVATOR_X (0x00)
#define BOARD_KRIEK (0x01)
#define BOARD_STARTER_KIT (0x02)
+#define BOARD_EAGLE (0x03)
#define BOARD_SALVATOR_XS (0x04)
+#define BOARD_DRAAK (0x07)
#define BOARD_EBISU (0x08)
#define BOARD_STARTER_KIT_PRE (0x0B)
-#define BOARD_EBISU_4D (0x0DU)
-#define BOARD_DRAAK (0x0EU)
-#define BOARD_EAGLE (0x0FU)
-#define BOARD_UNKNOWN (BOARD_EAGLE + 1U)
+#define BOARD_EBISU_4D (0x0D)
+#define BOARD_UNKNOWN (BOARD_EBISU_4D + 1U)
#define BOARD_REV_UNKNOWN (0xFF)
diff --git a/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
index 6063758074..5de4f1f655 100644
--- a/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
+++ b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
@@ -12,7 +12,7 @@
#include "rcar_private.h"
#include "../pfc_regs.h"
-/* Pin functon bit */
+/* Pin function bit */
#define GPSR0_DU_EXODDF_DU_ODDF_DISP_CDE BIT(21)
#define GPSR0_DU_EXVSYNC_DU_VSYNC BIT(20)
#define GPSR0_DU_EXHSYNC_DU_HSYNC BIT(19)
diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c
index f938f563fc..55a8832c3e 100644
--- a/drivers/rpi3/gpio/rpi3_gpio.c
+++ b/drivers/rpi3/gpio/rpi3_gpio.c
@@ -10,6 +10,7 @@
#include <lib/mmio.h>
#include <drivers/delay_timer.h>
#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <platform_def.h>
static uintptr_t reg_base;
diff --git a/drivers/rpi3/rng/rpi3_rng.c b/drivers/rpi3/rng/rpi3_rng.c
index b6bf0052a9..16733e15c4 100644
--- a/drivers/rpi3/rng/rpi3_rng.c
+++ b/drivers/rpi3/rng/rpi3_rng.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,6 +11,19 @@
#include <rpi_hw.h>
+#define RPI3_RNG_CTRL_OFFSET ULL(0x00000000)
+#define RPI3_RNG_STATUS_OFFSET ULL(0x00000004)
+#define RPI3_RNG_DATA_OFFSET ULL(0x00000008)
+#define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010)
+/* Enable/disable RNG */
+#define RPI3_RNG_CTRL_ENABLE U(0x1)
+#define RPI3_RNG_CTRL_DISABLE U(0x0)
+/* Number of currently available words */
+#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24)
+#define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF)
+/* Value to mask interrupts caused by the RNG */
+#define RPI3_RNG_INT_MASK_DISABLE U(0x1)
+
/* Initial amount of values to discard */
#define RNG_WARMUP_COUNT U(0x40000)
diff --git a/drivers/rpi3/sdhost/rpi3_sdhost.c b/drivers/rpi3/sdhost/rpi3_sdhost.c
index c4b6fcafec..90c850947b 100644
--- a/drivers/rpi3/sdhost/rpi3_sdhost.c
+++ b/drivers/rpi3/sdhost/rpi3_sdhost.c
@@ -245,13 +245,12 @@ static void rpi3_sdhost_reset(void)
static void rpi3_sdhost_initialize(void)
{
- uintptr_t reg_base = rpi3_sdhost_params.reg_base;
-
assert((rpi3_sdhost_params.reg_base & MMC_BLOCK_MASK) == 0);
rpi3_sdhost_reset();
- mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_PREFERVAL);
+ rpi3_sdhost_set_ios(rpi3_sdhost_params.clk_rate_initial,
+ rpi3_sdhost_params.bus_width);
udelay(300);
}
diff --git a/drivers/scmi-msg/base.c b/drivers/scmi-msg/base.c
index 2d7203451f..52502a5a56 100644
--- a/drivers/scmi-msg/base.c
+++ b/drivers/scmi-msg/base.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-2020, Linaro Limited
+ * Copyright (c) 2019-2022, Linaro Limited
*/
#include <assert.h>
#include <string.h>
@@ -131,15 +131,12 @@ static unsigned int count_protocols_in_list(const uint8_t *protocol_list)
return count;
}
-#define MAX_PROTOCOL_IN_LIST 8U
-
static void discover_list_protocols(struct scmi_msg *msg)
{
const struct scmi_base_discover_list_protocols_a2p *a2p = NULL;
struct scmi_base_discover_list_protocols_p2a p2a = {
.status = SCMI_SUCCESS,
};
- uint8_t outargs[sizeof(p2a) + MAX_PROTOCOL_IN_LIST] = { 0U };
const uint8_t *list = NULL;
unsigned int count = 0U;
@@ -148,24 +145,23 @@ static void discover_list_protocols(struct scmi_msg *msg)
return;
}
- assert(msg->out_size > sizeof(outargs));
-
a2p = (void *)msg->in;
list = plat_scmi_protocol_list(msg->agent_id);
count = count_protocols_in_list(list);
+
if (count > a2p->skip) {
- count = MIN(count - a2p->skip, MAX_PROTOCOL_IN_LIST);
+ count = MIN((uint32_t)(count - a2p->skip),
+ (uint32_t)(msg->out_size - sizeof(p2a)));
} else {
count = 0U;
}
p2a.num_protocols = count;
- memcpy(outargs, &p2a, sizeof(p2a));
- memcpy(outargs + sizeof(p2a), list + a2p->skip, count);
-
- scmi_write_response(msg, outargs, sizeof(outargs));
+ memcpy(msg->out, &p2a, sizeof(p2a));
+ memcpy(msg->out + sizeof(p2a), list + a2p->skip, count);
+ msg->out_size_out = sizeof(p2a) + round_up(count, sizeof(uint32_t));
}
static const scmi_msg_handler_t scmi_base_handler_table[] = {
diff --git a/drivers/scmi-msg/clock.c b/drivers/scmi-msg/clock.c
index e96cede6ed..5aaf68c82e 100644
--- a/drivers/scmi-msg/clock.c
+++ b/drivers/scmi-msg/clock.c
@@ -37,7 +37,8 @@ const char *plat_scmi_clock_get_name(unsigned int agent_id __unused,
int32_t plat_scmi_clock_rates_array(unsigned int agent_id __unused,
unsigned int scmi_id __unused,
unsigned long *rates __unused,
- size_t *nb_elts __unused)
+ size_t *nb_elts __unused,
+ uint32_t start_idx __unused)
{
return SCMI_NOT_SUPPORTED;
}
@@ -298,7 +299,7 @@ static void scmi_clock_describe_rates(struct scmi_msg *msg)
/* Platform may support array rate description */
status = plat_scmi_clock_rates_array(msg->agent_id, clock_id, NULL,
- &nb_rates);
+ &nb_rates, 0);
if (status == SCMI_SUCCESS) {
/* Currently 12 cells mex, so it's affordable for the stack */
unsigned long plat_rates[RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE];
@@ -307,7 +308,8 @@ static void scmi_clock_describe_rates(struct scmi_msg *msg)
size_t rem_nb = nb_rates - in_args->rate_index - ret_nb;
status = plat_scmi_clock_rates_array(msg->agent_id, clock_id,
- plat_rates, &ret_nb);
+ plat_rates, &ret_nb,
+ in_args->rate_index);
if (status == SCMI_SUCCESS) {
write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
plat_rates, ret_nb);
@@ -344,7 +346,7 @@ static void scmi_clock_describe_rates(struct scmi_msg *msg)
scmi_status_response(msg, status);
} else {
/*
- * Message payload is already writen to msg->out, and
+ * Message payload is already written to msg->out, and
* msg->out_size_out updated.
*/
}
@@ -361,7 +363,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] != NULL);
diff --git a/drivers/scmi-msg/common.h b/drivers/scmi-msg/common.h
index ef5953b3d0..6b186d07d2 100644
--- a/drivers/scmi-msg/common.h
+++ b/drivers/scmi-msg/common.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
- * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2020, Linaro Limited
*/
#ifndef SCMI_MSG_COMMON_H
@@ -13,7 +13,9 @@
#include "base.h"
#include "clock.h"
+#include "power_domain.h"
#include "reset_domain.h"
+#include "sensor.h"
#define SCMI_VERSION 0x20000U
#define SCMI_IMPL_VERSION 0U
@@ -111,6 +113,20 @@ scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg);
scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg);
/*
+ * scmi_msg_get_pd_handler - Return a handler for a power domain message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_sensor_handler - Return a handler for a sensor message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg);
+
+/*
* Process Read, process and write response for input SCMI message
*
* @msg: SCMI message context
diff --git a/drivers/scmi-msg/entry.c b/drivers/scmi-msg/entry.c
index ea3efa24b9..5ac68e1e6b 100644
--- a/drivers/scmi-msg/entry.c
+++ b/drivers/scmi-msg/entry.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
- * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2020, Linaro Limited
*/
@@ -11,6 +11,37 @@
#include "common.h"
+#pragma weak scmi_msg_get_clock_handler
+#pragma weak scmi_msg_get_rstd_handler
+#pragma weak scmi_msg_get_pd_handler
+#pragma weak scmi_msg_get_voltage_handler
+#pragma weak scmi_msg_get_sensor_handler
+
+scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_voltage_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg __unused)
+{
+ return NULL;
+}
+
void scmi_status_response(struct scmi_msg *msg, int32_t status)
{
assert(msg->out && msg->out_size >= sizeof(int32_t));
@@ -47,6 +78,12 @@ void scmi_process_message(struct scmi_msg *msg)
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
handler = scmi_msg_get_rstd_handler(msg);
break;
+ case SCMI_PROTOCOL_ID_POWER_DOMAIN:
+ handler = scmi_msg_get_pd_handler(msg);
+ break;
+ case SCMI_PROTOCOL_ID_SENSOR:
+ handler = scmi_msg_get_sensor_handler(msg);
+ break;
default:
break;
}
@@ -56,7 +93,7 @@ void scmi_process_message(struct scmi_msg *msg)
return;
}
- ERROR("Agent %u Protocol 0x%x Message 0x%x: not supported",
+ ERROR("Agent %u Protocol 0x%x Message 0x%x: not supported\n",
msg->agent_id, msg->protocol_id, msg->message_id);
scmi_status_response(msg, SCMI_NOT_SUPPORTED);
diff --git a/drivers/scmi-msg/power_domain.c b/drivers/scmi-msg/power_domain.c
new file mode 100644
index 0000000000..87c41dd8e1
--- /dev/null
+++ b/drivers/scmi-msg/power_domain.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <cdefs.h>
+#include <string.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+#pragma weak plat_scmi_pd_count
+#pragma weak plat_scmi_pd_get_name
+#pragma weak plat_scmi_pd_get_state
+#pragma weak plat_scmi_pd_set_state
+#pragma weak plat_scmi_pd_statistics
+#pragma weak plat_scmi_pd_get_attributes
+
+static bool message_id_is_supported(unsigned int message_id);
+
+size_t plat_scmi_pd_count(unsigned int agent_id __unused)
+{
+ return 0U;
+}
+
+const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
+ unsigned int pd_id __unused)
+{
+ return NULL;
+}
+
+unsigned int plat_scmi_pd_statistics(unsigned int agent_id __unused,
+ unsigned long *pd_id __unused)
+{
+ return 0U;
+}
+
+unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id __unused,
+ unsigned int pd_id __unused)
+{
+ return 0U;
+}
+
+unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
+ unsigned int pd_id __unused)
+{
+ return 0U;
+}
+
+int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
+ unsigned int flags __unused,
+ unsigned int pd_id __unused,
+ unsigned int state __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_PD,
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ unsigned long addr = 0UL;
+ unsigned int len;
+
+ struct scmi_protocol_attributes_p2a_pd return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ return_values.attributes = plat_scmi_pd_count(msg->agent_id);
+ len = plat_scmi_pd_statistics(msg->agent_id, &addr);
+ if (len != 0U) {
+ return_values.statistics_addr_low = (unsigned int)addr;
+ return_values.statistics_addr_high = (uint32_t)(addr >> 32);
+ return_values.statistics_len = len;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_pd_attributes(struct scmi_msg *msg)
+{
+ const struct scmi_pd_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_pd_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ const char *name = NULL;
+ unsigned int pd_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
+
+ if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ name = plat_scmi_pd_get_name(msg->agent_id, pd_id);
+ if (name == NULL) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.pd_name, name);
+
+ return_values.attributes = plat_scmi_pd_get_attributes(msg->agent_id, pd_id);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_pd_state_get(struct scmi_msg *msg)
+{
+ const struct scmi_pd_state_get_a2p *in_args = (void *)msg->in;
+ unsigned int state = 0U;
+ struct scmi_pd_state_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int pd_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
+
+ if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ state = plat_scmi_pd_get_state(msg->agent_id, pd_id);
+
+ return_values.power_state = state;
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_pd_state_set(struct scmi_msg *msg)
+{
+ const struct scmi_pd_state_set_a2p *in_args = (void *)msg->in;
+ unsigned int flags = 0U;
+ int32_t status = 0;
+ unsigned int pd_id = 0U;
+ unsigned int state = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ pd_id = SPECULATION_SAFE_VALUE(in_args->pd_id);
+
+ if (pd_id >= plat_scmi_pd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ flags = SPECULATION_SAFE_VALUE(in_args->flags);
+ state = SPECULATION_SAFE_VALUE(in_args->power_state);
+
+ status = plat_scmi_pd_set_state(msg->agent_id, flags, pd_id, state);
+
+ scmi_status_response(msg, status);
+}
+
+static const scmi_msg_handler_t scmi_pd_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_PD_ATTRIBUTES] = scmi_pd_attributes,
+ [SCMI_PD_STATE_SET] = scmi_pd_state_set,
+ [SCMI_PD_STATE_GET] = scmi_pd_state_get,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_pd_handler_table)) &&
+ (scmi_pd_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg)
+{
+ const size_t array_size = ARRAY_SIZE(scmi_pd_handler_table);
+ unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+ if (message_id >= array_size) {
+ VERBOSE("pd handle not found %u", msg->message_id);
+ return NULL;
+ }
+
+ return scmi_pd_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/power_domain.h b/drivers/scmi-msg/power_domain.h
new file mode 100644
index 0000000000..48551fd889
--- /dev/null
+++ b/drivers/scmi-msg/power_domain.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2021 NXP
+ */
+
+#ifndef SCMI_MSG_PD_H
+#define SCMI_MSG_PD_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_PD 0x21000U
+
+/*
+ * Identifiers of the SCMI POWER DOMAIN Protocol commands
+ */
+enum scmi_pd_command_id {
+ SCMI_PD_ATTRIBUTES = 0x003,
+ SCMI_PD_STATE_SET = 0x004,
+ SCMI_PD_STATE_GET = 0x005,
+};
+
+/* Protocol attributes */
+struct scmi_pd_attributes_a2p {
+ uint32_t pd_id;
+};
+
+struct scmi_protocol_attributes_p2a_pd {
+ int32_t status;
+ uint32_t attributes;
+ uint32_t statistics_addr_low;
+ uint32_t statistics_addr_high;
+ uint32_t statistics_len;
+};
+
+#define SCMI_PD_NAME_LENGTH_MAX 16U
+
+struct scmi_pd_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+ char pd_name[SCMI_PD_NAME_LENGTH_MAX];
+};
+
+/*
+ * Power Domain State Get
+ */
+
+struct scmi_pd_state_get_a2p {
+ uint32_t pd_id;
+};
+
+struct scmi_pd_state_get_p2a {
+ int32_t status;
+ uint32_t power_state;
+};
+
+/*
+ * Power domain State Set
+ */
+
+struct scmi_pd_state_set_a2p {
+ uint32_t flags;
+ uint32_t pd_id;
+ uint32_t power_state;
+};
+
+struct scmi_pd_state_set_p2a {
+ int32_t status;
+};
+
+#endif /* SCMI_MSG_PD_H */
diff --git a/drivers/scmi-msg/sensor.c b/drivers/scmi-msg/sensor.c
new file mode 100644
index 0000000000..a47018d887
--- /dev/null
+++ b/drivers/scmi-msg/sensor.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2021-2024 NXP
+ */
+
+#include <cdefs.h>
+#include <string.h>
+
+#include "common.h"
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+
+static bool message_id_is_supported(size_t message_id);
+
+uint16_t plat_scmi_sensor_count(unsigned int agent_id __unused)
+{
+ if (sensor_ops.sensor_count != NULL) {
+ return sensor_ops.sensor_count(agent_id);
+ }
+
+ return 0U;
+}
+
+uint8_t plat_scmi_sensor_max_requests(unsigned int agent_id __unused)
+{
+ if (sensor_ops.sensor_max_request != NULL) {
+ return sensor_ops.sensor_max_request(agent_id);
+ }
+
+ return 0U;
+}
+
+uint32_t plat_scmi_sensor_reg(unsigned int agent_id __unused,
+ unsigned int *addr)
+{
+ if (sensor_ops.get_sensor_req != NULL) {
+ return sensor_ops.get_sensor_req(agent_id, addr);
+ }
+
+ return 0U;
+}
+
+int32_t plat_scmi_sensor_reading_get(uint32_t agent_id __unused,
+ uint16_t sensor_id __unused,
+ uint32_t *val __unused)
+{
+ if (sensor_ops.sensor_reading_get != NULL) {
+ return sensor_ops.sensor_reading_get(agent_id, sensor_id, val);
+ }
+
+ return 0;
+}
+
+uint32_t plat_scmi_sensor_description_get(uint32_t agent_id __unused,
+ uint16_t desc_index __unused,
+ struct scmi_sensor_desc *desc __unused)
+{
+ if (sensor_ops.sensor_description_get != NULL) {
+ return sensor_ops.sensor_description_get(agent_id, desc_index, desc);
+ }
+
+ return 0U;
+}
+
+uint32_t plat_scmi_sensor_update_interval(uint32_t agent_id __unused,
+ uint16_t sensor_id __unused)
+{
+ if (sensor_ops.sensor_update_interval != NULL) {
+ return sensor_ops.sensor_update_interval(agent_id, sensor_id);
+ }
+
+ return 0U;
+}
+
+uint32_t plat_scmi_sensor_state(uint32_t agent_id __unused,
+ uint16_t sensor_id __unused)
+{
+ if (sensor_ops.sensor_state != NULL) {
+ return sensor_ops.sensor_state(agent_id, sensor_id);
+ }
+
+ return 0U;
+}
+
+uint32_t plat_scmi_sensor_timestamped(uint32_t agent_id __unused,
+ uint16_t sensor_id __unused)
+{
+ if (sensor_ops.sensor_timestamped != NULL) {
+ return sensor_ops.sensor_timestamped(agent_id, sensor_id);
+ }
+
+ return 0U;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_SENSOR,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ unsigned int addr[2];
+ unsigned int len;
+
+ struct scmi_protocol_attributes_p2a_sensor return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ return_values.num_sensors = plat_scmi_sensor_count(msg->agent_id);
+ return_values.max_reqs = plat_scmi_sensor_max_requests(msg->agent_id);
+ len = plat_scmi_sensor_reg(msg->agent_id, addr);
+ if (len != 0U) {
+ return_values.sensor_reg_low = addr[0];
+ return_values.sensor_reg_high = addr[1];
+ return_values.sensor_reg_len = len;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_sensor_description_get(struct scmi_msg *msg)
+{
+ const struct scmi_sensor_description_get_a2p *in_args = (void *)msg->in;
+ struct scmi_sensor_description_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ struct scmi_sensor_desc desc;
+ unsigned int desc_index = 0U;
+ unsigned int num_sensor_flags;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ desc_index = SPECULATION_SAFE_VALUE(in_args->desc_index);
+
+ num_sensor_flags = plat_scmi_sensor_description_get(msg->agent_id, desc_index,
+ &desc);
+ return_values.num_sensor_flags = num_sensor_flags;
+
+ memcpy(msg->out, &return_values, sizeof(return_values));
+ memcpy(msg->out + sizeof(return_values), &desc, sizeof(desc));
+ msg->out_size_out = sizeof(return_values) + sizeof(struct scmi_sensor_desc);
+}
+
+static void scmi_sensor_config_get(struct scmi_msg *msg)
+{
+ const struct scmi_sensor_config_get_a2p *in_args = (void *)msg->in;
+ struct scmi_sensor_config_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int sensor_id = 0U;
+ uint32_t update_interval, state, timestamped;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id);
+
+ if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ update_interval = plat_scmi_sensor_update_interval(msg->agent_id, sensor_id);
+ state = plat_scmi_sensor_state(msg->agent_id, sensor_id);
+ timestamped = plat_scmi_sensor_timestamped(msg->agent_id, sensor_id);
+ return_values.sensor_config = (update_interval << 11) | (timestamped << 1) | state;
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_sensor_reading_get(struct scmi_msg *msg)
+{
+ const struct scmi_sensor_reading_get_a2p *in_args = (void *)msg->in;
+ struct scmi_sensor_reading_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int sensor_id = 0U;
+ int32_t ret;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id);
+
+ if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ ret = plat_scmi_sensor_reading_get(msg->agent_id, sensor_id,
+ (uint32_t *)&return_values.val);
+ if (ret) {
+ scmi_status_response(msg, SCMI_HARDWARE_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_sensor_list_update_intervals(struct scmi_msg *msg)
+{
+ /* TODO */
+ scmi_status_response(msg, SCMI_NOT_SUPPORTED);
+}
+
+static const scmi_msg_handler_t scmi_sensor_handler_table[SCMI_SENSOR_MAX] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_SENSOR_DESCRIPTION_GET] = scmi_sensor_description_get,
+ [SCMI_SENSOR_CONFIG_GET] = scmi_sensor_config_get,
+ [SCMI_SENSOR_LIST_UPDATE_INTERVALS] = scmi_sensor_list_update_intervals,
+ [SCMI_SENSOR_READING_GET] = scmi_sensor_reading_get,
+};
+
+static bool message_id_is_supported(size_t message_id)
+{
+ return scmi_sensor_handler_table[message_id] != NULL;
+}
+
+scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg)
+{
+ unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
+
+ if (!message_id_is_supported(message_id)) {
+ VERBOSE("pd handle not found %u\n", msg->message_id);
+ return NULL;
+ }
+
+ return scmi_sensor_handler_table[message_id];
+}
diff --git a/drivers/scmi-msg/sensor.h b/drivers/scmi-msg/sensor.h
new file mode 100644
index 0000000000..28cbb1ed34
--- /dev/null
+++ b/drivers/scmi-msg/sensor.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2023-2024 NXP
+ */
+
+#ifndef SCMI_MSG_SENSOR_H
+#define SCMI_MSG_SENSOR_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_SENSOR 0x20000U
+
+/*
+ * Identifiers of the SCMI SENSOR Protocol commands
+ */
+enum scmi_sensor_command_id {
+ SCMI_SENSOR_DESCRIPTION_GET = 0x003,
+ SCMI_SENSOR_TRIP_POINT_NOTIFY = 0x004,
+ SCMI_SENSOR_TRIP_POINT_CONFIG = 0x005,
+ SCMI_SENSOR_READING_GET = 0x006,
+ SCMI_SENSOR_AXIS_DESCRIPTION_GET = 0x007,
+ SCMI_SENSOR_LIST_UPDATE_INTERVALS = 0x008,
+ SCMI_SENSOR_CONFIG_GET = 0x009,
+ SCMI_SENSOR_CONFIG_SET = 0x00A,
+ SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0x00B,
+ SCMI_SENSOR_MAX = 0x00C,
+};
+
+/* Protocol attributes */
+struct scmi_protocol_attributes_p2a_sensor {
+ int32_t status;
+ int16_t num_sensors;
+ uint8_t max_reqs;
+ uint8_t res;
+ uint32_t sensor_reg_low;
+ uint32_t sensor_reg_high;
+ uint32_t sensor_reg_len;
+};
+
+#define SCMI_SENSOR_NAME_LENGTH_MAX 16U
+
+struct scmi_sensor_desc {
+ uint32_t id;
+ uint32_t attr_low;
+ uint32_t attr_high;
+ uint8_t name[SCMI_SENSOR_NAME_LENGTH_MAX];
+ uint32_t power;
+ uint32_t resolution;
+ int32_t min_range_low;
+ int32_t min_range_high;
+ int32_t max_range_low;
+ int32_t max_range_high;
+};
+
+struct scmi_sensor_description_get_a2p {
+ uint32_t desc_index;
+};
+
+struct scmi_sensor_description_get_p2a {
+ int32_t status;
+ uint32_t num_sensor_flags;
+};
+
+struct scmi_sensor_config_get_a2p {
+ uint32_t sensor_id;
+};
+
+struct scmi_sensor_config_get_p2a {
+ int32_t status;
+ uint32_t sensor_config;
+};
+
+/*
+ * Sensor Reading Get
+ */
+struct scmi_sensor_reading_get_a2p {
+ uint32_t sensor_id;
+ uint32_t flags;
+};
+
+struct scmi_sensor_val {
+ uint32_t value_low;
+ uint32_t value_high;
+ uint32_t timestap_low;
+ uint32_t timestap_high;
+};
+
+struct scmi_sensor_reading_get_p2a {
+ int32_t status;
+ struct scmi_sensor_val val;
+};
+
+typedef struct {
+ uint16_t (*sensor_count)(unsigned int agent_id);
+ uint8_t (*sensor_max_request)(unsigned int agent_id);
+ uint32_t (*get_sensor_req)(unsigned int agent_id, unsigned int *addr);
+ int32_t (*sensor_reading_get)(uint32_t agent_id, uint16_t sensor_id,
+ uint32_t *val);
+ uint32_t (*sensor_description_get)(unsigned int agent_id, uint16_t sensor_id,
+ struct scmi_sensor_desc *desc);
+ uint32_t (*sensor_update_interval)(uint32_t agent_id, uint16_t sensor_id);
+ uint32_t (*sensor_state)(uint32_t agent_id, uint16_t sensor_id);
+ uint16_t (*sensor_timestamped)(uint32_t agent_id, uint16_t sensor_id);
+} plat_scmi_sensor_ops_t;
+
+#define REGISTER_SCMI_SENSOR_OPS(_sensor_count, _sensor_max_request, \
+ _get_sensor_req, _sensor_reading_get, \
+ _sensor_description_get, _sensor_update_interval, \
+ _sensor_state, _sensor_timestamped) \
+ const plat_scmi_sensor_ops_t sensor_ops = { \
+ .sensor_count = _sensor_count, \
+ .sensor_max_request = _sensor_max_request, \
+ .get_sensor_req = _get_sensor_req, \
+ .sensor_reading_get = _sensor_reading_get, \
+ .sensor_description_get = _sensor_description_get, \
+ .sensor_update_interval = _sensor_update_interval, \
+ .sensor_state = _sensor_state, \
+ .sensor_timestamped = _sensor_timestamped, \
+ }
+
+extern const plat_scmi_sensor_ops_t sensor_ops;
+
+#endif /* SCMI_MSG_SENSOR_H */
diff --git a/drivers/scmi-msg/smt.c b/drivers/scmi-msg/smt.c
index b08ee0626c..9b079c7640 100644
--- a/drivers/scmi-msg/smt.c
+++ b/drivers/scmi-msg/smt.c
@@ -44,12 +44,12 @@ CASSERT(SCMI_PLAYLOAD_MAX + sizeof(struct smt_header) <= SMT_BUF_SLOT_SIZE,
assert_scmi_message_max_length_fits_in_smt_buffer_slot);
/* Flag set in smt_header::status when SMT does not contain pending message */
-#define SMT_STATUS_FREE BIT(0)
+#define SMT_STATUS_FREE BIT_32(0)
/* Flag set in smt_header::status when SMT reports an error */
-#define SMT_STATUS_ERROR BIT(1)
+#define SMT_STATUS_ERROR BIT_32(1)
/* Flag set in smt_header::flags when SMT uses interrupts */
-#define SMT_FLAG_INTR_ENABLED BIT(1)
+#define SMT_FLAG_INTR_ENABLED BIT_32(1)
/* Bit fields packed in smt_header::message_header */
#define SMT_MSG_ID_MASK GENMASK_32(7, 0)
@@ -133,7 +133,7 @@ static void scmi_proccess_smt(unsigned int agent_id, uint32_t *payload_buf)
sizeof(smt_hdr->message_header);
if (in_payload_size > SCMI_PLAYLOAD_MAX) {
- VERBOSE("SCMI payload too big %u", in_payload_size);
+ VERBOSE("SCMI payload too big %zu", in_payload_size);
goto out;
}
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
deleted file mode 100644
index 01c369edcd..0000000000
--- a/drivers/st/bsec/bsec.c
+++ /dev/null
@@ -1,891 +0,0 @@
-/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <limits.h>
-
-#include <libfdt.h>
-
-#include <platform_def.h>
-
-#include <arch_helpers.h>
-#include <common/debug.h>
-#include <drivers/st/bsec.h>
-#include <lib/mmio.h>
-#include <lib/spinlock.h>
-
-#define BSEC_IP_VERSION_1_0 0x10
-#define BSEC_COMPAT "st,stm32mp15-bsec"
-
-#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
-
-static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused;
-
-static uint32_t bsec_power_safmem(bool power);
-
-/* BSEC access protection */
-static spinlock_t bsec_spinlock;
-static uintptr_t bsec_base;
-
-static void bsec_lock(void)
-{
- if (stm32mp_lock_available()) {
- spin_lock(&bsec_spinlock);
- }
-}
-
-static void bsec_unlock(void)
-{
- if (stm32mp_lock_available()) {
- spin_unlock(&bsec_spinlock);
- }
-}
-
-static int bsec_get_dt_node(struct dt_node_info *info)
-{
- int node;
-
- node = dt_get_node(info, -1, BSEC_COMPAT);
- if (node < 0) {
- return -FDT_ERR_NOTFOUND;
- }
-
- return node;
-}
-
-#if defined(IMAGE_BL32)
-static void enable_non_secure_access(uint32_t otp)
-{
- otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
-
- if (bsec_shadow_register(otp) != BSEC_OK) {
- panic();
- }
-}
-
-static bool non_secure_can_access(uint32_t otp)
-{
- return (otp_nsec_access[otp / __WORD_BIT] &
- BIT(otp % __WORD_BIT)) != 0;
-}
-
-static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
-{
- int bsec_subnode;
-
- fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
- const fdt32_t *cuint;
- uint32_t reg;
- uint32_t i;
- uint32_t size;
- uint8_t status;
-
- cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
- if (cuint == NULL) {
- panic();
- }
-
- reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
- if (reg < STM32MP1_UPPER_OTP_START) {
- continue;
- }
-
- status = fdt_get_status(bsec_subnode);
- if ((status & DT_NON_SECURE) == 0U) {
- continue;
- }
-
- size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
-
- if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
- size++;
- }
-
- for (i = reg; i < (reg + size); i++) {
- enable_non_secure_access(i);
- }
- }
-
- return 0;
-}
-#endif
-
-static uint32_t otp_bank_offset(uint32_t otp)
-{
- assert(otp <= STM32MP1_OTP_MAX_ID);
-
- return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
- sizeof(uint32_t);
-}
-
-static uint32_t bsec_check_error(uint32_t otp)
-{
- uint32_t bit = BIT(otp & BSEC_OTP_MASK);
- uint32_t bank = otp_bank_offset(otp);
-
- if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
- return BSEC_DISTURBED;
- }
-
- if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
- return BSEC_ERROR;
- }
-
- return BSEC_OK;
-}
-
-/*
- * bsec_probe: initialize BSEC driver.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_probe(void)
-{
- void *fdt;
- int node;
- struct dt_node_info bsec_info;
-
- if (fdt_get_address(&fdt) == 0) {
- panic();
- }
-
- node = bsec_get_dt_node(&bsec_info);
- if (node < 0) {
- panic();
- }
-
- bsec_base = bsec_info.base;
-
-#if defined(IMAGE_BL32)
- bsec_dt_otp_nsec_access(fdt, node);
-#endif
- return BSEC_OK;
-}
-
-/*
- * bsec_get_base: return BSEC base address.
- */
-uint32_t bsec_get_base(void)
-{
- return bsec_base;
-}
-
-/*
- * bsec_set_config: enable and configure BSEC.
- * cfg: pointer to param structure used to set register.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_set_config(struct bsec_config *cfg)
-{
- uint32_t value;
- int32_t result;
-
- value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) &
- BSEC_CONF_FRQ_MASK) |
- (((uint32_t)cfg->pulse_width << BSEC_CONF_PRG_WIDTH_SHIFT) &
- BSEC_CONF_PRG_WIDTH_MASK) |
- (((uint32_t)cfg->tread << BSEC_CONF_TREAD_SHIFT) &
- BSEC_CONF_TREAD_MASK));
-
- bsec_lock();
-
- mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, value);
-
- bsec_unlock();
-
- result = bsec_power_safmem((bool)cfg->power &
- BSEC_CONF_POWER_UP_MASK);
- if (result != BSEC_OK) {
- return result;
- }
-
- value = ((((uint32_t)cfg->upper_otp_lock << UPPER_OTP_LOCK_SHIFT) &
- UPPER_OTP_LOCK_MASK) |
- (((uint32_t)cfg->den_lock << DENREG_LOCK_SHIFT) &
- DENREG_LOCK_MASK) |
- (((uint32_t)cfg->prog_lock << GPLOCK_LOCK_SHIFT) &
- GPLOCK_LOCK_MASK));
-
- bsec_lock();
-
- mmio_write_32(bsec_base + BSEC_OTP_LOCK_OFF, value);
-
- bsec_unlock();
-
- return BSEC_OK;
-}
-
-/*
- * bsec_get_config: return config parameters set in BSEC registers.
- * cfg: config param return.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_get_config(struct bsec_config *cfg)
-{
- uint32_t value;
-
- if (cfg == NULL) {
- return BSEC_INVALID_PARAM;
- }
-
- value = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
- cfg->power = (uint8_t)((value & BSEC_CONF_POWER_UP_MASK) >>
- BSEC_CONF_POWER_UP_SHIFT);
- cfg->freq = (uint8_t)((value & BSEC_CONF_FRQ_MASK) >>
- BSEC_CONF_FRQ_SHIFT);
- cfg->pulse_width = (uint8_t)((value & BSEC_CONF_PRG_WIDTH_MASK) >>
- BSEC_CONF_PRG_WIDTH_SHIFT);
- cfg->tread = (uint8_t)((value & BSEC_CONF_TREAD_MASK) >>
- BSEC_CONF_TREAD_SHIFT);
-
- value = mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF);
- cfg->upper_otp_lock = (uint8_t)((value & UPPER_OTP_LOCK_MASK) >>
- UPPER_OTP_LOCK_SHIFT);
- cfg->den_lock = (uint8_t)((value & DENREG_LOCK_MASK) >>
- DENREG_LOCK_SHIFT);
- cfg->prog_lock = (uint8_t)((value & GPLOCK_LOCK_MASK) >>
- GPLOCK_LOCK_SHIFT);
-
- return BSEC_OK;
-}
-
-/*
- * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
- * otp: OTP number.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_shadow_register(uint32_t otp)
-{
- uint32_t result;
- bool power_up = false;
-
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
- }
-
- /* Check if shadowing of OTP is locked */
- if (bsec_read_sr_lock(otp)) {
- VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
- otp);
- }
-
- if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
- result = bsec_power_safmem(true);
-
- if (result != BSEC_OK) {
- return result;
- }
-
- power_up = true;
- }
-
- bsec_lock();
-
- /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
- mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
-
- while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
- ;
- }
-
- result = bsec_check_error(otp);
-
- bsec_unlock();
-
- if (power_up) {
- if (bsec_power_safmem(false) != BSEC_OK) {
- panic();
- }
- }
-
- return result;
-}
-
-/*
- * bsec_read_otp: read an OTP data value.
- * val: read value.
- * otp: OTP number.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
-{
- uint32_t result;
-
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
- }
-
- bsec_lock();
-
- *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
- (otp * sizeof(uint32_t)));
-
- result = bsec_check_error(otp);
-
- bsec_unlock();
-
- return result;
-}
-
-/*
- * bsec_write_otp: write value in BSEC data register.
- * val: value to write.
- * otp: OTP number.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
-{
- uint32_t result;
-
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
- }
-
- /* Check if programming of OTP is locked */
- if (bsec_read_sw_lock(otp)) {
- VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
- otp);
- }
-
- bsec_lock();
-
- mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
- (otp * sizeof(uint32_t)), val);
-
- result = bsec_check_error(otp);
-
- bsec_unlock();
-
- return result;
-}
-
-/*
- * bsec_program_otp: program a bit in SAFMEM after the prog.
- * The OTP data is not refreshed.
- * val: value to program.
- * otp: OTP number.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
-{
- uint32_t result;
- bool power_up = false;
-
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
- }
-
- /* Check if programming of OTP is locked */
- if (bsec_read_sp_lock(otp)) {
- WARN("BSEC: OTP locked, prog will be ignored\n");
- }
-
- if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
- BIT(BSEC_LOCK_PROGRAM)) != 0U) {
- WARN("BSEC: GPLOCK activated, prog will be ignored\n");
- }
-
- if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
- result = bsec_power_safmem(true);
-
- if (result != BSEC_OK) {
- return result;
- }
-
- power_up = true;
- }
-
- bsec_lock();
-
- /* Set value in write register */
- mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
-
- /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
- mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
-
- while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
- ;
- }
-
- if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
- result = BSEC_PROG_FAIL;
- } else {
- result = bsec_check_error(otp);
- }
-
- bsec_unlock();
-
- if (power_up) {
- if (bsec_power_safmem(false) != BSEC_OK) {
- panic();
- }
- }
-
- return result;
-}
-
-/*
- * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
- * otp: OTP number.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_permanent_lock_otp(uint32_t otp)
-{
- uint32_t result;
- bool power_up = false;
- uint32_t data;
- uint32_t addr;
-
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
- }
-
- if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
- result = bsec_power_safmem(true);
-
- if (result != BSEC_OK) {
- return result;
- }
-
- power_up = true;
- }
-
- if (otp < STM32MP1_UPPER_OTP_START) {
- addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
- data = DATA_LOWER_OTP_PERLOCK_BIT <<
- ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
- } else {
- addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
- data = DATA_UPPER_OTP_PERLOCK_BIT <<
- (otp & DATA_UPPER_OTP_PERLOCK_MASK);
- }
-
- bsec_lock();
-
- /* Set value in write register */
- mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
-
- /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
- mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF,
- addr | BSEC_WRITE | BSEC_LOCK);
-
- while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
- ;
- }
-
- if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
- result = BSEC_PROG_FAIL;
- } else {
- result = bsec_check_error(otp);
- }
-
- bsec_unlock();
-
- if (power_up) {
- if (bsec_power_safmem(false) != BSEC_OK) {
- panic();
- }
- }
-
- return result;
-}
-
-/*
- * bsec_write_debug_conf: write value in debug feature
- * to enable/disable debug service.
- * val: value to write.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_write_debug_conf(uint32_t val)
-{
- uint32_t result = BSEC_ERROR;
- uint32_t masked_val = val & BSEC_DEN_ALL_MSK;
-
- bsec_lock();
-
- mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val);
-
- if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) {
- result = BSEC_OK;
- }
-
- bsec_unlock();
-
- return result;
-}
-
-/*
- * bsec_read_debug_conf: read debug configuration.
- */
-uint32_t bsec_read_debug_conf(void)
-{
- return mmio_read_32(bsec_base + BSEC_DEN_OFF);
-}
-
-/*
- * bsec_get_status: return status register value.
- */
-uint32_t bsec_get_status(void)
-{
- return mmio_read_32(bsec_base + BSEC_OTP_STATUS_OFF);
-}
-
-/*
- * bsec_get_hw_conf: return hardware configuration.
- */
-uint32_t bsec_get_hw_conf(void)
-{
- return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF);
-}
-
-/*
- * bsec_get_version: return BSEC version.
- */
-uint32_t bsec_get_version(void)
-{
- return mmio_read_32(bsec_base + BSEC_IPVR_OFF);
-}
-
-/*
- * bsec_get_id: return BSEC ID.
- */
-uint32_t bsec_get_id(void)
-{
- return mmio_read_32(bsec_base + BSEC_IP_ID_OFF);
-}
-
-/*
- * bsec_get_magic_id: return BSEC magic number.
- */
-uint32_t bsec_get_magic_id(void)
-{
- return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF);
-}
-
-/*
- * bsec_write_sr_lock: write shadow-read lock.
- * otp: OTP number.
- * value: value to write in the register.
- * Must be always 1.
- * return: true if OTP is locked, else false.
- */
-bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
-{
- bool result = false;
- uint32_t bank = otp_bank_offset(otp);
- uint32_t bank_value;
- uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
-
- bsec_lock();
-
- bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
-
- if ((bank_value & otp_mask) == value) {
- /*
- * In case of write don't need to write,
- * the lock is already set.
- */
- if (value != 0U) {
- result = true;
- }
- } else {
- if (value != 0U) {
- bank_value = bank_value | otp_mask;
- } else {
- bank_value = bank_value & ~otp_mask;
- }
-
- /*
- * We can write 0 in all other OTP
- * if the lock is activated in one of other OTP.
- * Write 0 has no effect.
- */
- mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value);
- result = true;
- }
-
- bsec_unlock();
-
- return result;
-}
-
-/*
- * bsec_read_sr_lock: read shadow-read lock.
- * otp: OTP number.
- * return: true if otp is locked, else false.
- */
-bool bsec_read_sr_lock(uint32_t otp)
-{
- uint32_t bank = otp_bank_offset(otp);
- uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
- uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
-
- return (bank_value & otp_mask) != 0U;
-}
-
-/*
- * bsec_write_sw_lock: write shadow-write lock.
- * otp: OTP number.
- * value: Value to write in the register.
- * Must be always 1.
- * return: true if OTP is locked, else false.
- */
-bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
-{
- bool result = false;
- uint32_t bank = otp_bank_offset(otp);
- uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
- uint32_t bank_value;
-
- bsec_lock();
-
- bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
-
- if ((bank_value & otp_mask) == value) {
- /*
- * In case of write don't need to write,
- * the lock is already set.
- */
- if (value != 0U) {
- result = true;
- }
- } else {
- if (value != 0U) {
- bank_value = bank_value | otp_mask;
- } else {
- bank_value = bank_value & ~otp_mask;
- }
-
- /*
- * We can write 0 in all other OTP
- * if the lock is activated in one of other OTP.
- * Write 0 has no effect.
- */
- mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value);
- result = true;
- }
-
- bsec_unlock();
-
- return result;
-}
-
-/*
- * bsec_read_sw_lock: read shadow-write lock.
- * otp: OTP number.
- * return: true if OTP is locked, else false.
- */
-bool bsec_read_sw_lock(uint32_t otp)
-{
- uint32_t bank = otp_bank_offset(otp);
- uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
- uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
-
- return (bank_value & otp_mask) != 0U;
-}
-
-/*
- * bsec_write_sp_lock: write shadow-program lock.
- * otp: OTP number.
- * value: Value to write in the register.
- * Must be always 1.
- * return: true if OTP is locked, else false.
- */
-bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
-{
- bool result = false;
- uint32_t bank = otp_bank_offset(otp);
- uint32_t bank_value;
- uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
-
- bsec_lock();
-
- bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
-
- if ((bank_value & otp_mask) == value) {
- /*
- * In case of write don't need to write,
- * the lock is already set.
- */
- if (value != 0U) {
- result = true;
- }
- } else {
- if (value != 0U) {
- bank_value = bank_value | otp_mask;
- } else {
- bank_value = bank_value & ~otp_mask;
- }
-
- /*
- * We can write 0 in all other OTP
- * if the lock is activated in one of other OTP.
- * Write 0 has no effect.
- */
- mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value);
- result = true;
- }
-
- bsec_unlock();
-
- return result;
-}
-
-/*
- * bsec_read_sp_lock: read shadow-program lock.
- * otp: OTP number.
- * return: true if OTP is locked, else false.
- */
-bool bsec_read_sp_lock(uint32_t otp)
-{
- uint32_t bank = otp_bank_offset(otp);
- uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
- uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
-
- return (bank_value & otp_mask) != 0U;
-}
-
-/*
- * bsec_wr_lock: Read permanent lock status.
- * otp: OTP number.
- * return: true if OTP is locked, else false.
- */
-bool bsec_wr_lock(uint32_t otp)
-{
- uint32_t bank = otp_bank_offset(otp);
- uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
-
- if ((mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank) &
- lock_bit) != 0U) {
- /*
- * In case of write don't need to write,
- * the lock is already set.
- */
- return true;
- }
-
- return false;
-}
-
-/*
- * bsec_otp_lock: Lock Upper OTP or Global programming or debug enable
- * service: Service to lock see header file.
- * value: Value to write must always set to 1 (only use for debug purpose).
- * return: BSEC_OK if succeed.
- */
-uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
-{
- uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
-
- switch (service) {
- case BSEC_LOCK_UPPER_OTP:
- mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP);
- break;
- case BSEC_LOCK_DEBUG:
- mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
- break;
- case BSEC_LOCK_PROGRAM:
- mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
- break;
- default:
- return BSEC_INVALID_PARAM;
- }
-
- return BSEC_OK;
-}
-
-/*
- * bsec_power_safmem: Activate or deactivate SAFMEM power.
- * power: true to power up, false to power down.
- * return: BSEC_OK if succeed.
- */
-static uint32_t bsec_power_safmem(bool power)
-{
- uint32_t register_val;
- uint32_t timeout = BSEC_TIMEOUT_VALUE;
-
- bsec_lock();
-
- register_val = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
-
- if (power) {
- register_val |= BSEC_CONF_POWER_UP_MASK;
- } else {
- register_val &= ~BSEC_CONF_POWER_UP_MASK;
- }
-
- mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val);
-
- /* Waiting loop */
- if (power) {
- while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) &&
- (timeout != 0U)) {
- timeout--;
- }
- } else {
- while (((bsec_get_status() & BSEC_MODE_PWR_MASK) != 0U) &&
- (timeout != 0U)) {
- timeout--;
- }
- }
-
- bsec_unlock();
-
- if (timeout == 0U) {
- return BSEC_TIMEOUT;
- }
-
- return BSEC_OK;
-}
-
-/*
- * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
- * otp_value: read value.
- * word: OTP number.
- * return value: BSEC_OK if no error.
- */
-uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word)
-{
- uint32_t result;
-
- result = bsec_shadow_register(word);
- if (result != BSEC_OK) {
- ERROR("BSEC: %u Shadowing Error %i\n", word, result);
- return result;
- }
-
- result = bsec_read_otp(otp_value, word);
- if (result != BSEC_OK) {
- ERROR("BSEC: %u Read Error %i\n", word, result);
- }
-
- return result;
-}
-
-/*
- * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
- * otp: OTP number.
- * return: BSEC_OK if authorized access.
- */
-uint32_t bsec_check_nsec_access_rights(uint32_t otp)
-{
-#if defined(IMAGE_BL32)
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
- }
-
- if (otp >= STM32MP1_UPPER_OTP_START) {
- /* Check if BSEC is in OTP-SECURED closed_device state. */
- if (stm32mp_is_closed_device()) {
- if (!non_secure_can_access(otp)) {
- return BSEC_ERROR;
- }
- }
- }
-#endif
-
- return BSEC_OK;
-}
-
diff --git a/drivers/st/bsec/bsec2.c b/drivers/st/bsec/bsec2.c
new file mode 100644
index 0000000000..a6e5220948
--- /dev/null
+++ b/drivers/st/bsec/bsec2.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (c) 2017-2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define BSEC_IP_VERSION_1_1 U(0x11)
+#define BSEC_IP_VERSION_2_0 U(0x20)
+#define BSEC_IP_ID_2 U(0x100032)
+
+/*
+ * IP configuration
+ */
+#define BSEC_OTP_MASK GENMASK(4, 0)
+#define BSEC_OTP_BANK_SHIFT 5
+#define BSEC_TIMEOUT_VALUE U(0xFFFF)
+
+#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
+
+static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __maybe_unused;
+
+static uint32_t bsec_shadow_register(uint32_t otp);
+static uint32_t bsec_power_safmem(bool power);
+static uint32_t bsec_get_version(void);
+static uint32_t bsec_get_id(void);
+static uint32_t bsec_get_status(void);
+static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value);
+
+/* BSEC access protection */
+static spinlock_t bsec_spinlock;
+
+static void bsec_lock(void)
+{
+ if (stm32mp_lock_available()) {
+ spin_lock(&bsec_spinlock);
+ }
+}
+
+static void bsec_unlock(void)
+{
+ if (stm32mp_lock_available()) {
+ spin_unlock(&bsec_spinlock);
+ }
+}
+
+static bool is_otp_invalid_mode(void)
+{
+ bool ret = ((bsec_get_status() & BSEC_OTP_STATUS_INVALID) == BSEC_OTP_STATUS_INVALID);
+
+ if (ret) {
+ ERROR("OTP mode is OTP-INVALID\n");
+ }
+
+ return ret;
+}
+
+#if defined(IMAGE_BL32)
+static int bsec_get_dt_node(struct dt_node_info *info)
+{
+ int node;
+
+ node = dt_get_node(info, -1, DT_BSEC_COMPAT);
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return node;
+}
+
+static void enable_non_secure_access(uint32_t otp)
+{
+ otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
+
+ if (bsec_shadow_register(otp) != BSEC_OK) {
+ panic();
+ }
+}
+
+static bool non_secure_can_access(uint32_t otp)
+{
+ return (otp_nsec_access[otp / __WORD_BIT] &
+ BIT(otp % __WORD_BIT)) != 0U;
+}
+
+static void bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
+{
+ int bsec_subnode;
+
+ fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
+ const fdt32_t *cuint;
+ uint32_t otp;
+ uint32_t i;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t length;
+
+ cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ panic();
+ }
+
+ offset = fdt32_to_cpu(*cuint);
+ cuint++;
+ length = fdt32_to_cpu(*cuint);
+
+ otp = offset / sizeof(uint32_t);
+
+ if (otp < STM32MP1_UPPER_OTP_START) {
+ unsigned int otp_end = round_up(offset + length,
+ sizeof(uint32_t)) /
+ sizeof(uint32_t);
+
+ if (otp_end > STM32MP1_UPPER_OTP_START) {
+ /*
+ * OTP crosses Lower/Upper boundary, consider
+ * only the upper part.
+ */
+ otp = STM32MP1_UPPER_OTP_START;
+ length -= (STM32MP1_UPPER_OTP_START *
+ sizeof(uint32_t)) - offset;
+ offset = STM32MP1_UPPER_OTP_START *
+ sizeof(uint32_t);
+
+ WARN("OTP crosses Lower/Upper boundary\n");
+ } else {
+ continue;
+ }
+ }
+
+ if ((fdt_getprop(fdt, bsec_subnode,
+ "st,non-secure-otp", NULL)) == NULL) {
+ continue;
+ }
+
+ if (((offset % sizeof(uint32_t)) != 0U) ||
+ ((length % sizeof(uint32_t)) != 0U)) {
+ ERROR("Unaligned non-secure OTP\n");
+ panic();
+ }
+
+ size = length / sizeof(uint32_t);
+
+ for (i = otp; i < (otp + size); i++) {
+ enable_non_secure_access(i);
+ }
+ }
+}
+
+static void bsec_late_init(void)
+{
+ void *fdt;
+ int node;
+ struct dt_node_info bsec_info;
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = bsec_get_dt_node(&bsec_info);
+ if (node < 0) {
+ panic();
+ }
+
+ assert(bsec_info.base == BSEC_BASE);
+
+ bsec_dt_otp_nsec_access(fdt, node);
+}
+#endif
+
+static uint32_t otp_bank_offset(uint32_t otp)
+{
+ assert(otp <= STM32MP1_OTP_MAX_ID);
+
+ return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
+ sizeof(uint32_t);
+}
+
+static uint32_t otp_bit_mask(uint32_t otp)
+{
+ return BIT(otp & BSEC_OTP_MASK);
+}
+
+/*
+ * bsec_check_error: check BSEC error status.
+ * otp: OTP number.
+ * check_disturbed: check only error (false),
+ * or error and disturbed status (true).
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
+{
+ uint32_t bit = otp_bit_mask(otp);
+ uint32_t bank = otp_bank_offset(otp);
+
+ if ((mmio_read_32(BSEC_BASE + BSEC_ERROR_OFF + bank) & bit) != 0U) {
+ return BSEC_ERROR;
+ }
+
+ if (!check_disturbed) {
+ return BSEC_OK;
+ }
+
+ if ((mmio_read_32(BSEC_BASE + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+ return BSEC_DISTURBED;
+ }
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (((bsec_get_version() != BSEC_IP_VERSION_1_1) &&
+ (bsec_get_version() != BSEC_IP_VERSION_2_0)) ||
+ (bsec_get_id() != BSEC_IP_ID_2)) {
+ panic();
+ }
+
+#if defined(IMAGE_BL32)
+ bsec_late_init();
+#endif
+ return BSEC_OK;
+}
+
+/*
+ * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_shadow_register(uint32_t otp)
+{
+ uint32_t result;
+ bool value;
+ bool power_up = false;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ result = bsec_read_sr_lock(otp, &value);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ if (value) {
+ VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n",
+ otp);
+ }
+
+ if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) {
+ result = bsec_power_safmem(true);
+
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ power_up = true;
+ }
+
+ bsec_lock();
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
+
+ while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) {
+ ;
+ }
+
+ result = bsec_check_error(otp, true);
+
+ bsec_unlock();
+
+ if (power_up) {
+ if (bsec_power_safmem(false) != BSEC_OK) {
+ panic();
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_read_otp: read an OTP data value.
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
+{
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ *val = mmio_read_32(BSEC_BASE + BSEC_OTP_DATA_OFF +
+ (otp * sizeof(uint32_t)));
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_write_otp: write value in BSEC data register.
+ * val: value to write.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
+{
+ uint32_t result;
+ bool value;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ result = bsec_read_sw_lock(otp, &value);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ if (value) {
+ VERBOSE("BSEC: OTP %u is locked and write will be ignored\n",
+ otp);
+ }
+
+ /* Ensure integrity of each register access sequence */
+ bsec_lock();
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_DATA_OFF +
+ (otp * sizeof(uint32_t)), val);
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_program_otp: program a bit in SAFMEM after the prog.
+ * The OTP data is not refreshed.
+ * val: value to program.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
+{
+ uint32_t result;
+ bool power_up = false;
+ bool sp_lock;
+ bool perm_lock;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ result = bsec_read_sp_lock(otp, &sp_lock);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ result = bsec_read_permanent_lock(otp, &perm_lock);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u permanent bit read Error %u\n", otp, result);
+ return result;
+ }
+
+ if (sp_lock || perm_lock) {
+ WARN("BSEC: OTP locked, prog will be ignored\n");
+ return BSEC_PROG_FAIL;
+ }
+
+ if ((mmio_read_32(BSEC_BASE + BSEC_OTP_LOCK_OFF) & GPLOCK_LOCK_MASK) != 0U) {
+ WARN("BSEC: GPLOCK activated, prog will be ignored\n");
+ }
+
+ if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) {
+ result = bsec_power_safmem(true);
+
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ power_up = true;
+ }
+
+ bsec_lock();
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, val);
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
+
+ while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) {
+ ;
+ }
+
+ if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) {
+ result = BSEC_PROG_FAIL;
+ } else {
+ result = bsec_check_error(otp, true);
+ }
+
+ bsec_unlock();
+
+ if (power_up) {
+ if (bsec_power_safmem(false) != BSEC_OK) {
+ panic();
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+#if defined(IMAGE_BL32)
+uint32_t bsec_permanent_lock_otp(uint32_t otp)
+{
+ uint32_t result;
+ bool power_up = false;
+ uint32_t data;
+ uint32_t addr;
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) {
+ result = bsec_power_safmem(true);
+
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ power_up = true;
+ }
+
+ if (otp < STM32MP1_UPPER_OTP_START) {
+ addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
+ data = DATA_LOWER_OTP_PERLOCK_BIT <<
+ ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
+ } else {
+ addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
+ data = DATA_UPPER_OTP_PERLOCK_BIT <<
+ (otp & DATA_UPPER_OTP_PERLOCK_MASK);
+ }
+
+ bsec_lock();
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, data);
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF,
+ addr | BSEC_WRITE | BSEC_LOCK);
+
+ while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) {
+ ;
+ }
+
+ if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) {
+ result = BSEC_PROG_FAIL;
+ } else {
+ result = bsec_check_error(otp, false);
+ }
+
+ bsec_unlock();
+
+ if (power_up) {
+ if (bsec_power_safmem(false) != BSEC_OK) {
+ panic();
+ }
+ }
+
+ return result;
+}
+#endif
+
+/*
+ * bsec_read_debug_conf: return debug configuration register value.
+ */
+uint32_t bsec_read_debug_conf(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_DEN_OFF);
+}
+
+/*
+ * bsec_write_scratch: write value in scratch register.
+ * val: value to write.
+ * return value: none.
+ */
+void bsec_write_scratch(uint32_t val)
+{
+#if defined(IMAGE_BL32)
+ if (is_otp_invalid_mode()) {
+ return;
+ }
+
+ bsec_lock();
+ mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val);
+ bsec_unlock();
+#else
+ mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val);
+#endif
+}
+
+/*
+ * bsec_get_status: return status register value.
+ */
+static uint32_t bsec_get_status(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_OTP_STATUS_OFF);
+}
+
+/*
+ * bsec_get_version: return BSEC version register value.
+ */
+static uint32_t bsec_get_version(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_IPVR_OFF) & BSEC_IPVR_MSK;
+}
+
+/*
+ * bsec_get_id: return BSEC ID register value.
+ */
+static uint32_t bsec_get_id(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_IP_ID_OFF);
+}
+
+/*
+ * bsec_set_sr_lock: set shadow-read lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sr_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+ mmio_write_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank, otp_mask);
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_sr_lock: read shadow-read lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_set_sw_lock: set shadow-write lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sw_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+ mmio_write_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank, otp_mask);
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_sw_lock: read shadow-write lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_set_sp_lock: set shadow-program lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sp_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ if (is_otp_invalid_mode()) {
+ return BSEC_ERROR;
+ }
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+ mmio_write_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank, otp_mask);
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_sp_lock: read shadow-program lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_permanent_lock: Read permanent lock status.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+ uint32_t bank_value;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(BSEC_BASE + BSEC_WRLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_power_safmem: Activate or deactivate SAFMEM power.
+ * power: true to power up, false to power down.
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_power_safmem(bool power)
+{
+ uint32_t register_val;
+ uint32_t timeout = BSEC_TIMEOUT_VALUE;
+
+ bsec_lock();
+
+ register_val = mmio_read_32(BSEC_BASE + BSEC_OTP_CONF_OFF);
+
+ if (power) {
+ register_val |= BSEC_CONF_POWER_UP_MASK;
+ } else {
+ register_val &= ~BSEC_CONF_POWER_UP_MASK;
+ }
+
+ mmio_write_32(BSEC_BASE + BSEC_OTP_CONF_OFF, register_val);
+
+ if (power) {
+ while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) &&
+ (timeout != 0U)) {
+ timeout--;
+ }
+ } else {
+ while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) != 0U) &&
+ (timeout != 0U)) {
+ timeout--;
+ }
+ }
+
+ bsec_unlock();
+
+ if (timeout == 0U) {
+ return BSEC_TIMEOUT;
+ }
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value.
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_read_otp(uint32_t *val, uint32_t otp)
+{
+ uint32_t result;
+
+ result = bsec_shadow_register(otp);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Shadowing Error %u\n", otp, result);
+ return result;
+ }
+
+ result = bsec_read_otp(val, otp);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Read Error %u\n", otp, result);
+ }
+
+ return result;
+}
+
+#if defined(IMAGE_BL32)
+/*
+ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
+ * otp: OTP number.
+ * return value: BSEC_OK if authorized access.
+ */
+uint32_t bsec_check_nsec_access_rights(uint32_t otp)
+{
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ if (otp >= STM32MP1_UPPER_OTP_START) {
+ if (!non_secure_can_access(otp)) {
+ return BSEC_ERROR;
+ }
+ }
+
+ return BSEC_OK;
+}
+#endif
+
+uint32_t bsec_get_secure_state(void)
+{
+ uint32_t status = bsec_get_status();
+ uint32_t result = BSEC_STATE_INVALID;
+ uint32_t otp_enc_id __maybe_unused;
+ uint32_t otp_bit_len __maybe_unused;
+ int res __maybe_unused;
+
+ if ((status & BSEC_OTP_STATUS_INVALID) != 0U) {
+ result = BSEC_STATE_INVALID;
+ } else {
+ if ((status & BSEC_OTP_STATUS_SECURE) != 0U) {
+ if (stm32mp_check_closed_device() == STM32MP_CHIP_SEC_CLOSED) {
+ result = BSEC_STATE_SEC_CLOSED;
+ } else {
+ result = BSEC_STATE_SEC_OPEN;
+ }
+ } else {
+ /* OTP modes OPEN1 and OPEN2 are not supported */
+ result = BSEC_STATE_INVALID;
+ }
+ }
+
+ return result;
+}
diff --git a/drivers/st/bsec/bsec3.c b/drivers/st/bsec/bsec3.c
new file mode 100644
index 0000000000..a803a3a9c1
--- /dev/null
+++ b/drivers/st/bsec/bsec3.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/bsec3_reg.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define BSEC_IP_VERSION_1_0 U(0x10)
+#define BSEC_IP_ID_3 U(0x100033)
+
+#define MAX_NB_TRIES U(3)
+
+/*
+ * IP configuration
+ */
+#define BSEC_OTP_MASK GENMASK_32(4, 0)
+#define BSEC_OTP_BANK_SHIFT U(5)
+#define BSEC_TIMEOUT_VALUE U(0x800000) /* ~7sec @1.2GHz */
+
+/* Magic use to indicated valid SHADOW = 'B' 'S' 'E' 'C' */
+#define BSEC_MAGIC U(0x42534543)
+
+#define OTP_MAX_SIZE (STM32MP2_OTP_MAX_ID + U(1))
+
+struct bsec_shadow {
+ uint32_t magic;
+ uint32_t state;
+ uint32_t value[OTP_MAX_SIZE];
+ uint32_t status[OTP_MAX_SIZE];
+};
+
+static uint32_t otp_bank(uint32_t otp)
+{
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ return (otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT;
+}
+
+static uint32_t otp_bit_mask(uint32_t otp)
+{
+ return BIT(otp & BSEC_OTP_MASK);
+}
+
+/*
+ * bsec_get_status: return status register value.
+ */
+static uint32_t bsec_get_status(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_OTPSR);
+}
+
+/*
+ * bsec_get_version: return BSEC version.
+ */
+static uint32_t bsec_get_version(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_VERR) & BSEC_VERR_MASK;
+}
+
+/*
+ * bsec_get_id: return BSEC ID.
+ */
+static uint32_t bsec_get_id(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_IPIDR);
+}
+
+static bool is_fuse_shadowed(uint32_t otp)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+ uint32_t bank_value;
+
+ bank_value = mmio_read_32(BSEC_BASE + BSEC_SFSR(bank));
+
+ if ((bank_value & otp_mask) != 0U) {
+ return true;
+ }
+
+ return false;
+}
+
+static void poll_otp_status_busy(void)
+{
+ uint32_t timeout = BSEC_TIMEOUT_VALUE;
+
+ while (((bsec_get_status() & BSEC_OTPSR_BUSY) != 0U) && (timeout != 0U)) {
+ timeout--;
+ }
+
+ if ((bsec_get_status() & BSEC_OTPSR_BUSY) != 0U) {
+ ERROR("BSEC timeout\n");
+ panic();
+ }
+}
+
+static uint32_t check_read_error(uint32_t otp)
+{
+ uint32_t status = bsec_get_status();
+
+ if ((status & BSEC_OTPSR_SECF) != 0U) {
+ VERBOSE("BSEC read %u single error correction detected\n", otp);
+ }
+
+ if ((status & BSEC_OTPSR_PPLF) != 0U) {
+ VERBOSE("BSEC read %u permanent programming lock detected.\n", otp);
+ }
+
+ if ((status & BSEC_OTPSR_PPLMF) != 0U) {
+ ERROR("BSEC read %u error 0x%x\n", otp, status);
+ return BSEC_ERROR;
+ }
+
+ if ((status & (BSEC_OTPSR_DISTURBF | BSEC_OTPSR_DEDF | BSEC_OTPSR_AMEF)) != 0U) {
+ ERROR("BSEC read %u error 0x%x with invalid FVR\n", otp, status);
+ return BSEC_RETRY;
+ }
+
+ return BSEC_OK;
+}
+
+static uint32_t check_program_error(uint32_t otp)
+{
+ uint32_t status = bsec_get_status();
+
+ if ((status & BSEC_OTPSR_PROGFAIL) != 0U) {
+ ERROR("BSEC program %u error 0x%x\n", otp, status);
+ return BSEC_RETRY;
+ }
+
+ return BSEC_OK;
+}
+
+static void check_reset_error(void)
+{
+ uint32_t status = bsec_get_status();
+
+ /* check initial status reporting */
+ if ((status & BSEC_OTPSR_BUSY) != 0U) {
+ VERBOSE("BSEC reset and busy when OTPSR read\n");
+ }
+ if ((status & BSEC_OTPSR_HIDEUP) != 0U) {
+ VERBOSE("BSEC upper fuse are not accessible (HIDEUP)\n");
+ }
+ if ((status & BSEC_OTPSR_OTPSEC) != 0U) {
+ VERBOSE("BSEC reset single error correction detected\n");
+ }
+ if ((status & BSEC_OTPSR_OTPNVIR) == 0U) {
+ VERBOSE("BSEC reset first fuse word 0 is detected zero\n");
+ }
+ if ((status & BSEC_OTPSR_OTPERR) != 0U) {
+ ERROR("BSEC reset critical error 0x%x\n", status);
+ panic();
+ }
+ if ((status & BSEC_OTPSR_FUSEOK) != BSEC_OTPSR_FUSEOK) {
+ ERROR("BSEC reset critical error 0x%x\n", status);
+ panic();
+ }
+}
+
+static bool is_bsec_write_locked(void)
+{
+ return (mmio_read_32(BSEC_BASE + BSEC_LOCKR) & BSEC_LOCKR_GWLOCK_MASK) != 0U;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+ uint32_t version = bsec_get_version();
+ uint32_t id = bsec_get_id();
+
+ if ((version != BSEC_IP_VERSION_1_0) || (id != BSEC_IP_ID_3)) {
+ ERROR("%s: version = 0x%x, id = 0x%x\n", __func__, version, id);
+ panic();
+ }
+
+ check_reset_error();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_shadow_register(uint32_t otp)
+{
+ uint32_t result;
+ uint32_t i;
+ bool value;
+
+ result = bsec_read_sr_lock(otp, &value);
+ if (result != BSEC_OK) {
+ WARN("BSEC: %u Sticky-read bit read Error %u\n", otp, result);
+ } else if (value) {
+ VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n", otp);
+ }
+
+ for (i = 0U; i < MAX_NB_TRIES; i++) {
+ mmio_write_32(BSEC_BASE + BSEC_OTPCR, otp);
+
+ poll_otp_status_busy();
+
+ result = check_read_error(otp);
+ if (result != BSEC_RETRY) {
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_write_otp: write a value in shadow OTP.
+ * val: value to program.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
+{
+ bool state;
+ uint32_t result;
+
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ if (!is_fuse_shadowed(otp)) {
+ return BSEC_ERROR;
+ }
+
+ if (is_bsec_write_locked()) {
+ return BSEC_WRITE_LOCKED;
+ }
+
+ result = bsec_read_sw_lock(otp, &state);
+ if (result != BSEC_OK) {
+ WARN("Shadow register is SW locked\n");
+ return result;
+ }
+
+ mmio_write_32(BSEC_BASE + BSEC_FVR(otp), val);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_program_otp: program a bit in SAFMEM after the prog.
+ * The OTP data is not refreshed.
+ * val: value to program.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
+{
+ uint32_t result;
+ uint32_t i;
+ bool value;
+
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ if (is_bsec_write_locked() == true) {
+ return BSEC_WRITE_LOCKED;
+ }
+
+ result = bsec_read_sp_lock(otp, &value);
+ if (result != BSEC_OK) {
+ WARN("BSEC: %u Sticky-prog bit read Error %u\n", otp, result);
+ } else if (value) {
+ WARN("BSEC: OTP locked, prog will be ignored\n");
+ return BSEC_WRITE_LOCKED;
+ }
+
+ mmio_write_32(BSEC_BASE + BSEC_WDR, val);
+
+ for (i = 0U; i < MAX_NB_TRIES; i++) {
+ mmio_write_32(BSEC_BASE + BSEC_OTPCR, otp | BSEC_OTPCR_PROG);
+
+ poll_otp_status_busy();
+
+ result = check_program_error(otp);
+ if (result != BSEC_RETRY) {
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_read_debug_conf: read debug configuration.
+ */
+uint32_t bsec_read_debug_conf(void)
+{
+ return mmio_read_32(BSEC_BASE + BSEC_DENR);
+}
+
+static uint32_t bsec_lock_register_set(uint32_t offset, uint32_t mask)
+{
+ uint32_t value = mmio_read_32(BSEC_BASE + offset);
+
+ /* The lock is already set */
+ if ((value & mask) != 0U) {
+ return BSEC_OK;
+ }
+
+ if (is_bsec_write_locked()) {
+ return BSEC_WRITE_LOCKED;
+ }
+
+ value |= mask;
+
+ mmio_write_32(BSEC_BASE + offset, value);
+
+ return BSEC_OK;
+}
+
+static bool bsec_lock_register_get(uint32_t offset, uint32_t mask)
+{
+ uint32_t value = mmio_read_32(BSEC_BASE + offset);
+
+ return (value & mask) != 0U;
+}
+
+/*
+ * bsec_set_sr_lock: set shadow-read lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sr_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ return bsec_lock_register_set(BSEC_SRLOCK(bank), otp_mask);
+}
+
+/*
+ * bsec_read_sr_lock: read shadow-read lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ assert(value != NULL);
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ *value = bsec_lock_register_get(BSEC_SRLOCK(bank), otp_mask);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_set_sw_lock: set shadow-write lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sw_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ return bsec_lock_register_set(BSEC_SWLOCK(bank), otp_mask);
+}
+
+/*
+ * bsec_read_sw_lock: read shadow-write lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ assert(value != NULL);
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ *value = bsec_lock_register_get(BSEC_SWLOCK(bank), otp_mask);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_set_sp_lock: set shadow-program lock.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_sp_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ return bsec_lock_register_set(BSEC_SPLOCK(bank), otp_mask);
+}
+
+/*
+ * bsec_read_sp_lock: read shadow-program lock.
+ * otp: OTP number.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value)
+{
+ uint32_t bank = otp_bank(otp);
+ uint32_t otp_mask = otp_bit_mask(otp);
+
+ assert(value != NULL);
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ *value = bsec_lock_register_get(BSEC_SPLOCK(bank), otp_mask);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_get_secure_state: read state in BSEC status register.
+ * return: secure state
+ */
+uint32_t bsec_get_secure_state(void)
+{
+ uint32_t state = BSEC_STATE_INVALID;
+ uint32_t status = bsec_get_status();
+ uint32_t bsec_sr = mmio_read_32(BSEC_BASE + BSEC_SR);
+
+ if ((status & BSEC_OTPSR_FUSEOK) == BSEC_OTPSR_FUSEOK) {
+ /* NVSTATE is only valid if FUSEOK */
+ uint32_t nvstates = (bsec_sr & BSEC_SR_NVSTATE_MASK) >> BSEC_SR_NVSTATE_SHIFT;
+
+ if (nvstates == BSEC_SR_NVSTATE_OPEN) {
+ state = BSEC_STATE_SEC_OPEN;
+ } else if (nvstates == BSEC_SR_NVSTATE_CLOSED) {
+ state = BSEC_STATE_SEC_CLOSED;
+ } else {
+ VERBOSE("%s nvstates = %u\n", __func__, nvstates);
+ }
+ }
+
+ return state;
+}
+
+/*
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_read_otp(uint32_t *val, uint32_t otp)
+{
+ assert(val != NULL);
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ *val = 0U;
+
+ if (is_bsec_write_locked()) {
+ return BSEC_WRITE_LOCKED;
+ }
+
+ if (!is_fuse_shadowed(otp)) {
+ uint32_t result = bsec_shadow_register(otp);
+
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Shadowing Error %u\n", otp, result);
+ return result;
+ }
+ }
+
+ *val = mmio_read_32(BSEC_BASE + BSEC_FVR(otp));
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_read_otp: read an OTP data value.
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
+{
+ assert(val != NULL);
+ if (otp > STM32MP2_OTP_MAX_ID) {
+ panic();
+ }
+
+ return bsec_shadow_read_otp(val, otp);
+}
diff --git a/drivers/st/clk/clk-stm32-core.c b/drivers/st/clk/clk-stm32-core.c
new file mode 100644
index 0000000000..9fe8c8ccac
--- /dev/null
+++ b/drivers/st/clk/clk-stm32-core.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include "clk-stm32-core.h"
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+static struct spinlock reg_lock;
+static struct spinlock refcount_lock;
+
+static struct stm32_clk_priv *stm32_clock_data;
+
+const struct stm32_clk_ops clk_mux_ops;
+
+struct stm32_clk_priv *clk_stm32_get_priv(void)
+{
+ return stm32_clock_data;
+}
+
+static void stm32mp1_clk_lock(struct spinlock *lock)
+{
+ if (stm32mp_lock_available()) {
+ /* Assume interrupts are masked */
+ spin_lock(lock);
+ }
+}
+
+static void stm32mp1_clk_unlock(struct spinlock *lock)
+{
+ if (stm32mp_lock_available()) {
+ spin_unlock(lock);
+ }
+}
+
+void stm32mp1_clk_rcc_regs_lock(void)
+{
+ stm32mp1_clk_lock(&reg_lock);
+}
+
+void stm32mp1_clk_rcc_regs_unlock(void)
+{
+ stm32mp1_clk_unlock(&reg_lock);
+}
+
+#define TIMEOUT_US_1S U(1000000)
+#define OSCRDY_TIMEOUT TIMEOUT_US_1S
+
+struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_osc_cfg *osc_cfg = clk->clock_cfg;
+ int osc_id = osc_cfg->osc_id;
+
+ return &priv->osci_data[osc_id];
+}
+
+void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ struct stm32_clk_bypass *bypass_data = osc_data->bypass;
+ uintptr_t address;
+
+ if (bypass_data == NULL) {
+ return;
+ }
+
+ address = priv->base + bypass_data->offset;
+
+ if (digbyp) {
+ mmio_setbits_32(address, BIT(bypass_data->bit_digbyp));
+ }
+
+ if (bypass || digbyp) {
+ mmio_setbits_32(address, BIT(bypass_data->bit_byp));
+ }
+}
+
+void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ struct stm32_clk_css *css_data = osc_data->css;
+ uintptr_t address;
+
+ if (css_data == NULL) {
+ return;
+ }
+
+ address = priv->base + css_data->offset;
+
+ if (css) {
+ mmio_setbits_32(address, BIT(css_data->bit_css));
+ }
+}
+
+void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ struct stm32_clk_drive *drive_data = osc_data->drive;
+ uintptr_t address;
+ uint32_t mask;
+ uint32_t value;
+
+ if (drive_data == NULL) {
+ return;
+ }
+
+ address = priv->base + drive_data->offset;
+
+ mask = (BIT(drive_data->drv_width) - 1U) << drive_data->drv_shift;
+
+ /*
+ * Warning: not recommended to switch directly from "high drive"
+ * to "medium low drive", and vice-versa.
+ */
+ value = (mmio_read_32(address) & mask) >> drive_data->drv_shift;
+
+ while (value != lsedrv) {
+ if (value > lsedrv) {
+ value--;
+ } else {
+ value++;
+ }
+
+ mmio_clrsetbits_32(address, mask, value << drive_data->drv_shift);
+ }
+}
+
+int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ return _clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, ready_on);
+}
+
+int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id)
+{
+ return clk_oscillator_wait_ready(priv, id, true);
+}
+
+int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id)
+{
+ return clk_oscillator_wait_ready(priv, id, false);
+}
+
+static int clk_gate_enable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_gate_cfg *cfg = clk->clock_cfg;
+
+ mmio_setbits_32(priv->base + cfg->offset, BIT(cfg->bit_idx));
+
+ return 0;
+}
+
+static void clk_gate_disable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_gate_cfg *cfg = clk->clock_cfg;
+
+ mmio_clrbits_32(priv->base + cfg->offset, BIT(cfg->bit_idx));
+}
+
+static bool clk_gate_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_gate_cfg *cfg = clk->clock_cfg;
+
+ return ((mmio_read_32(priv->base + cfg->offset) & BIT(cfg->bit_idx)) != 0U);
+}
+
+const struct stm32_clk_ops clk_gate_ops = {
+ .enable = clk_gate_enable,
+ .disable = clk_gate_disable,
+ .is_enabled = clk_gate_is_enabled,
+};
+
+void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id)
+{
+ const struct gate_cfg *gate = &priv->gates[gate_id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx));
+ } else {
+ mmio_clrbits_32(addr, BIT(gate->bit_idx));
+ }
+}
+
+int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id)
+{
+ const struct gate_cfg *gate = &priv->gates[gate_id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr, BIT(gate->bit_idx));
+
+ } else {
+ mmio_setbits_32(addr, BIT(gate->bit_idx));
+ }
+
+ return 0;
+}
+
+const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id)
+{
+ if ((unsigned int)id < priv->num) {
+ return &priv->clks[id];
+ }
+
+ return NULL;
+}
+
+#define clk_div_mask(_width) GENMASK(((_width) - 1U), 0U)
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++) {
+ if (clkt->val == val) {
+ return clkt->div;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags,
+ uint8_t width)
+{
+ if ((flags & CLK_DIVIDER_ONE_BASED) != 0UL) {
+ return val;
+ }
+
+ if ((flags & CLK_DIVIDER_POWER_OF_TWO) != 0UL) {
+ return BIT(val);
+ }
+
+ if ((flags & CLK_DIVIDER_MAX_AT_ZERO) != 0UL) {
+ return (val != 0U) ? val : BIT(width);
+ }
+
+ if (table != NULL) {
+ return _get_table_div(table, val);
+ }
+
+ return val + 1U;
+}
+
+#define TIMEOUT_US_200MS U(200000)
+#define CLKSRC_TIMEOUT TIMEOUT_US_200MS
+
+int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel)
+{
+ const struct parent_cfg *parents = &priv->parents[pid & MUX_PARENT_MASK];
+ const struct mux_cfg *mux = parents->mux;
+ uintptr_t address = priv->base + mux->offset;
+ uint32_t mask;
+ uint64_t timeout;
+
+ mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
+
+ mmio_clrsetbits_32(address, mask, (sel << mux->shift) & mask);
+
+ if (mux->bitrdy == MUX_NO_BIT_RDY) {
+ return 0;
+ }
+
+ timeout = timeout_init_us(CLKSRC_TIMEOUT);
+
+ mask = BIT(mux->bitrdy);
+
+ while ((mmio_read_32(address) & mask) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int clk, int clkp)
+{
+ const struct parent_cfg *parents;
+ uint16_t pid;
+ uint8_t sel;
+ int old_parent;
+
+ pid = priv->clks[clk].parent;
+
+ if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) {
+ return -EINVAL;
+ }
+
+ old_parent = _clk_stm32_get_parent(priv, clk);
+ if (old_parent < 0) {
+ return old_parent;
+ }
+ if (old_parent == clkp) {
+ return 0;
+ }
+
+ parents = &priv->parents[pid & MUX_PARENT_MASK];
+
+ for (sel = 0; sel < parents->num_parents; sel++) {
+ if (parents->id_parents[sel] == (uint16_t)clkp) {
+ bool clk_was_enabled = _clk_stm32_is_enabled(priv, clk);
+ int err = 0;
+
+ /* Enable the parents (for glitch free mux) */
+ _clk_stm32_enable(priv, clkp);
+ _clk_stm32_enable(priv, old_parent);
+
+ err = clk_mux_set_parent(priv, pid, sel);
+
+ _clk_stm32_disable(priv, old_parent);
+
+ if (clk_was_enabled) {
+ _clk_stm32_disable(priv, old_parent);
+ } else {
+ _clk_stm32_disable(priv, clkp);
+ }
+
+ return err;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id)
+{
+ const struct parent_cfg *parent;
+ const struct mux_cfg *mux;
+ uint32_t mask;
+
+ if (mux_id >= priv->nb_parents) {
+ panic();
+ }
+
+ parent = &priv->parents[mux_id];
+ mux = parent->mux;
+
+ mask = MASK_WIDTH_SHIFT(mux->width, mux->shift);
+
+ return (mmio_read_32(priv->base + mux->offset) & mask) >> mux->shift;
+}
+
+int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel)
+{
+ uint16_t pid;
+
+ pid = priv->clks[clk].parent;
+
+ if ((pid == CLK_IS_ROOT) || (pid < MUX_MAX_PARENTS)) {
+ return -EINVAL;
+ }
+
+ return clk_mux_set_parent(priv, pid, sel);
+}
+
+int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int clk_id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, clk_id);
+ const struct parent_cfg *parent;
+ uint16_t mux_id;
+ int sel;
+
+ mux_id = priv->clks[clk_id].parent;
+ if (mux_id == CLK_IS_ROOT) {
+ return CLK_IS_ROOT;
+ }
+
+ if (mux_id < MUX_MAX_PARENTS) {
+ return mux_id & MUX_PARENT_MASK;
+ }
+
+ mux_id &= MUX_PARENT_MASK;
+ parent = &priv->parents[mux_id];
+
+ if (clk->ops->get_parent != NULL) {
+ sel = clk->ops->get_parent(priv, clk_id);
+ } else {
+ sel = clk_mux_get_parent(priv, mux_id);
+ }
+
+ if ((sel >= 0) && (sel < parent->num_parents)) {
+ return parent->id_parents[sel];
+ }
+
+ return -EINVAL;
+}
+
+int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id)
+{
+ uint16_t mux_id;
+
+ mux_id = priv->clks[clk_id].parent;
+ if (mux_id == CLK_IS_ROOT) {
+ return CLK_IS_ROOT;
+ }
+
+ if (mux_id < MUX_MAX_PARENTS) {
+ return mux_id & MUX_PARENT_MASK;
+ }
+
+ mux_id &= MUX_PARENT_MASK;
+
+ return clk_mux_get_parent(priv, mux_id);
+}
+
+int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx)
+{
+ const struct parent_cfg *parent;
+ uint16_t mux_id;
+
+ mux_id = priv->clks[clk_id].parent;
+ if (mux_id == CLK_IS_ROOT) {
+ return CLK_IS_ROOT;
+ }
+
+ if (mux_id < MUX_MAX_PARENTS) {
+ return mux_id & MUX_PARENT_MASK;
+ }
+
+ mux_id &= MUX_PARENT_MASK;
+ parent = &priv->parents[mux_id];
+
+ if (idx < parent->num_parents) {
+ return parent->id_parents[idx];
+ }
+
+ return -EINVAL;
+}
+
+int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id)
+{
+ unsigned int i;
+
+ for (i = 0U; i < priv->num; i++) {
+ if (binding_id == priv->clks[i].binding) {
+ return (int)i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ int parent;
+
+ if ((unsigned int)id >= priv->num) {
+ return 0UL;
+ }
+
+ parent = _clk_stm32_get_parent(priv, id);
+ if (parent < 0) {
+ return 0UL;
+ }
+
+ if (clk->ops->recalc_rate != NULL) {
+ unsigned long prate = 0UL;
+
+ if (parent != CLK_IS_ROOT) {
+ prate = _clk_stm32_get_rate(priv, parent);
+ }
+
+ return clk->ops->recalc_rate(priv, id, prate);
+ }
+
+ if (parent == CLK_IS_ROOT) {
+ panic();
+ }
+
+ return _clk_stm32_get_rate(priv, parent);
+}
+
+unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id)
+{
+ int parent_id = _clk_stm32_get_parent(priv, id);
+
+ if (parent_id < 0) {
+ return 0UL;
+ }
+
+ return _clk_stm32_get_rate(priv, parent_id);
+}
+
+static uint8_t _stm32_clk_get_flags(struct stm32_clk_priv *priv, int id)
+{
+ return priv->clks[id].flags;
+}
+
+bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag)
+{
+ if ((_stm32_clk_get_flags(priv, id) & flag) != 0U) {
+ return true;
+ }
+
+ return false;
+}
+
+int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+
+ if (clk->ops->enable != NULL) {
+ clk->ops->enable(priv, id);
+ }
+
+ return 0;
+}
+
+static int _clk_stm32_enable_core(struct stm32_clk_priv *priv, int id)
+{
+ int parent;
+ int ret = 0;
+
+ if (priv->gate_refcounts[id] == 0U) {
+ parent = _clk_stm32_get_parent(priv, id);
+ if (parent < 0) {
+ return parent;
+ }
+ if (parent != CLK_IS_ROOT) {
+ ret = _clk_stm32_enable_core(priv, parent);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ clk_stm32_enable_call_ops(priv, id);
+ }
+
+ priv->gate_refcounts[id]++;
+
+ if (priv->gate_refcounts[id] == UINT_MAX) {
+ ERROR("%s: %d max enable count !", __func__, id);
+ panic();
+ }
+
+ return 0;
+}
+
+int _clk_stm32_enable(struct stm32_clk_priv *priv, int id)
+{
+ int ret;
+
+ stm32mp1_clk_lock(&refcount_lock);
+ ret = _clk_stm32_enable_core(priv, id);
+ stm32mp1_clk_unlock(&refcount_lock);
+
+ return ret;
+}
+
+void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+
+ if (clk->ops->disable != NULL) {
+ clk->ops->disable(priv, id);
+ }
+}
+
+static void _clk_stm32_disable_core(struct stm32_clk_priv *priv, int id)
+{
+ int parent;
+
+ if ((priv->gate_refcounts[id] == 1U) && _stm32_clk_is_flags(priv, id, CLK_IS_CRITICAL)) {
+ return;
+ }
+
+ if (priv->gate_refcounts[id] == 0U) {
+ /* case of clock ignore unused */
+ if (_clk_stm32_is_enabled(priv, id)) {
+ clk_stm32_disable_call_ops(priv, id);
+ return;
+ }
+ VERBOSE("%s: %d already disabled !\n\n", __func__, id);
+ return;
+ }
+
+ if (--priv->gate_refcounts[id] > 0U) {
+ return;
+ }
+
+ clk_stm32_disable_call_ops(priv, id);
+
+ parent = _clk_stm32_get_parent(priv, id);
+ if ((parent >= 0) && (parent != CLK_IS_ROOT)) {
+ _clk_stm32_disable_core(priv, parent);
+ }
+}
+
+void _clk_stm32_disable(struct stm32_clk_priv *priv, int id)
+{
+ stm32mp1_clk_lock(&refcount_lock);
+
+ _clk_stm32_disable_core(priv, id);
+
+ stm32mp1_clk_unlock(&refcount_lock);
+}
+
+bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+
+ if (clk->ops->is_enabled != NULL) {
+ return clk->ops->is_enabled(priv, id);
+ }
+
+ return priv->gate_refcounts[id];
+}
+
+static int clk_stm32_enable(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return id;
+ }
+
+ return _clk_stm32_enable(priv, id);
+}
+
+static void clk_stm32_disable(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id != -EINVAL) {
+ _clk_stm32_disable(priv, id);
+ }
+}
+
+static bool clk_stm32_is_enabled(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return false;
+ }
+
+ return _clk_stm32_is_enabled(priv, id);
+}
+
+static unsigned long clk_stm32_get_rate(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return 0UL;
+ }
+
+ return _clk_stm32_get_rate(priv, id);
+}
+
+static int clk_stm32_get_parent(unsigned long binding_id)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int id;
+
+ id = clk_get_index(priv, binding_id);
+ if (id == -EINVAL) {
+ return id;
+ }
+
+ return _clk_stm32_get_parent(priv, 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,
+ .get_parent = clk_stm32_get_parent,
+};
+
+void clk_stm32_enable_critical_clocks(void)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ unsigned int i;
+
+ for (i = 0U; i < priv->num; i++) {
+ if (_stm32_clk_is_flags(priv, i, CLK_IS_CRITICAL)) {
+ _clk_stm32_enable(priv, i);
+ }
+ }
+}
+
+static void stm32_clk_register(void)
+{
+ clk_register(&stm32mp_clk_ops);
+}
+
+uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id)
+{
+ const struct div_cfg *divider = &priv->div[div_id];
+ uint32_t val = 0;
+
+ val = mmio_read_32(priv->base + divider->offset) >> divider->shift;
+ val &= clk_div_mask(divider->width);
+
+ return val;
+}
+
+unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv,
+ int div_id,
+ unsigned long prate)
+{
+ const struct div_cfg *divider = &priv->div[div_id];
+ uint32_t val = clk_stm32_div_get_value(priv, div_id);
+ unsigned int div = 0U;
+
+ div = _get_div(divider->table, val, divider->flags, divider->width);
+ if (div == 0U) {
+ return prate;
+ }
+
+ return div_round_up((uint64_t)prate, div);
+}
+
+unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int id,
+ unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_div_cfg *div_cfg = clk->clock_cfg;
+
+ return _clk_stm32_divider_recalc(priv, div_cfg->id, prate);
+}
+
+const struct stm32_clk_ops clk_stm32_divider_ops = {
+ .recalc_rate = clk_stm32_divider_recalc,
+};
+
+int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value)
+{
+ const struct div_cfg *divider;
+ uintptr_t address;
+ uint64_t timeout;
+ uint32_t mask;
+
+ if (div_id >= priv->nb_div) {
+ panic();
+ }
+
+ divider = &priv->div[div_id];
+ address = priv->base + divider->offset;
+
+ mask = MASK_WIDTH_SHIFT(divider->width, divider->shift);
+ mmio_clrsetbits_32(address, mask, (value << divider->shift) & mask);
+
+ if (divider->bitrdy == DIV_NO_BIT_RDY) {
+ return 0;
+ }
+
+ timeout = timeout_init_us(CLKSRC_TIMEOUT);
+ mask = BIT(divider->bitrdy);
+
+ while ((mmio_read_32(address) & mask) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id,
+ bool ready_on)
+{
+ const struct gate_cfg *gate = &priv->gates[gate_id];
+ uintptr_t address = priv->base + gate->offset;
+ uint32_t mask_rdy = BIT(gate->bit_idx);
+ uint64_t timeout;
+ uint32_t mask_test;
+
+ if (ready_on) {
+ mask_test = BIT(gate->bit_idx);
+ } else {
+ mask_test = 0U;
+ }
+
+ timeout = timeout_init_us(OSCRDY_TIMEOUT);
+
+ while ((mmio_read_32(address) & mask_rdy) != mask_test) {
+ if (timeout_elapsed(timeout)) {
+ break;
+ }
+ }
+
+ if ((mmio_read_32(address) & mask_rdy) != mask_test) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_gate_cfg *cfg = clk->clock_cfg;
+ const struct gate_cfg *gate = &priv->gates[cfg->id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr, BIT(gate->bit_idx));
+
+ } else {
+ mmio_setbits_32(addr, BIT(gate->bit_idx));
+ }
+
+ return 0;
+}
+
+void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_gate_cfg *cfg = clk->clock_cfg;
+ const struct gate_cfg *gate = &priv->gates[cfg->id];
+ uintptr_t addr = priv->base + gate->offset;
+
+ if (gate->set_clr != 0U) {
+ mmio_write_32(addr + RCC_MP_ENCLRR_OFFSET, BIT(gate->bit_idx));
+ } else {
+ mmio_clrbits_32(addr, BIT(gate->bit_idx));
+ }
+}
+
+bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id)
+{
+ const struct gate_cfg *gate;
+ uint32_t addr;
+
+ gate = &priv->gates[gate_id];
+ addr = priv->base + gate->offset;
+
+ return ((mmio_read_32(addr) & BIT(gate->bit_idx)) != 0U);
+}
+
+bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_gate_cfg *cfg = clk->clock_cfg;
+
+ return _clk_stm32_gate_is_enabled(priv, cfg->id);
+}
+
+const struct stm32_clk_ops clk_stm32_gate_ops = {
+ .enable = clk_stm32_gate_enable,
+ .disable = clk_stm32_gate_disable,
+ .is_enabled = clk_stm32_gate_is_enabled,
+};
+
+const struct stm32_clk_ops clk_fixed_factor_ops = {
+ .recalc_rate = fixed_factor_recalc_rate,
+};
+
+unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv,
+ int id, unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ const struct fixed_factor_cfg *cfg = clk->clock_cfg;
+ unsigned long long rate;
+
+ rate = (unsigned long long)prate * cfg->mult;
+
+ if (cfg->div == 0U) {
+ ERROR("division by zero\n");
+ panic();
+ }
+
+ return (unsigned long)(rate / cfg->div);
+};
+
+#define APB_DIV_MASK GENMASK(2, 0)
+#define TIM_PRE_MASK BIT(0)
+
+static unsigned long timer_recalc_rate(struct stm32_clk_priv *priv,
+ int id, unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ const struct clk_timer_cfg *cfg = clk->clock_cfg;
+ uint32_t prescaler, timpre;
+ uintptr_t rcc_base = priv->base;
+
+ prescaler = mmio_read_32(rcc_base + cfg->apbdiv) &
+ APB_DIV_MASK;
+
+ timpre = mmio_read_32(rcc_base + cfg->timpre) &
+ TIM_PRE_MASK;
+
+ if (prescaler == 0U) {
+ return prate;
+ }
+
+ return prate * (timpre + 1U) * 2U;
+};
+
+const struct stm32_clk_ops clk_timer_ops = {
+ .recalc_rate = timer_recalc_rate,
+};
+
+static unsigned long clk_fixed_rate_recalc(struct stm32_clk_priv *priv, int id,
+ unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct clk_stm32_fixed_rate_cfg *cfg = clk->clock_cfg;
+
+ return cfg->rate;
+}
+
+const struct stm32_clk_ops clk_stm32_fixed_rate_ops = {
+ .recalc_rate = clk_fixed_rate_recalc,
+};
+
+static unsigned long clk_stm32_osc_recalc_rate(struct stm32_clk_priv *priv,
+ int id, unsigned long prate)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ return osc_data->frequency;
+};
+
+bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ return _clk_stm32_gate_is_enabled(priv, osc_data->gate_id);
+
+}
+
+int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ _clk_stm32_gate_enable(priv, osc_data->gate_id);
+
+ if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, true) != 0U) {
+ ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__);
+ panic();
+ }
+
+ return 0;
+}
+
+void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+
+ _clk_stm32_gate_disable(priv, osc_data->gate_id);
+
+ if (_clk_stm32_gate_wait_ready(priv, osc_data->gate_rdy_id, false) != 0U) {
+ ERROR("%s: %s (%d)\n", __func__, osc_data->name, __LINE__);
+ panic();
+ }
+}
+
+static unsigned long clk_stm32_get_dt_oscillator_frequency(const char *name)
+{
+ void *fdt = NULL;
+ int node = 0;
+ int subnode = 0;
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = fdt_path_offset(fdt, "/clocks");
+ if (node < 0) {
+ return 0UL;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, node) {
+ const char *cchar = NULL;
+ const fdt32_t *cuint = NULL;
+ int ret = 0;
+
+ cchar = fdt_get_name(fdt, subnode, &ret);
+ if (cchar == NULL) {
+ continue;
+ }
+
+ if (strncmp(cchar, name, (size_t)ret) ||
+ fdt_get_status(subnode) == DT_DISABLED) {
+ continue;
+ }
+
+ cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret);
+ if (cuint == NULL) {
+ return 0UL;
+ }
+
+ return fdt32_to_cpu(*cuint);
+ }
+
+ return 0UL;
+}
+
+void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, id);
+ const char *name = osc_data->name;
+
+ osc_data->frequency = clk_stm32_get_dt_oscillator_frequency(name);
+}
+
+const struct stm32_clk_ops clk_stm32_osc_ops = {
+ .recalc_rate = clk_stm32_osc_recalc_rate,
+ .is_enabled = clk_stm32_osc_gate_is_enabled,
+ .enable = clk_stm32_osc_gate_enable,
+ .disable = clk_stm32_osc_gate_disable,
+ .init = clk_stm32_osc_init,
+};
+
+const struct stm32_clk_ops clk_stm32_osc_nogate_ops = {
+ .recalc_rate = clk_stm32_osc_recalc_rate,
+ .init = clk_stm32_osc_init,
+};
+
+int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb)
+{
+ const fdt32_t *cell;
+ int len = 0;
+ uint32_t i;
+
+ cell = fdt_getprop(fdt, node, name, &len);
+ if (cell == NULL) {
+ *nb = 0U;
+ return 0;
+ }
+
+ for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
+ uint32_t val = fdt32_to_cpu(cell[i]);
+
+ tab[i] = val;
+ }
+
+ *nb = (uint32_t)len / sizeof(uint32_t);
+
+ return 0;
+}
+
+int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base)
+{
+ unsigned int i;
+
+ stm32_clock_data = priv;
+
+ priv->base = base;
+
+ for (i = 0U; i < priv->num; i++) {
+ const struct clk_stm32 *clk = _clk_get(priv, i);
+
+ assert(clk->ops != NULL);
+
+ if (clk->ops->init != NULL) {
+ clk->ops->init(priv, i);
+ }
+ }
+
+ stm32_clk_register();
+
+ return 0;
+}
diff --git a/drivers/st/clk/clk-stm32-core.h b/drivers/st/clk/clk-stm32-core.h
new file mode 100644
index 0000000000..8bfb5134f4
--- /dev/null
+++ b/drivers/st/clk/clk-stm32-core.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef CLK_STM32_CORE_H
+#define CLK_STM32_CORE_H
+
+struct mux_cfg {
+ uint16_t offset;
+ uint8_t shift;
+ uint8_t width;
+ uint8_t bitrdy;
+};
+
+struct gate_cfg {
+ uint16_t offset;
+ uint8_t bit_idx;
+ uint8_t set_clr;
+};
+
+struct clk_div_table {
+ unsigned int val;
+ unsigned int div;
+};
+
+struct div_cfg {
+ uint16_t offset;
+ uint8_t shift;
+ uint8_t width;
+ uint8_t flags;
+ uint8_t bitrdy;
+ const struct clk_div_table *table;
+};
+
+struct parent_cfg {
+ uint8_t num_parents;
+ const uint16_t *id_parents;
+ struct mux_cfg *mux;
+};
+
+struct stm32_clk_priv;
+
+struct stm32_clk_ops {
+ unsigned long (*recalc_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate);
+ int (*get_parent)(struct stm32_clk_priv *priv, int id);
+ int (*set_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate,
+ unsigned long prate);
+ int (*enable)(struct stm32_clk_priv *priv, int id);
+ void (*disable)(struct stm32_clk_priv *priv, int id);
+ bool (*is_enabled)(struct stm32_clk_priv *priv, int id);
+ void (*init)(struct stm32_clk_priv *priv, int id);
+};
+
+struct clk_stm32 {
+ uint16_t binding;
+ uint16_t parent;
+ uint8_t flags;
+ void *clock_cfg;
+ const struct stm32_clk_ops *ops;
+};
+
+struct stm32_clk_priv {
+ uintptr_t base;
+ const uint32_t num;
+ const struct clk_stm32 *clks;
+ const struct parent_cfg *parents;
+ const uint32_t nb_parents;
+ const struct gate_cfg *gates;
+ const uint32_t nb_gates;
+ const struct div_cfg *div;
+ const uint32_t nb_div;
+ struct clk_oscillator_data *osci_data;
+ const uint32_t nb_osci_data;
+ uint32_t *gate_refcounts;
+ void *pdata;
+};
+
+struct stm32_clk_bypass {
+ uint16_t offset;
+ uint8_t bit_byp;
+ uint8_t bit_digbyp;
+};
+
+struct stm32_clk_css {
+ uint16_t offset;
+ uint8_t bit_css;
+};
+
+struct stm32_clk_drive {
+ uint16_t offset;
+ uint8_t drv_shift;
+ uint8_t drv_width;
+ uint8_t drv_default;
+};
+
+struct clk_oscillator_data {
+ const char *name;
+ uint16_t id_clk;
+ unsigned long frequency;
+ uint16_t gate_id;
+ uint16_t gate_rdy_id;
+ struct stm32_clk_bypass *bypass;
+ struct stm32_clk_css *css;
+ struct stm32_clk_drive *drive;
+};
+
+struct clk_fixed_rate {
+ const char *name;
+ unsigned long fixed_rate;
+};
+
+struct clk_gate_cfg {
+ uint32_t offset;
+ uint8_t bit_idx;
+};
+
+/* CLOCK FLAGS */
+#define CLK_IS_CRITICAL BIT(0)
+#define CLK_IGNORE_UNUSED BIT(1)
+#define CLK_SET_RATE_PARENT BIT(2)
+
+#define CLK_DIVIDER_ONE_BASED BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK BIT(3)
+#define CLK_DIVIDER_ROUND_CLOSEST BIT(4)
+#define CLK_DIVIDER_READ_ONLY BIT(5)
+#define CLK_DIVIDER_MAX_AT_ZERO BIT(6)
+#define CLK_DIVIDER_BIG_ENDIAN BIT(7)
+
+#define MUX_MAX_PARENTS U(0x8000)
+#define MUX_PARENT_MASK GENMASK(14, 0)
+#define MUX_FLAG U(0x8000)
+#define MUX(mux) ((mux) | MUX_FLAG)
+
+#define NO_GATE 0
+#define _NO_ID UINT16_MAX
+#define CLK_IS_ROOT UINT16_MAX
+#define MUX_NO_BIT_RDY UINT8_MAX
+#define DIV_NO_BIT_RDY UINT8_MAX
+
+#define MASK_WIDTH_SHIFT(_width, _shift) \
+ GENMASK(((_width) + (_shift) - 1U), (_shift))
+
+int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base);
+void clk_stm32_enable_critical_clocks(void);
+
+struct stm32_clk_priv *clk_stm32_get_priv(void);
+
+int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id);
+const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id);
+
+void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass);
+void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv);
+void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css);
+
+int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, bool ready_on);
+
+int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on);
+int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id);
+int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id);
+
+int clk_stm32_get_counter(unsigned long binding_id);
+
+void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id);
+int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id);
+
+int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int id, int src_id);
+int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel);
+
+int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int id);
+int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx);
+int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id);
+
+unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id);
+unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id);
+
+bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag);
+
+int _clk_stm32_enable(struct stm32_clk_priv *priv, int id);
+void _clk_stm32_disable(struct stm32_clk_priv *priv, int id);
+
+int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
+void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
+
+bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id);
+
+int _clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int div_id,
+ unsigned long rate, unsigned long parent_rate);
+
+int clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int id, unsigned long rate,
+ unsigned long prate);
+
+unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv,
+ int div_id,
+ unsigned long prate);
+
+unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int idx,
+ unsigned long prate);
+
+int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int idx);
+void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int idx);
+
+bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id);
+bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int idx);
+
+uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id);
+int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value);
+int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel);
+int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id);
+
+int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb);
+
+#ifdef CFG_STM32_CLK_DEBUG
+void clk_stm32_display_clock_info(void);
+#endif
+
+struct clk_stm32_div_cfg {
+ int id;
+};
+
+#define STM32_DIV(idx, _binding, _parent, _flags, _div_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_stm32_div_cfg){\
+ .id = (_div_id),\
+ },\
+ .ops = &clk_stm32_divider_ops,\
+ }
+
+struct clk_stm32_gate_cfg {
+ int id;
+};
+
+#define STM32_GATE(idx, _binding, _parent, _flags, _gate_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_stm32_gate_cfg){\
+ .id = (_gate_id),\
+ },\
+ .ops = &clk_stm32_gate_ops,\
+ }
+
+struct fixed_factor_cfg {
+ unsigned int mult;
+ unsigned int div;
+};
+
+unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv,
+ int _idx, unsigned long prate);
+
+#define FIXED_FACTOR(idx, _idx, _parent, _mult, _div) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .clock_cfg = &(struct fixed_factor_cfg){\
+ .mult = (_mult),\
+ .div = (_div),\
+ },\
+ .ops = &clk_fixed_factor_ops,\
+ }
+
+#define GATE(idx, _binding, _parent, _flags, _offset, _bit_idx) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_gate_cfg){\
+ .offset = (_offset),\
+ .bit_idx = (_bit_idx),\
+ },\
+ .ops = &clk_gate_ops,\
+ }
+
+#define STM32_MUX(idx, _binding, _mux_id, _flags) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (MUX(_mux_id)),\
+ .flags = (_flags),\
+ .clock_cfg = NULL,\
+ .ops = (&clk_mux_ops),\
+ }
+
+struct clk_timer_cfg {
+ uint32_t apbdiv;
+ uint32_t timpre;
+};
+
+#define CK_TIMER(idx, _idx, _parent, _flags, _apbdiv, _timpre) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .flags = (CLK_SET_RATE_PARENT | (_flags)),\
+ .clock_cfg = &(struct clk_timer_cfg){\
+ .apbdiv = (_apbdiv),\
+ .timpre = (_timpre),\
+ },\
+ .ops = &clk_timer_ops,\
+ }
+
+struct clk_stm32_fixed_rate_cfg {
+ unsigned long rate;
+};
+
+#define CLK_FIXED_RATE(idx, _binding, _rate) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_binding),\
+ .parent = (CLK_IS_ROOT),\
+ .clock_cfg = &(struct clk_stm32_fixed_rate_cfg){\
+ .rate = (_rate),\
+ },\
+ .ops = &clk_stm32_fixed_rate_ops,\
+ }
+
+#define BYPASS(_offset, _bit_byp, _bit_digbyp) &(struct stm32_clk_bypass){\
+ .offset = (_offset),\
+ .bit_byp = (_bit_byp),\
+ .bit_digbyp = (_bit_digbyp),\
+}
+
+#define CSS(_offset, _bit_css) &(struct stm32_clk_css){\
+ .offset = (_offset),\
+ .bit_css = (_bit_css),\
+}
+
+#define DRIVE(_offset, _shift, _width, _default) &(struct stm32_clk_drive){\
+ .offset = (_offset),\
+ .drv_shift = (_shift),\
+ .drv_width = (_width),\
+ .drv_default = (_default),\
+}
+
+#define OSCILLATOR(idx_osc, _id, _name, _gate_id, _gate_rdy_id, _bypass, _css, _drive) \
+ [(idx_osc)] = (struct clk_oscillator_data){\
+ .name = (_name),\
+ .id_clk = (_id),\
+ .gate_id = (_gate_id),\
+ .gate_rdy_id = (_gate_rdy_id),\
+ .bypass = (_bypass),\
+ .css = (_css),\
+ .drive = (_drive),\
+ }
+
+struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id);
+
+void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id);
+bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id);
+int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id);
+void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id);
+
+struct stm32_osc_cfg {
+ int osc_id;
+};
+
+#define CLK_OSC(idx, _idx, _parent, _osc_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .flags = CLK_IS_CRITICAL,\
+ .clock_cfg = &(struct stm32_osc_cfg){\
+ .osc_id = (_osc_id),\
+ },\
+ .ops = &clk_stm32_osc_ops,\
+ }
+
+#define CLK_OSC_FIXED(idx, _idx, _parent, _osc_id) \
+ [(idx)] = (struct clk_stm32){ \
+ .binding = (_idx),\
+ .parent = (_parent),\
+ .flags = CLK_IS_CRITICAL,\
+ .clock_cfg = &(struct stm32_osc_cfg){\
+ .osc_id = (_osc_id),\
+ },\
+ .ops = &clk_stm32_osc_nogate_ops,\
+ }
+
+extern const struct stm32_clk_ops clk_mux_ops;
+extern const struct stm32_clk_ops clk_stm32_divider_ops;
+extern const struct stm32_clk_ops clk_stm32_gate_ops;
+extern const struct stm32_clk_ops clk_fixed_factor_ops;
+extern const struct stm32_clk_ops clk_gate_ops;
+extern const struct stm32_clk_ops clk_timer_ops;
+extern const struct stm32_clk_ops clk_stm32_fixed_rate_ops;
+extern const struct stm32_clk_ops clk_stm32_osc_ops;
+extern const struct stm32_clk_ops clk_stm32_osc_nogate_ops;
+
+#endif /* CLK_STM32_CORE_H */
diff --git a/drivers/st/clk/clk-stm32mp13.c b/drivers/st/clk/clk-stm32mp13.c
new file mode 100644
index 0000000000..01d1764002
--- /dev/null
+++ b/drivers/st/clk/clk-stm32mp13.c
@@ -0,0 +1,2332 @@
+/*
+ * Copyright (C) 2022-2023, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include "clk-stm32-core.h"
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp13_rcc.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <dt-bindings/clock/stm32mp13-clksrc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+struct stm32_osci_dt_cfg {
+ unsigned long freq;
+ bool bypass;
+ bool digbyp;
+ bool css;
+ uint32_t drive;
+};
+
+enum pll_mn {
+ PLL_CFG_M,
+ PLL_CFG_N,
+ PLL_DIV_MN_NB
+};
+
+enum pll_pqr {
+ PLL_CFG_P,
+ PLL_CFG_Q,
+ PLL_CFG_R,
+ PLL_DIV_PQR_NB
+};
+
+enum pll_csg {
+ PLL_CSG_MOD_PER,
+ PLL_CSG_INC_STEP,
+ PLL_CSG_SSCG_MODE,
+ PLL_CSG_NB
+};
+
+struct stm32_pll_vco {
+ uint32_t status;
+ uint32_t src;
+ uint32_t div_mn[PLL_DIV_MN_NB];
+ uint32_t frac;
+ bool csg_enabled;
+ uint32_t csg[PLL_CSG_NB];
+};
+
+struct stm32_pll_output {
+ uint32_t output[PLL_DIV_PQR_NB];
+};
+
+struct stm32_pll_dt_cfg {
+ struct stm32_pll_vco vco;
+ struct stm32_pll_output output;
+};
+
+struct stm32_clk_platdata {
+ uint32_t nosci;
+ struct stm32_osci_dt_cfg *osci;
+ uint32_t npll;
+ struct stm32_pll_dt_cfg *pll;
+ uint32_t nclksrc;
+ uint32_t *clksrc;
+ uint32_t nclkdiv;
+ uint32_t *clkdiv;
+};
+
+enum stm32_clock {
+ /* ROOT CLOCKS */
+ _CK_OFF,
+ _CK_HSI,
+ _CK_HSE,
+ _CK_CSI,
+ _CK_LSI,
+ _CK_LSE,
+ _I2SCKIN,
+ _CSI_DIV122,
+ _HSE_DIV,
+ _HSE_DIV2,
+ _CK_PLL1,
+ _CK_PLL2,
+ _CK_PLL3,
+ _CK_PLL4,
+ _PLL1P,
+ _PLL1P_DIV,
+ _PLL2P,
+ _PLL2Q,
+ _PLL2R,
+ _PLL3P,
+ _PLL3Q,
+ _PLL3R,
+ _PLL4P,
+ _PLL4Q,
+ _PLL4R,
+ _PCLK1,
+ _PCLK2,
+ _PCLK3,
+ _PCLK4,
+ _PCLK5,
+ _PCLK6,
+ _CKMPU,
+ _CKAXI,
+ _CKMLAHB,
+ _CKPER,
+ _CKTIMG1,
+ _CKTIMG2,
+ _CKTIMG3,
+ _USB_PHY_48,
+ _MCO1_K,
+ _MCO2_K,
+ _TRACECK,
+ /* BUS and KERNEL CLOCKS */
+ _DDRC1,
+ _DDRC1LP,
+ _DDRPHYC,
+ _DDRPHYCLP,
+ _DDRCAPB,
+ _DDRCAPBLP,
+ _AXIDCG,
+ _DDRPHYCAPB,
+ _DDRPHYCAPBLP,
+ _SYSCFG,
+ _DDRPERFM,
+ _IWDG2APB,
+ _USBPHY_K,
+ _USBO_K,
+ _RTCAPB,
+ _TZC,
+ _ETZPC,
+ _IWDG1APB,
+ _BSEC,
+ _STGENC,
+ _USART1_K,
+ _USART2_K,
+ _I2C3_K,
+ _I2C4_K,
+ _I2C5_K,
+ _TIM12,
+ _TIM15,
+ _RTCCK,
+ _GPIOA,
+ _GPIOB,
+ _GPIOC,
+ _GPIOD,
+ _GPIOE,
+ _GPIOF,
+ _GPIOG,
+ _GPIOH,
+ _GPIOI,
+ _PKA,
+ _SAES_K,
+ _CRYP1,
+ _HASH1,
+ _RNG1_K,
+ _BKPSRAM,
+ _SDMMC1_K,
+ _SDMMC2_K,
+ _DBGCK,
+ _USART3_K,
+ _UART4_K,
+ _UART5_K,
+ _UART7_K,
+ _UART8_K,
+ _USART6_K,
+ _MCE,
+ _FMC_K,
+ _QSPI_K,
+#if defined(IMAGE_BL32)
+ _LTDC,
+ _DMA1,
+ _DMA2,
+ _MDMA,
+ _ETH1MAC,
+ _USBH,
+ _TIM2,
+ _TIM3,
+ _TIM4,
+ _TIM5,
+ _TIM6,
+ _TIM7,
+ _LPTIM1_K,
+ _SPI2_K,
+ _SPI3_K,
+ _SPDIF_K,
+ _TIM1,
+ _TIM8,
+ _SPI1_K,
+ _SAI1_K,
+ _SAI2_K,
+ _DFSDM,
+ _FDCAN_K,
+ _TIM13,
+ _TIM14,
+ _TIM16,
+ _TIM17,
+ _SPI4_K,
+ _SPI5_K,
+ _I2C1_K,
+ _I2C2_K,
+ _ADFSDM,
+ _LPTIM2_K,
+ _LPTIM3_K,
+ _LPTIM4_K,
+ _LPTIM5_K,
+ _VREF,
+ _DTS,
+ _PMBCTRL,
+ _HDP,
+ _STGENRO,
+ _DCMIPP_K,
+ _DMAMUX1,
+ _DMAMUX2,
+ _DMA3,
+ _ADC1_K,
+ _ADC2_K,
+ _TSC,
+ _AXIMC,
+ _ETH1CK,
+ _ETH1TX,
+ _ETH1RX,
+ _CRC1,
+ _ETH2CK,
+ _ETH2TX,
+ _ETH2RX,
+ _ETH2MAC,
+#endif
+ CK_LAST
+};
+
+/* PARENT CONFIG */
+static const uint16_t RTC_src[] = {
+ _CK_OFF, _CK_LSE, _CK_LSI, _CK_HSE
+};
+
+static const uint16_t MCO1_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI, _CK_LSI, _CK_LSE
+};
+
+static const uint16_t MCO2_src[] = {
+ _CKMPU, _CKAXI, _CKMLAHB, _PLL4P, _CK_HSE, _CK_HSI
+};
+
+static const uint16_t PLL12_src[] = {
+ _CK_HSI, _CK_HSE
+};
+
+static const uint16_t PLL3_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI
+};
+
+static const uint16_t PLL4_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI, _I2SCKIN
+};
+
+static const uint16_t MPU_src[] = {
+ _CK_HSI, _CK_HSE, _PLL1P, _PLL1P_DIV
+};
+
+static const uint16_t AXI_src[] = {
+ _CK_HSI, _CK_HSE, _PLL2P
+};
+
+static const uint16_t MLAHBS_src[] = {
+ _CK_HSI, _CK_HSE, _CK_CSI, _PLL3P
+};
+
+static const uint16_t CKPER_src[] = {
+ _CK_HSI, _CK_CSI, _CK_HSE, _CK_OFF
+};
+
+static const uint16_t I2C12_src[] = {
+ _PCLK1, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t I2C3_src[] = {
+ _PCLK6, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t I2C4_src[] = {
+ _PCLK6, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t I2C5_src[] = {
+ _PCLK6, _PLL4R, _CK_HSI, _CK_CSI
+};
+
+static const uint16_t SPI1_src[] = {
+ _PLL4P, _PLL3Q, _I2SCKIN, _CKPER, _PLL3R
+};
+
+static const uint16_t SPI23_src[] = {
+ _PLL4P, _PLL3Q, _I2SCKIN, _CKPER, _PLL3R
+};
+
+static const uint16_t SPI4_src[] = {
+ _PCLK6, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE, _I2SCKIN
+};
+
+static const uint16_t SPI5_src[] = {
+ _PCLK6, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART1_src[] = {
+ _PCLK6, _PLL3Q, _CK_HSI, _CK_CSI, _PLL4Q, _CK_HSE
+};
+
+static const uint16_t UART2_src[] = {
+ _PCLK6, _PLL3Q, _CK_HSI, _CK_CSI, _PLL4Q, _CK_HSE
+};
+
+static const uint16_t UART35_src[] = {
+ _PCLK1, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART4_src[] = {
+ _PCLK1, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART6_src[] = {
+ _PCLK2, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t UART78_src[] = {
+ _PCLK1, _PLL4Q, _CK_HSI, _CK_CSI, _CK_HSE
+};
+
+static const uint16_t LPTIM1_src[] = {
+ _PCLK1, _PLL4P, _PLL3Q, _CK_LSE, _CK_LSI, _CKPER
+};
+
+static const uint16_t LPTIM2_src[] = {
+ _PCLK3, _PLL4Q, _CKPER, _CK_LSE, _CK_LSI
+};
+
+static const uint16_t LPTIM3_src[] = {
+ _PCLK3, _PLL4Q, _CKPER, _CK_LSE, _CK_LSI
+};
+
+static const uint16_t LPTIM45_src[] = {
+ _PCLK3, _PLL4P, _PLL3Q, _CK_LSE, _CK_LSI, _CKPER
+};
+
+static const uint16_t SAI1_src[] = {
+ _PLL4Q, _PLL3Q, _I2SCKIN, _CKPER, _PLL3R
+};
+
+static const uint16_t SAI2_src[] = {
+ _PLL4Q, _PLL3Q, _I2SCKIN, _CKPER, _NO_ID, _PLL3R
+};
+
+static const uint16_t FDCAN_src[] = {
+ _CK_HSE, _PLL3Q, _PLL4Q, _PLL4R
+};
+
+static const uint16_t SPDIF_src[] = {
+ _PLL4P, _PLL3Q, _CK_HSI
+};
+
+static const uint16_t ADC1_src[] = {
+ _PLL4R, _CKPER, _PLL3Q
+};
+
+static const uint16_t ADC2_src[] = {
+ _PLL4R, _CKPER, _PLL3Q
+};
+
+static const uint16_t SDMMC1_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CK_HSI
+};
+
+static const uint16_t SDMMC2_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CK_HSI
+};
+
+static const uint16_t ETH1_src[] = {
+ _PLL4P, _PLL3Q
+};
+
+static const uint16_t ETH2_src[] = {
+ _PLL4P, _PLL3Q
+};
+
+static const uint16_t USBPHY_src[] = {
+ _CK_HSE, _PLL4R, _HSE_DIV2
+};
+
+static const uint16_t USBO_src[] = {
+ _PLL4R, _USB_PHY_48
+};
+
+static const uint16_t QSPI_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CKPER
+};
+
+static const uint16_t FMC_src[] = {
+ _CKAXI, _PLL3R, _PLL4P, _CKPER
+};
+
+/* Position 2 of RNG1 mux is reserved */
+static const uint16_t RNG1_src[] = {
+ _CK_CSI, _PLL4R, _CK_OFF, _CK_LSI
+};
+
+static const uint16_t STGEN_src[] = {
+ _CK_HSI, _CK_HSE
+};
+
+static const uint16_t DCMIPP_src[] = {
+ _CKAXI, _PLL2Q, _PLL4P, _CKPER
+};
+
+static const uint16_t SAES_src[] = {
+ _CKAXI, _CKPER, _PLL4R, _CK_LSI
+};
+
+#define MUX_CFG(id, src, _offset, _shift, _witdh)[id] = {\
+ .id_parents = src,\
+ .num_parents = ARRAY_SIZE(src),\
+ .mux = &(struct mux_cfg) {\
+ .offset = (_offset),\
+ .shift = (_shift),\
+ .width = (_witdh),\
+ .bitrdy = MUX_NO_BIT_RDY,\
+ },\
+}
+
+#define MUX_RDY_CFG(id, src, _offset, _shift, _witdh)[id] = {\
+ .id_parents = src,\
+ .num_parents = ARRAY_SIZE(src),\
+ .mux = &(struct mux_cfg) {\
+ .offset = (_offset),\
+ .shift = (_shift),\
+ .width = (_witdh),\
+ .bitrdy = 31,\
+ },\
+}
+
+static const struct parent_cfg parent_mp13[MUX_MAX] = {
+ MUX_CFG(MUX_ADC1, ADC1_src, RCC_ADC12CKSELR, 0, 2),
+ MUX_CFG(MUX_ADC2, ADC2_src, RCC_ADC12CKSELR, 2, 2),
+ MUX_RDY_CFG(MUX_AXI, AXI_src, RCC_ASSCKSELR, 0, 3),
+ MUX_CFG(MUX_CKPER, CKPER_src, RCC_CPERCKSELR, 0, 2),
+ MUX_CFG(MUX_DCMIPP, DCMIPP_src, RCC_DCMIPPCKSELR, 0, 2),
+ MUX_CFG(MUX_ETH1, ETH1_src, RCC_ETH12CKSELR, 0, 2),
+ MUX_CFG(MUX_ETH2, ETH2_src, RCC_ETH12CKSELR, 8, 2),
+ MUX_CFG(MUX_FDCAN, FDCAN_src, RCC_FDCANCKSELR, 0, 2),
+ MUX_CFG(MUX_FMC, FMC_src, RCC_FMCCKSELR, 0, 2),
+ MUX_CFG(MUX_I2C12, I2C12_src, RCC_I2C12CKSELR, 0, 3),
+ MUX_CFG(MUX_I2C3, I2C3_src, RCC_I2C345CKSELR, 0, 3),
+ MUX_CFG(MUX_I2C4, I2C4_src, RCC_I2C345CKSELR, 3, 3),
+ MUX_CFG(MUX_I2C5, I2C5_src, RCC_I2C345CKSELR, 6, 3),
+ MUX_CFG(MUX_LPTIM1, LPTIM1_src, RCC_LPTIM1CKSELR, 0, 3),
+ MUX_CFG(MUX_LPTIM2, LPTIM2_src, RCC_LPTIM23CKSELR, 0, 3),
+ MUX_CFG(MUX_LPTIM3, LPTIM3_src, RCC_LPTIM23CKSELR, 3, 3),
+ MUX_CFG(MUX_LPTIM45, LPTIM45_src, RCC_LPTIM45CKSELR, 0, 3),
+ MUX_CFG(MUX_MCO1, MCO1_src, RCC_MCO1CFGR, 0, 3),
+ MUX_CFG(MUX_MCO2, MCO2_src, RCC_MCO2CFGR, 0, 3),
+ MUX_RDY_CFG(MUX_MLAHB, MLAHBS_src, RCC_MSSCKSELR, 0, 2),
+ MUX_RDY_CFG(MUX_MPU, MPU_src, RCC_MPCKSELR, 0, 2),
+ MUX_RDY_CFG(MUX_PLL12, PLL12_src, RCC_RCK12SELR, 0, 2),
+ MUX_RDY_CFG(MUX_PLL3, PLL3_src, RCC_RCK3SELR, 0, 2),
+ MUX_RDY_CFG(MUX_PLL4, PLL4_src, RCC_RCK4SELR, 0, 2),
+ MUX_CFG(MUX_QSPI, QSPI_src, RCC_QSPICKSELR, 0, 2),
+ MUX_CFG(MUX_RNG1, RNG1_src, RCC_RNG1CKSELR, 0, 2),
+ MUX_CFG(MUX_RTC, RTC_src, RCC_BDCR, 16, 2),
+ MUX_CFG(MUX_SAES, SAES_src, RCC_SAESCKSELR, 0, 2),
+ MUX_CFG(MUX_SAI1, SAI1_src, RCC_SAI1CKSELR, 0, 3),
+ MUX_CFG(MUX_SAI2, SAI2_src, RCC_SAI2CKSELR, 0, 3),
+ MUX_CFG(MUX_SDMMC1, SDMMC1_src, RCC_SDMMC12CKSELR, 0, 3),
+ MUX_CFG(MUX_SDMMC2, SDMMC2_src, RCC_SDMMC12CKSELR, 3, 3),
+ MUX_CFG(MUX_SPDIF, SPDIF_src, RCC_SPDIFCKSELR, 0, 2),
+ MUX_CFG(MUX_SPI1, SPI1_src, RCC_SPI2S1CKSELR, 0, 3),
+ MUX_CFG(MUX_SPI23, SPI23_src, RCC_SPI2S23CKSELR, 0, 3),
+ MUX_CFG(MUX_SPI4, SPI4_src, RCC_SPI45CKSELR, 0, 3),
+ MUX_CFG(MUX_SPI5, SPI5_src, RCC_SPI45CKSELR, 3, 3),
+ MUX_CFG(MUX_STGEN, STGEN_src, RCC_STGENCKSELR, 0, 2),
+ MUX_CFG(MUX_UART1, UART1_src, RCC_UART12CKSELR, 0, 3),
+ MUX_CFG(MUX_UART2, UART2_src, RCC_UART12CKSELR, 3, 3),
+ MUX_CFG(MUX_UART35, UART35_src, RCC_UART35CKSELR, 0, 3),
+ MUX_CFG(MUX_UART4, UART4_src, RCC_UART4CKSELR, 0, 3),
+ MUX_CFG(MUX_UART6, UART6_src, RCC_UART6CKSELR, 0, 3),
+ MUX_CFG(MUX_UART78, UART78_src, RCC_UART78CKSELR, 0, 3),
+ MUX_CFG(MUX_USBO, USBO_src, RCC_USBCKSELR, 4, 1),
+ MUX_CFG(MUX_USBPHY, USBPHY_src, RCC_USBCKSELR, 0, 2),
+};
+
+/*
+ * GATE CONFIG
+ */
+
+enum enum_gate_cfg {
+ GATE_ZERO, /* reserved for no gate */
+ GATE_LSE,
+ GATE_RTCCK,
+ GATE_LSI,
+ GATE_HSI,
+ GATE_CSI,
+ GATE_HSE,
+ GATE_LSI_RDY,
+ GATE_CSI_RDY,
+ GATE_LSE_RDY,
+ GATE_HSE_RDY,
+ GATE_HSI_RDY,
+ GATE_MCO1,
+ GATE_MCO2,
+ GATE_DBGCK,
+ GATE_TRACECK,
+ GATE_PLL1,
+ GATE_PLL1_DIVP,
+ GATE_PLL1_DIVQ,
+ GATE_PLL1_DIVR,
+ GATE_PLL2,
+ GATE_PLL2_DIVP,
+ GATE_PLL2_DIVQ,
+ GATE_PLL2_DIVR,
+ GATE_PLL3,
+ GATE_PLL3_DIVP,
+ GATE_PLL3_DIVQ,
+ GATE_PLL3_DIVR,
+ GATE_PLL4,
+ GATE_PLL4_DIVP,
+ GATE_PLL4_DIVQ,
+ GATE_PLL4_DIVR,
+ GATE_DDRC1,
+ GATE_DDRC1LP,
+ GATE_DDRPHYC,
+ GATE_DDRPHYCLP,
+ GATE_DDRCAPB,
+ GATE_DDRCAPBLP,
+ GATE_AXIDCG,
+ GATE_DDRPHYCAPB,
+ GATE_DDRPHYCAPBLP,
+ GATE_TIM2,
+ GATE_TIM3,
+ GATE_TIM4,
+ GATE_TIM5,
+ GATE_TIM6,
+ GATE_TIM7,
+ GATE_LPTIM1,
+ GATE_SPI2,
+ GATE_SPI3,
+ GATE_USART3,
+ GATE_UART4,
+ GATE_UART5,
+ GATE_UART7,
+ GATE_UART8,
+ GATE_I2C1,
+ GATE_I2C2,
+ GATE_SPDIF,
+ GATE_TIM1,
+ GATE_TIM8,
+ GATE_SPI1,
+ GATE_USART6,
+ GATE_SAI1,
+ GATE_SAI2,
+ GATE_DFSDM,
+ GATE_ADFSDM,
+ GATE_FDCAN,
+ GATE_LPTIM2,
+ GATE_LPTIM3,
+ GATE_LPTIM4,
+ GATE_LPTIM5,
+ GATE_VREF,
+ GATE_DTS,
+ GATE_PMBCTRL,
+ GATE_HDP,
+ GATE_SYSCFG,
+ GATE_DCMIPP,
+ GATE_DDRPERFM,
+ GATE_IWDG2APB,
+ GATE_USBPHY,
+ GATE_STGENRO,
+ GATE_LTDC,
+ GATE_RTCAPB,
+ GATE_TZC,
+ GATE_ETZPC,
+ GATE_IWDG1APB,
+ GATE_BSEC,
+ GATE_STGENC,
+ GATE_USART1,
+ GATE_USART2,
+ GATE_SPI4,
+ GATE_SPI5,
+ GATE_I2C3,
+ GATE_I2C4,
+ GATE_I2C5,
+ GATE_TIM12,
+ GATE_TIM13,
+ GATE_TIM14,
+ GATE_TIM15,
+ GATE_TIM16,
+ GATE_TIM17,
+ GATE_DMA1,
+ GATE_DMA2,
+ GATE_DMAMUX1,
+ GATE_DMA3,
+ GATE_DMAMUX2,
+ GATE_ADC1,
+ GATE_ADC2,
+ GATE_USBO,
+ GATE_TSC,
+ GATE_GPIOA,
+ GATE_GPIOB,
+ GATE_GPIOC,
+ GATE_GPIOD,
+ GATE_GPIOE,
+ GATE_GPIOF,
+ GATE_GPIOG,
+ GATE_GPIOH,
+ GATE_GPIOI,
+ GATE_PKA,
+ GATE_SAES,
+ GATE_CRYP1,
+ GATE_HASH1,
+ GATE_RNG1,
+ GATE_BKPSRAM,
+ GATE_AXIMC,
+ GATE_MCE,
+ GATE_ETH1CK,
+ GATE_ETH1TX,
+ GATE_ETH1RX,
+ GATE_ETH1MAC,
+ GATE_FMC,
+ GATE_QSPI,
+ GATE_SDMMC1,
+ GATE_SDMMC2,
+ GATE_CRC1,
+ GATE_USBH,
+ GATE_ETH2CK,
+ GATE_ETH2TX,
+ GATE_ETH2RX,
+ GATE_ETH2MAC,
+ GATE_MDMA,
+
+ LAST_GATE
+};
+
+#define GATE_CFG(id, _offset, _bit_idx, _offset_clr)[id] = {\
+ .offset = (_offset),\
+ .bit_idx = (_bit_idx),\
+ .set_clr = (_offset_clr),\
+}
+
+static const struct gate_cfg gates_mp13[LAST_GATE] = {
+ GATE_CFG(GATE_LSE, RCC_BDCR, 0, 0),
+ GATE_CFG(GATE_RTCCK, RCC_BDCR, 20, 0),
+ GATE_CFG(GATE_LSI, RCC_RDLSICR, 0, 0),
+ GATE_CFG(GATE_HSI, RCC_OCENSETR, 0, 1),
+ GATE_CFG(GATE_CSI, RCC_OCENSETR, 4, 1),
+ GATE_CFG(GATE_HSE, RCC_OCENSETR, 8, 1),
+ GATE_CFG(GATE_LSI_RDY, RCC_RDLSICR, 1, 0),
+ GATE_CFG(GATE_CSI_RDY, RCC_OCRDYR, 4, 0),
+ GATE_CFG(GATE_LSE_RDY, RCC_BDCR, 2, 0),
+ GATE_CFG(GATE_HSE_RDY, RCC_OCRDYR, 8, 0),
+ GATE_CFG(GATE_HSI_RDY, RCC_OCRDYR, 0, 0),
+ GATE_CFG(GATE_MCO1, RCC_MCO1CFGR, 12, 0),
+ GATE_CFG(GATE_MCO2, RCC_MCO2CFGR, 12, 0),
+ GATE_CFG(GATE_DBGCK, RCC_DBGCFGR, 8, 0),
+ GATE_CFG(GATE_TRACECK, RCC_DBGCFGR, 9, 0),
+ GATE_CFG(GATE_PLL1, RCC_PLL1CR, 0, 0),
+ GATE_CFG(GATE_PLL1_DIVP, RCC_PLL1CR, 4, 0),
+ GATE_CFG(GATE_PLL1_DIVQ, RCC_PLL1CR, 5, 0),
+ GATE_CFG(GATE_PLL1_DIVR, RCC_PLL1CR, 6, 0),
+ GATE_CFG(GATE_PLL2, RCC_PLL2CR, 0, 0),
+ GATE_CFG(GATE_PLL2_DIVP, RCC_PLL2CR, 4, 0),
+ GATE_CFG(GATE_PLL2_DIVQ, RCC_PLL2CR, 5, 0),
+ GATE_CFG(GATE_PLL2_DIVR, RCC_PLL2CR, 6, 0),
+ GATE_CFG(GATE_PLL3, RCC_PLL3CR, 0, 0),
+ GATE_CFG(GATE_PLL3_DIVP, RCC_PLL3CR, 4, 0),
+ GATE_CFG(GATE_PLL3_DIVQ, RCC_PLL3CR, 5, 0),
+ GATE_CFG(GATE_PLL3_DIVR, RCC_PLL3CR, 6, 0),
+ GATE_CFG(GATE_PLL4, RCC_PLL4CR, 0, 0),
+ GATE_CFG(GATE_PLL4_DIVP, RCC_PLL4CR, 4, 0),
+ GATE_CFG(GATE_PLL4_DIVQ, RCC_PLL4CR, 5, 0),
+ GATE_CFG(GATE_PLL4_DIVR, RCC_PLL4CR, 6, 0),
+ GATE_CFG(GATE_DDRC1, RCC_DDRITFCR, 0, 0),
+ GATE_CFG(GATE_DDRC1LP, RCC_DDRITFCR, 1, 0),
+ GATE_CFG(GATE_DDRPHYC, RCC_DDRITFCR, 4, 0),
+ GATE_CFG(GATE_DDRPHYCLP, RCC_DDRITFCR, 5, 0),
+ GATE_CFG(GATE_DDRCAPB, RCC_DDRITFCR, 6, 0),
+ GATE_CFG(GATE_DDRCAPBLP, RCC_DDRITFCR, 7, 0),
+ GATE_CFG(GATE_AXIDCG, RCC_DDRITFCR, 8, 0),
+ GATE_CFG(GATE_DDRPHYCAPB, RCC_DDRITFCR, 9, 0),
+ GATE_CFG(GATE_DDRPHYCAPBLP, RCC_DDRITFCR, 10, 0),
+ GATE_CFG(GATE_TIM2, RCC_MP_APB1ENSETR, 0, 1),
+ GATE_CFG(GATE_TIM3, RCC_MP_APB1ENSETR, 1, 1),
+ GATE_CFG(GATE_TIM4, RCC_MP_APB1ENSETR, 2, 1),
+ GATE_CFG(GATE_TIM5, RCC_MP_APB1ENSETR, 3, 1),
+ GATE_CFG(GATE_TIM6, RCC_MP_APB1ENSETR, 4, 1),
+ GATE_CFG(GATE_TIM7, RCC_MP_APB1ENSETR, 5, 1),
+ GATE_CFG(GATE_LPTIM1, RCC_MP_APB1ENSETR, 9, 1),
+ GATE_CFG(GATE_SPI2, RCC_MP_APB1ENSETR, 11, 1),
+ GATE_CFG(GATE_SPI3, RCC_MP_APB1ENSETR, 12, 1),
+ GATE_CFG(GATE_USART3, RCC_MP_APB1ENSETR, 15, 1),
+ GATE_CFG(GATE_UART4, RCC_MP_APB1ENSETR, 16, 1),
+ GATE_CFG(GATE_UART5, RCC_MP_APB1ENSETR, 17, 1),
+ GATE_CFG(GATE_UART7, RCC_MP_APB1ENSETR, 18, 1),
+ GATE_CFG(GATE_UART8, RCC_MP_APB1ENSETR, 19, 1),
+ GATE_CFG(GATE_I2C1, RCC_MP_APB1ENSETR, 21, 1),
+ GATE_CFG(GATE_I2C2, RCC_MP_APB1ENSETR, 22, 1),
+ GATE_CFG(GATE_SPDIF, RCC_MP_APB1ENSETR, 26, 1),
+ GATE_CFG(GATE_TIM1, RCC_MP_APB2ENSETR, 0, 1),
+ GATE_CFG(GATE_TIM8, RCC_MP_APB2ENSETR, 1, 1),
+ GATE_CFG(GATE_SPI1, RCC_MP_APB2ENSETR, 8, 1),
+ GATE_CFG(GATE_USART6, RCC_MP_APB2ENSETR, 13, 1),
+ GATE_CFG(GATE_SAI1, RCC_MP_APB2ENSETR, 16, 1),
+ GATE_CFG(GATE_SAI2, RCC_MP_APB2ENSETR, 17, 1),
+ GATE_CFG(GATE_DFSDM, RCC_MP_APB2ENSETR, 20, 1),
+ GATE_CFG(GATE_ADFSDM, RCC_MP_APB2ENSETR, 21, 1),
+ GATE_CFG(GATE_FDCAN, RCC_MP_APB2ENSETR, 24, 1),
+ GATE_CFG(GATE_LPTIM2, RCC_MP_APB3ENSETR, 0, 1),
+ GATE_CFG(GATE_LPTIM3, RCC_MP_APB3ENSETR, 1, 1),
+ GATE_CFG(GATE_LPTIM4, RCC_MP_APB3ENSETR, 2, 1),
+ GATE_CFG(GATE_LPTIM5, RCC_MP_APB3ENSETR, 3, 1),
+ GATE_CFG(GATE_VREF, RCC_MP_APB3ENSETR, 13, 1),
+ GATE_CFG(GATE_DTS, RCC_MP_APB3ENSETR, 16, 1),
+ GATE_CFG(GATE_PMBCTRL, RCC_MP_APB3ENSETR, 17, 1),
+ GATE_CFG(GATE_HDP, RCC_MP_APB3ENSETR, 20, 1),
+ GATE_CFG(GATE_SYSCFG, RCC_MP_S_APB3ENSETR, 0, 1),
+ GATE_CFG(GATE_DCMIPP, RCC_MP_APB4ENSETR, 1, 1),
+ GATE_CFG(GATE_DDRPERFM, RCC_MP_APB4ENSETR, 8, 1),
+ GATE_CFG(GATE_IWDG2APB, RCC_MP_APB4ENSETR, 15, 1),
+ GATE_CFG(GATE_USBPHY, RCC_MP_APB4ENSETR, 16, 1),
+ GATE_CFG(GATE_STGENRO, RCC_MP_APB4ENSETR, 20, 1),
+ GATE_CFG(GATE_LTDC, RCC_MP_S_APB4ENSETR, 0, 1),
+ GATE_CFG(GATE_RTCAPB, RCC_MP_APB5ENSETR, 8, 1),
+ GATE_CFG(GATE_TZC, RCC_MP_APB5ENSETR, 11, 1),
+ GATE_CFG(GATE_ETZPC, RCC_MP_APB5ENSETR, 13, 1),
+ GATE_CFG(GATE_IWDG1APB, RCC_MP_APB5ENSETR, 15, 1),
+ GATE_CFG(GATE_BSEC, RCC_MP_APB5ENSETR, 16, 1),
+ GATE_CFG(GATE_STGENC, RCC_MP_APB5ENSETR, 20, 1),
+ GATE_CFG(GATE_USART1, RCC_MP_APB6ENSETR, 0, 1),
+ GATE_CFG(GATE_USART2, RCC_MP_APB6ENSETR, 1, 1),
+ GATE_CFG(GATE_SPI4, RCC_MP_APB6ENSETR, 2, 1),
+ GATE_CFG(GATE_SPI5, RCC_MP_APB6ENSETR, 3, 1),
+ GATE_CFG(GATE_I2C3, RCC_MP_APB6ENSETR, 4, 1),
+ GATE_CFG(GATE_I2C4, RCC_MP_APB6ENSETR, 5, 1),
+ GATE_CFG(GATE_I2C5, RCC_MP_APB6ENSETR, 6, 1),
+ GATE_CFG(GATE_TIM12, RCC_MP_APB6ENSETR, 7, 1),
+ GATE_CFG(GATE_TIM13, RCC_MP_APB6ENSETR, 8, 1),
+ GATE_CFG(GATE_TIM14, RCC_MP_APB6ENSETR, 9, 1),
+ GATE_CFG(GATE_TIM15, RCC_MP_APB6ENSETR, 10, 1),
+ GATE_CFG(GATE_TIM16, RCC_MP_APB6ENSETR, 11, 1),
+ GATE_CFG(GATE_TIM17, RCC_MP_APB6ENSETR, 12, 1),
+ GATE_CFG(GATE_DMA1, RCC_MP_AHB2ENSETR, 0, 1),
+ GATE_CFG(GATE_DMA2, RCC_MP_AHB2ENSETR, 1, 1),
+ GATE_CFG(GATE_DMAMUX1, RCC_MP_AHB2ENSETR, 2, 1),
+ GATE_CFG(GATE_DMA3, RCC_MP_AHB2ENSETR, 3, 1),
+ GATE_CFG(GATE_DMAMUX2, RCC_MP_AHB2ENSETR, 4, 1),
+ GATE_CFG(GATE_ADC1, RCC_MP_AHB2ENSETR, 5, 1),
+ GATE_CFG(GATE_ADC2, RCC_MP_AHB2ENSETR, 6, 1),
+ GATE_CFG(GATE_USBO, RCC_MP_AHB2ENSETR, 8, 1),
+ GATE_CFG(GATE_TSC, RCC_MP_AHB4ENSETR, 15, 1),
+
+ GATE_CFG(GATE_GPIOA, RCC_MP_S_AHB4ENSETR, 0, 1),
+ GATE_CFG(GATE_GPIOB, RCC_MP_S_AHB4ENSETR, 1, 1),
+ GATE_CFG(GATE_GPIOC, RCC_MP_S_AHB4ENSETR, 2, 1),
+ GATE_CFG(GATE_GPIOD, RCC_MP_S_AHB4ENSETR, 3, 1),
+ GATE_CFG(GATE_GPIOE, RCC_MP_S_AHB4ENSETR, 4, 1),
+ GATE_CFG(GATE_GPIOF, RCC_MP_S_AHB4ENSETR, 5, 1),
+ GATE_CFG(GATE_GPIOG, RCC_MP_S_AHB4ENSETR, 6, 1),
+ GATE_CFG(GATE_GPIOH, RCC_MP_S_AHB4ENSETR, 7, 1),
+ GATE_CFG(GATE_GPIOI, RCC_MP_S_AHB4ENSETR, 8, 1),
+
+ GATE_CFG(GATE_PKA, RCC_MP_AHB5ENSETR, 2, 1),
+ GATE_CFG(GATE_SAES, RCC_MP_AHB5ENSETR, 3, 1),
+ GATE_CFG(GATE_CRYP1, RCC_MP_AHB5ENSETR, 4, 1),
+ GATE_CFG(GATE_HASH1, RCC_MP_AHB5ENSETR, 5, 1),
+ GATE_CFG(GATE_RNG1, RCC_MP_AHB5ENSETR, 6, 1),
+ GATE_CFG(GATE_BKPSRAM, RCC_MP_AHB5ENSETR, 8, 1),
+ GATE_CFG(GATE_AXIMC, RCC_MP_AHB5ENSETR, 16, 1),
+ GATE_CFG(GATE_MCE, RCC_MP_AHB6ENSETR, 1, 1),
+ GATE_CFG(GATE_ETH1CK, RCC_MP_AHB6ENSETR, 7, 1),
+ GATE_CFG(GATE_ETH1TX, RCC_MP_AHB6ENSETR, 8, 1),
+ GATE_CFG(GATE_ETH1RX, RCC_MP_AHB6ENSETR, 9, 1),
+ GATE_CFG(GATE_ETH1MAC, RCC_MP_AHB6ENSETR, 10, 1),
+ GATE_CFG(GATE_FMC, RCC_MP_AHB6ENSETR, 12, 1),
+ GATE_CFG(GATE_QSPI, RCC_MP_AHB6ENSETR, 14, 1),
+ GATE_CFG(GATE_SDMMC1, RCC_MP_AHB6ENSETR, 16, 1),
+ GATE_CFG(GATE_SDMMC2, RCC_MP_AHB6ENSETR, 17, 1),
+ GATE_CFG(GATE_CRC1, RCC_MP_AHB6ENSETR, 20, 1),
+ GATE_CFG(GATE_USBH, RCC_MP_AHB6ENSETR, 24, 1),
+ GATE_CFG(GATE_ETH2CK, RCC_MP_AHB6ENSETR, 27, 1),
+ GATE_CFG(GATE_ETH2TX, RCC_MP_AHB6ENSETR, 28, 1),
+ GATE_CFG(GATE_ETH2RX, RCC_MP_AHB6ENSETR, 29, 1),
+ GATE_CFG(GATE_ETH2MAC, RCC_MP_AHB6ENSETR, 30, 1),
+ GATE_CFG(GATE_MDMA, RCC_MP_S_AHB6ENSETR, 0, 1),
+};
+
+/*
+ * DIV CONFIG
+ */
+
+static const struct clk_div_table axi_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+ { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 },
+ { 0 },
+};
+
+static const struct clk_div_table mlahb_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 },
+ { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 },
+ { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 },
+ { 0 },
+};
+
+static const struct clk_div_table apb_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 },
+ { 0 },
+};
+
+#define DIV_CFG(id, _offset, _shift, _width, _flags, _table, _bitrdy)[id] = {\
+ .offset = _offset,\
+ .shift = _shift,\
+ .width = _width,\
+ .flags = _flags,\
+ .table = _table,\
+ .bitrdy = _bitrdy,\
+}
+
+static const struct div_cfg dividers_mp13[DIV_MAX] = {
+ DIV_CFG(DIV_PLL1DIVP, RCC_PLL1CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL2DIVP, RCC_PLL2CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL2DIVQ, RCC_PLL2CFGR2, 8, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL2DIVR, RCC_PLL2CFGR2, 16, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL3DIVP, RCC_PLL3CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL3DIVQ, RCC_PLL3CFGR2, 8, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL3DIVR, RCC_PLL3CFGR2, 16, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL4DIVP, RCC_PLL4CFGR2, 0, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL4DIVQ, RCC_PLL4CFGR2, 8, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_PLL4DIVR, RCC_PLL4CFGR2, 16, 7, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_MPU, RCC_MPCKDIVR, 0, 4, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_AXI, RCC_AXIDIVR, 0, 3, 0, axi_div_table, 31),
+ DIV_CFG(DIV_MLAHB, RCC_MLAHBDIVR, 0, 4, 0, mlahb_div_table, 31),
+ DIV_CFG(DIV_APB1, RCC_APB1DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB2, RCC_APB2DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB3, RCC_APB3DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB4, RCC_APB4DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB5, RCC_APB5DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_APB6, RCC_APB6DIVR, 0, 3, 0, apb_div_table, 31),
+ DIV_CFG(DIV_RTC, RCC_RTCDIVR, 0, 6, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_MCO1, RCC_MCO1CFGR, 4, 4, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_MCO2, RCC_MCO2CFGR, 4, 4, 0, NULL, DIV_NO_BIT_RDY),
+
+ DIV_CFG(DIV_HSI, RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_TRACE, RCC_DBGCFGR, 0, 3, CLK_DIVIDER_POWER_OF_TWO, NULL, DIV_NO_BIT_RDY),
+
+ DIV_CFG(DIV_ETH1PTP, RCC_ETH12CKSELR, 4, 4, 0, NULL, DIV_NO_BIT_RDY),
+ DIV_CFG(DIV_ETH2PTP, RCC_ETH12CKSELR, 12, 4, 0, NULL, DIV_NO_BIT_RDY),
+};
+
+#define MAX_HSI_HZ 64000000
+#define USB_PHY_48_MHZ 48000000
+
+#define TIMEOUT_US_200MS U(200000)
+#define TIMEOUT_US_1S U(1000000)
+
+#define PLLRDY_TIMEOUT TIMEOUT_US_200MS
+#define CLKSRC_TIMEOUT TIMEOUT_US_200MS
+#define CLKDIV_TIMEOUT TIMEOUT_US_200MS
+#define HSIDIV_TIMEOUT TIMEOUT_US_200MS
+#define OSCRDY_TIMEOUT TIMEOUT_US_1S
+
+enum stm32_osc {
+ OSC_HSI,
+ OSC_HSE,
+ OSC_CSI,
+ OSC_LSI,
+ OSC_LSE,
+ OSC_I2SCKIN,
+ NB_OSCILLATOR
+};
+
+enum stm32mp1_pll_id {
+ _PLL1,
+ _PLL2,
+ _PLL3,
+ _PLL4,
+ _PLL_NB
+};
+
+enum stm32mp1_plltype {
+ PLL_800,
+ PLL_1600,
+ PLL_2000,
+ PLL_TYPE_NB
+};
+
+#define RCC_OFFSET_PLLXCR 0
+#define RCC_OFFSET_PLLXCFGR1 4
+#define RCC_OFFSET_PLLXCFGR2 8
+#define RCC_OFFSET_PLLXFRACR 12
+#define RCC_OFFSET_PLLXCSGR 16
+
+struct stm32_clk_pll {
+ enum stm32mp1_plltype plltype;
+ uint16_t clk_id;
+ uint16_t reg_pllxcr;
+};
+
+struct stm32mp1_pll {
+ uint8_t refclk_min;
+ uint8_t refclk_max;
+};
+
+/* Define characteristic of PLL according type */
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+ [PLL_800] = {
+ .refclk_min = 4,
+ .refclk_max = 16,
+ },
+ [PLL_1600] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ },
+ [PLL_2000] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ },
+};
+
+#if STM32MP_USB_PROGRAMMER
+static bool pll4_bootrom;
+#endif
+
+/* RCC clock device driver private */
+static unsigned int refcounts_mp13[CK_LAST];
+
+static const struct stm32_clk_pll *clk_st32_pll_data(unsigned int idx);
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+static void clk_oscillator_check_bypass(struct stm32_clk_priv *priv, int idx,
+ bool digbyp, bool bypass)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, idx);
+ struct stm32_clk_bypass *bypass_data = osc_data->bypass;
+ uintptr_t address;
+
+ if (bypass_data == NULL) {
+ return;
+ }
+
+ address = priv->base + bypass_data->offset;
+ if ((mmio_read_32(address) & RCC_OCENR_HSEBYP) &&
+ (!(digbyp || bypass))) {
+ panic();
+ }
+}
+#endif
+
+static void stm32_enable_oscillator_hse(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ struct stm32_osci_dt_cfg *osci = &pdata->osci[OSC_HSE];
+ bool digbyp = osci->digbyp;
+ bool bypass = osci->bypass;
+ bool css = osci->css;
+
+ if (_clk_stm32_get_rate(priv, _CK_HSE) == 0U) {
+ return;
+ }
+
+ clk_oscillator_set_bypass(priv, _CK_HSE, digbyp, bypass);
+
+ _clk_stm32_enable(priv, _CK_HSE);
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+ clk_oscillator_check_bypass(priv, _CK_HSE, digbyp, bypass);
+#endif
+
+ clk_oscillator_set_css(priv, _CK_HSE, css);
+}
+
+static void stm32_enable_oscillator_lse(struct stm32_clk_priv *priv)
+{
+ struct clk_oscillator_data *osc_data = clk_oscillator_get_data(priv, _CK_LSE);
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ struct stm32_osci_dt_cfg *osci = &pdata->osci[OSC_LSE];
+ bool digbyp = osci->digbyp;
+ bool bypass = osci->bypass;
+ uint8_t drive = osci->drive;
+
+ if (_clk_stm32_get_rate(priv, _CK_LSE) == 0U) {
+ return;
+ }
+
+ clk_oscillator_set_bypass(priv, _CK_LSE, digbyp, bypass);
+
+ clk_oscillator_set_drive(priv, _CK_LSE, drive);
+
+ _clk_stm32_gate_enable(priv, osc_data->gate_id);
+}
+
+static int stm32mp1_set_hsidiv(uint8_t hsidiv)
+{
+ uint64_t timeout;
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uintptr_t address = rcc_base + RCC_OCRDYR;
+
+ mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
+ RCC_HSICFGR_HSIDIV_MASK,
+ RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
+
+ timeout = timeout_init_us(HSIDIV_TIMEOUT);
+ while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
+ address, mmio_read_32(address));
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32mp1_hsidiv(unsigned long hsifreq)
+{
+ uint8_t hsidiv;
+ uint32_t hsidivfreq = MAX_HSI_HZ;
+
+ for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
+ if (hsidivfreq == hsifreq) {
+ break;
+ }
+
+ hsidivfreq /= 2U;
+ }
+
+ if (hsidiv == 4U) {
+ ERROR("Invalid clk-hsi frequency\n");
+ return -EINVAL;
+ }
+
+ if (hsidiv != 0U) {
+ return stm32mp1_set_hsidiv(hsidiv);
+ }
+
+ return 0;
+}
+
+static int stm32_clk_oscillators_lse_set_css(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ struct stm32_osci_dt_cfg *osci = &pdata->osci[OSC_LSE];
+
+ clk_oscillator_set_css(priv, _CK_LSE, osci->css);
+
+ return 0;
+}
+
+static int stm32mp1_come_back_to_hsi(void)
+{
+ int ret;
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+
+ /* Come back to HSI */
+ ret = _clk_stm32_set_parent(priv, _CKMPU, _CK_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = _clk_stm32_set_parent(priv, _CKAXI, _CK_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = _clk_stm32_set_parent(priv, _CKMLAHB, _CK_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_configure_clk_get_binding_id(struct stm32_clk_priv *priv, uint32_t data)
+{
+ unsigned long binding_id = ((unsigned long)data & CLK_ID_MASK) >> CLK_ID_SHIFT;
+
+ return clk_get_index(priv, binding_id);
+}
+
+static int stm32_clk_configure_clk(struct stm32_clk_priv *priv, uint32_t data)
+{
+ int sel = (data & CLK_SEL_MASK) >> CLK_SEL_SHIFT;
+ int enable = (data & CLK_ON_MASK) >> CLK_ON_SHIFT;
+ int clk_id;
+ int ret;
+
+ clk_id = stm32_clk_configure_clk_get_binding_id(priv, data);
+ if (clk_id < 0) {
+ return clk_id;
+ }
+
+ ret = _clk_stm32_set_parent_by_index(priv, clk_id, sel);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (enable != 0) {
+ clk_stm32_enable_call_ops(priv, clk_id);
+ } else {
+ clk_stm32_disable_call_ops(priv, clk_id);
+ }
+
+ return 0;
+}
+
+static int stm32_clk_configure_mux(struct stm32_clk_priv *priv, uint32_t data)
+{
+ int mux = (data & MUX_ID_MASK) >> MUX_ID_SHIFT;
+ int sel = (data & MUX_SEL_MASK) >> MUX_SEL_SHIFT;
+
+ return clk_mux_set_parent(priv, mux, sel);
+}
+
+static int stm32_clk_dividers_configure(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ uint32_t i;
+
+ for (i = 0; i < pdata->nclkdiv; i++) {
+ int div_id, div_n;
+ int val;
+ int ret;
+
+ val = pdata->clkdiv[i] & CMD_DATA_MASK;
+ div_id = (val & DIV_ID_MASK) >> DIV_ID_SHIFT;
+ div_n = (val & DIV_DIVN_MASK) >> DIV_DIVN_SHIFT;
+
+ ret = clk_stm32_set_div(priv, div_id, div_n);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_clk_source_configure(struct stm32_clk_priv *priv)
+{
+ struct stm32_clk_platdata *pdata = priv->pdata;
+ bool ckper_disabled = false;
+ int clk_id;
+ int ret;
+ uint32_t i;
+
+ for (i = 0; i < pdata->nclksrc; i++) {
+ uint32_t val = pdata->clksrc[i];
+ uint32_t cmd, cmd_data;
+
+ if (val == (uint32_t)CLK_CKPER_DISABLED) {
+ ckper_disabled = true;
+ continue;
+ }
+
+ if (val == (uint32_t)CLK_RTC_DISABLED) {
+ continue;
+ }
+
+ cmd = (val & CMD_MASK) >> CMD_SHIFT;
+ cmd_data = val & ~CMD_MASK;
+
+ switch (cmd) {
+ case CMD_MUX:
+ ret = stm32_clk_configure_mux(priv, cmd_data);
+ break;
+
+ case CMD_CLK:
+ clk_id = stm32_clk_configure_clk_get_binding_id(priv, cmd_data);
+
+ if (clk_id == _RTCCK) {
+ if ((_clk_stm32_is_enabled(priv, _RTCCK) == true)) {
+ continue;
+ }
+ }
+
+ ret = stm32_clk_configure_clk(priv, cmd_data);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /*
+ * CKPER is source for some peripheral clocks
+ * (FMC-NAND / QPSI-NOR) and switching source is allowed
+ * only if previous clock is still ON
+ * => deactivate CKPER only after switching clock
+ */
+ if (ckper_disabled) {
+ ret = stm32_clk_configure_mux(priv, CLK_CKPER_DISABLED);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_clk_stgen_configure(struct stm32_clk_priv *priv, int id)
+{
+ unsigned long stgen_freq;
+
+ stgen_freq = _clk_stm32_get_rate(priv, id);
+
+ stm32mp_stgen_config(stgen_freq);
+
+ return 0;
+}
+
+#define CLK_PLL_CFG(_idx, _clk_id, _type, _reg)\
+ [(_idx)] = {\
+ .clk_id = (_clk_id),\
+ .plltype = (_type),\
+ .reg_pllxcr = (_reg),\
+ }
+
+static int clk_stm32_pll_compute_cfgr1(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll,
+ struct stm32_pll_vco *vco,
+ uint32_t *value)
+{
+ uint32_t divm = vco->div_mn[PLL_CFG_M];
+ uint32_t divn = vco->div_mn[PLL_CFG_N];
+ unsigned long prate = 0UL;
+ unsigned long refclk = 0UL;
+
+ prate = _clk_stm32_get_parent_rate(priv, pll->clk_id);
+ refclk = prate / (divm + 1U);
+
+ if ((refclk < (stm32mp1_pll[pll->plltype].refclk_min * 1000000U)) ||
+ (refclk > (stm32mp1_pll[pll->plltype].refclk_max * 1000000U))) {
+ return -EINVAL;
+ }
+
+ *value = 0;
+
+ if ((pll->plltype == PLL_800) && (refclk >= 8000000U)) {
+ *value = 1U << RCC_PLLNCFGR1_IFRGE_SHIFT;
+ }
+
+ *value |= (divn << RCC_PLLNCFGR1_DIVN_SHIFT) & RCC_PLLNCFGR1_DIVN_MASK;
+ *value |= (divm << RCC_PLLNCFGR1_DIVM_SHIFT) & RCC_PLLNCFGR1_DIVM_MASK;
+
+ return 0;
+}
+
+static uint32_t clk_stm32_pll_compute_cfgr2(struct stm32_pll_output *out)
+{
+ uint32_t value = 0;
+
+ value |= (out->output[PLL_CFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & RCC_PLLNCFGR2_DIVP_MASK;
+ value |= (out->output[PLL_CFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & RCC_PLLNCFGR2_DIVQ_MASK;
+ value |= (out->output[PLL_CFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & RCC_PLLNCFGR2_DIVR_MASK;
+
+ return value;
+}
+
+static void clk_stm32_pll_config_vco(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll,
+ struct stm32_pll_vco *vco)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t value = 0;
+
+ if (clk_stm32_pll_compute_cfgr1(priv, pll, vco, &value) != 0) {
+ ERROR("Invalid Vref clock !\n");
+ panic();
+ }
+
+ /* Write N / M / IFREGE fields */
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXCFGR1, value);
+
+ /* Fractional configuration */
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXFRACR, 0);
+
+ /* Frac must be enabled only once its configuration is loaded */
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXFRACR, vco->frac << RCC_PLLNFRACR_FRACV_SHIFT);
+ mmio_setbits_32(pll_base + RCC_OFFSET_PLLXFRACR, RCC_PLLNFRACR_FRACLE);
+}
+
+static void clk_stm32_pll_config_csg(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll,
+ struct stm32_pll_vco *vco)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t mod_per = 0;
+ uint32_t inc_step = 0;
+ uint32_t sscg_mode = 0;
+ uint32_t value = 0;
+
+ if (!vco->csg_enabled) {
+ return;
+ }
+
+ mod_per = vco->csg[PLL_CSG_MOD_PER];
+ inc_step = vco->csg[PLL_CSG_INC_STEP];
+ sscg_mode = vco->csg[PLL_CSG_SSCG_MODE];
+
+ value |= (mod_per << RCC_PLLNCSGR_MOD_PER_SHIFT) & RCC_PLLNCSGR_MOD_PER_MASK;
+ value |= (inc_step << RCC_PLLNCSGR_INC_STEP_SHIFT) & RCC_PLLNCSGR_INC_STEP_MASK;
+ value |= (sscg_mode << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & RCC_PLLNCSGR_SSCG_MODE_MASK;
+
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXCSGR, value);
+ mmio_setbits_32(pll_base + RCC_OFFSET_PLLXCR, RCC_PLLNCR_SSCG_CTRL);
+}
+
+static void clk_stm32_pll_config_out(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll,
+ struct stm32_pll_output *out)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t value = 0;
+
+ value = clk_stm32_pll_compute_cfgr2(out);
+
+ mmio_write_32(pll_base + RCC_OFFSET_PLLXCFGR2, value);
+}
+
+static inline struct stm32_pll_dt_cfg *clk_stm32_pll_get_pdata(int pll_idx)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ struct stm32_clk_platdata *pdata = priv->pdata;
+
+ return &pdata->pll[pll_idx];
+}
+
+static bool _clk_stm32_pll_is_enabled(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+
+ return ((mmio_read_32(pll_base) & RCC_PLLNCR_PLLON) != 0U);
+}
+
+static void _clk_stm32_pll_set_on(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+
+ /* Preserve RCC_PLLNCR_SSCG_CTRL value */
+ mmio_clrsetbits_32(pll_base, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN,
+ RCC_PLLNCR_PLLON);
+}
+
+static void _clk_stm32_pll_set_off(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+
+ /* Stop all output */
+ mmio_clrbits_32(pll_base, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ /* Stop PLL */
+ mmio_clrbits_32(pll_base, RCC_PLLNCR_PLLON);
+}
+
+static int _clk_stm32_pll_wait_ready_on(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
+
+ /* Wait PLL lock */
+ while ((mmio_read_32(pll_base) & RCC_PLLNCR_PLLRDY) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%d clock start failed @ 0x%x: 0x%x\n",
+ pll->clk_id, pll->reg_pllxcr, mmio_read_32(pll_base));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int _clk_stm32_pll_wait_ready_off(struct stm32_clk_priv *priv,
+ const struct stm32_clk_pll *pll)
+{
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
+
+ /* Wait PLL lock */
+ while ((mmio_read_32(pll_base) & RCC_PLLNCR_PLLRDY) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%d clock stop failed @ 0x%x: 0x%x\n",
+ pll->clk_id, pll->reg_pllxcr, mmio_read_32(pll_base));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int _clk_stm32_pll_enable(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ if (_clk_stm32_pll_is_enabled(priv, pll)) {
+ return 0;
+ }
+
+ /* Preserve RCC_PLLNCR_SSCG_CTRL value */
+ _clk_stm32_pll_set_on(priv, pll);
+
+ /* Wait PLL lock */
+ return _clk_stm32_pll_wait_ready_on(priv, pll);
+}
+
+static void _clk_stm32_pll_disable(struct stm32_clk_priv *priv, const struct stm32_clk_pll *pll)
+{
+ if (!_clk_stm32_pll_is_enabled(priv, pll)) {
+ return;
+ }
+
+ /* Stop all outputs and the PLL */
+ _clk_stm32_pll_set_off(priv, pll);
+
+ /* Wait PLL stopped */
+ _clk_stm32_pll_wait_ready_off(priv, pll);
+}
+
+static int _clk_stm32_pll_init(struct stm32_clk_priv *priv, int pll_idx,
+ struct stm32_pll_dt_cfg *pll_conf)
+{
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_idx);
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ int ret = 0;
+
+ /* Configure PLLs source */
+ ret = stm32_clk_configure_mux(priv, pll_conf->vco.src);
+ if (ret != 0) {
+ return ret;
+ }
+
+#if STM32MP_USB_PROGRAMMER
+ if ((pll_idx == _PLL4) && pll4_bootrom) {
+ clk_stm32_pll_config_out(priv, pll, &pll_conf->output);
+
+ mmio_setbits_32(pll_base,
+ RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ return 0;
+ }
+#endif
+ /* Stop the PLL before */
+ _clk_stm32_pll_disable(priv, pll);
+
+ clk_stm32_pll_config_vco(priv, pll, &pll_conf->vco);
+ clk_stm32_pll_config_out(priv, pll, &pll_conf->output);
+ clk_stm32_pll_config_csg(priv, pll, &pll_conf->vco);
+
+ ret = _clk_stm32_pll_enable(priv, pll);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_setbits_32(pll_base, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ return 0;
+}
+
+static int clk_stm32_pll_init(struct stm32_clk_priv *priv, int pll_idx)
+{
+ struct stm32_pll_dt_cfg *pll_conf = clk_stm32_pll_get_pdata(pll_idx);
+
+ if (pll_conf->vco.status != 0U) {
+ return _clk_stm32_pll_init(priv, pll_idx, pll_conf);
+ }
+
+ return 0;
+}
+
+static int stm32_clk_pll_configure(struct stm32_clk_priv *priv)
+{
+ int err = 0;
+
+ err = clk_stm32_pll_init(priv, _PLL1);
+ if (err != 0) {
+ return err;
+ }
+
+ err = clk_stm32_pll_init(priv, _PLL2);
+ if (err != 0) {
+ return err;
+ }
+
+ err = clk_stm32_pll_init(priv, _PLL3);
+ if (err != 0) {
+ return err;
+ }
+
+ err = clk_stm32_pll_init(priv, _PLL4);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_oscillators_wait_lse_ready(struct stm32_clk_priv *priv)
+{
+ int ret = 0;
+
+ if (_clk_stm32_get_rate(priv, _CK_LSE) != 0U) {
+ ret = clk_oscillator_wait_ready_on(priv, _CK_LSE);
+ }
+
+ return ret;
+}
+
+static void stm32_clk_oscillators_enable(struct stm32_clk_priv *priv)
+{
+ stm32_enable_oscillator_hse(priv);
+ stm32_enable_oscillator_lse(priv);
+ _clk_stm32_enable(priv, _CK_LSI);
+ _clk_stm32_enable(priv, _CK_CSI);
+}
+
+static int stm32_clk_hsidiv_configure(struct stm32_clk_priv *priv)
+{
+ return stm32mp1_hsidiv(_clk_stm32_get_rate(priv, _CK_HSI));
+}
+
+#if STM32MP_USB_PROGRAMMER
+static bool stm32mp1_clk_is_pll4_used_by_bootrom(struct stm32_clk_priv *priv, int usbphy_p)
+{
+ /* Don't initialize PLL4, when used by BOOTROM */
+ if ((stm32mp_get_boot_itf_selected() ==
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
+ (usbphy_p == _PLL4R)) {
+ return true;
+ }
+
+ return false;
+}
+
+static int stm32mp1_clk_check_usb_conflict(struct stm32_clk_priv *priv, int usbphy_p, int usbo_p)
+{
+ int _usbo_p;
+ int _usbphy_p;
+
+ if (!pll4_bootrom) {
+ return 0;
+ }
+
+ _usbo_p = _clk_stm32_get_parent(priv, _USBO_K);
+ _usbphy_p = _clk_stm32_get_parent(priv, _USBPHY_K);
+
+ if ((_usbo_p != usbo_p) || (_usbphy_p != usbphy_p)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ return 0;
+}
+#endif
+
+static struct clk_oscillator_data stm32mp13_osc_data[NB_OSCILLATOR] = {
+ OSCILLATOR(OSC_HSI, _CK_HSI, "clk-hsi", GATE_HSI, GATE_HSI_RDY,
+ NULL, NULL, NULL),
+
+ OSCILLATOR(OSC_LSI, _CK_LSI, "clk-lsi", GATE_LSI, GATE_LSI_RDY,
+ NULL, NULL, NULL),
+
+ OSCILLATOR(OSC_CSI, _CK_CSI, "clk-csi", GATE_CSI, GATE_CSI_RDY,
+ NULL, NULL, NULL),
+
+ OSCILLATOR(OSC_LSE, _CK_LSE, "clk-lse", GATE_LSE, GATE_LSE_RDY,
+ BYPASS(RCC_BDCR, 1, 3),
+ CSS(RCC_BDCR, 8),
+ DRIVE(RCC_BDCR, 4, 2, 2)),
+
+ OSCILLATOR(OSC_HSE, _CK_HSE, "clk-hse", GATE_HSE, GATE_HSE_RDY,
+ BYPASS(RCC_OCENSETR, 10, 7),
+ CSS(RCC_OCENSETR, 11),
+ NULL),
+
+ OSCILLATOR(OSC_I2SCKIN, _I2SCKIN, "i2s_ckin", NO_GATE, NO_GATE,
+ NULL, NULL, NULL),
+};
+
+static const char *clk_stm32_get_oscillator_name(enum stm32_osc id)
+{
+ if (id < NB_OSCILLATOR) {
+ return stm32mp13_osc_data[id].name;
+ }
+
+ return NULL;
+}
+
+#define CLK_PLL_CFG(_idx, _clk_id, _type, _reg)\
+ [(_idx)] = {\
+ .clk_id = (_clk_id),\
+ .plltype = (_type),\
+ .reg_pllxcr = (_reg),\
+ }
+
+static const struct stm32_clk_pll stm32_mp13_clk_pll[_PLL_NB] = {
+ CLK_PLL_CFG(_PLL1, _CK_PLL1, PLL_2000, RCC_PLL1CR),
+ CLK_PLL_CFG(_PLL2, _CK_PLL2, PLL_1600, RCC_PLL2CR),
+ CLK_PLL_CFG(_PLL3, _CK_PLL3, PLL_800, RCC_PLL3CR),
+ CLK_PLL_CFG(_PLL4, _CK_PLL4, PLL_800, RCC_PLL4CR),
+};
+
+static const struct stm32_clk_pll *clk_st32_pll_data(unsigned int idx)
+{
+ return &stm32_mp13_clk_pll[idx];
+}
+
+struct stm32_pll_cfg {
+ int pll_id;
+};
+
+static unsigned long clk_stm32_pll_recalc_rate(struct stm32_clk_priv *priv, int id,
+ unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+ uintptr_t pll_base = priv->base + pll->reg_pllxcr;
+ uint32_t cfgr1, fracr, divm, divn;
+ unsigned long fvco;
+
+ cfgr1 = mmio_read_32(pll_base + RCC_OFFSET_PLLXCFGR1);
+ fracr = mmio_read_32(pll_base + RCC_OFFSET_PLLXFRACR);
+
+ divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
+ divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
+
+ /*
+ * With FRACV :
+ * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
+ * Without FRACV
+ * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
+ */
+ if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
+ uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
+ RCC_PLLNFRACR_FRACV_SHIFT;
+ unsigned long long numerator, denominator;
+
+ numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
+ numerator = prate * numerator;
+ denominator = ((unsigned long long)divm + 1U) << 13;
+ fvco = (unsigned long)(numerator / denominator);
+ } else {
+ fvco = (unsigned long)(prate * (divn + 1U) / (divm + 1U));
+ }
+
+ return fvco;
+};
+
+static bool clk_stm32_pll_is_enabled(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+
+ return _clk_stm32_pll_is_enabled(priv, pll);
+}
+
+static int clk_stm32_pll_enable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+
+ return _clk_stm32_pll_enable(priv, pll);
+}
+
+static void clk_stm32_pll_disable(struct stm32_clk_priv *priv, int id)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, id);
+ struct stm32_pll_cfg *pll_cfg = clk->clock_cfg;
+ const struct stm32_clk_pll *pll = clk_st32_pll_data(pll_cfg->pll_id);
+
+ _clk_stm32_pll_disable(priv, pll);
+}
+
+static const struct stm32_clk_ops clk_stm32_pll_ops = {
+ .recalc_rate = clk_stm32_pll_recalc_rate,
+ .enable = clk_stm32_pll_enable,
+ .disable = clk_stm32_pll_disable,
+ .is_enabled = clk_stm32_pll_is_enabled,
+};
+
+#define CLK_PLL(idx, _idx, _parent, _gate, _pll_id, _flags)[idx] = {\
+ .binding = _idx,\
+ .parent = _parent,\
+ .flags = (_flags),\
+ .clock_cfg = &(struct stm32_pll_cfg) {\
+ .pll_id = _pll_id,\
+ },\
+ .ops = &clk_stm32_pll_ops,\
+}
+
+struct clk_stm32_composite_cfg {
+ int gate_id;
+ int div_id;
+};
+
+static unsigned long clk_stm32_composite_recalc_rate(struct stm32_clk_priv *priv,
+ int idx, unsigned long prate)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ return _clk_stm32_divider_recalc(priv, composite_cfg->div_id, prate);
+};
+
+static bool clk_stm32_composite_gate_is_enabled(struct stm32_clk_priv *priv, int idx)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ return _clk_stm32_gate_is_enabled(priv, composite_cfg->gate_id);
+}
+
+static int clk_stm32_composite_gate_enable(struct stm32_clk_priv *priv, int idx)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ return _clk_stm32_gate_enable(priv, composite_cfg->gate_id);
+}
+
+static void clk_stm32_composite_gate_disable(struct stm32_clk_priv *priv, int idx)
+{
+ const struct clk_stm32 *clk = _clk_get(priv, idx);
+ struct clk_stm32_composite_cfg *composite_cfg = clk->clock_cfg;
+
+ _clk_stm32_gate_disable(priv, composite_cfg->gate_id);
+}
+
+static const struct stm32_clk_ops clk_stm32_composite_ops = {
+ .recalc_rate = clk_stm32_composite_recalc_rate,
+ .is_enabled = clk_stm32_composite_gate_is_enabled,
+ .enable = clk_stm32_composite_gate_enable,
+ .disable = clk_stm32_composite_gate_disable,
+};
+
+#define STM32_COMPOSITE(idx, _binding, _parent, _flags, _gate_id,\
+ _div_id)[idx] = {\
+ .binding = (_binding),\
+ .parent = (_parent),\
+ .flags = (_flags),\
+ .clock_cfg = &(struct clk_stm32_composite_cfg) {\
+ .gate_id = (_gate_id),\
+ .div_id = (_div_id),\
+ },\
+ .ops = &clk_stm32_composite_ops,\
+}
+
+static const struct clk_stm32 stm32mp13_clk[CK_LAST] = {
+ /* ROOT CLOCKS */
+ CLK_FIXED_RATE(_CK_OFF, _NO_ID, 0),
+ CLK_OSC(_CK_HSE, CK_HSE, CLK_IS_ROOT, OSC_HSE),
+ CLK_OSC(_CK_HSI, CK_HSI, CLK_IS_ROOT, OSC_HSI),
+ CLK_OSC(_CK_CSI, CK_CSI, CLK_IS_ROOT, OSC_CSI),
+ CLK_OSC(_CK_LSI, CK_LSI, CLK_IS_ROOT, OSC_LSI),
+ CLK_OSC(_CK_LSE, CK_LSE, CLK_IS_ROOT, OSC_LSE),
+
+ CLK_OSC_FIXED(_I2SCKIN, _NO_ID, CLK_IS_ROOT, OSC_I2SCKIN),
+
+ CLK_FIXED_RATE(_USB_PHY_48, _NO_ID, USB_PHY_48_MHZ),
+
+ STM32_DIV(_HSE_DIV, _NO_ID, _CK_HSE, 0, DIV_RTC),
+
+ FIXED_FACTOR(_HSE_DIV2, CK_HSE_DIV2, _CK_HSE, 1, 2),
+ FIXED_FACTOR(_CSI_DIV122, _NO_ID, _CK_CSI, 1, 122),
+
+ CLK_PLL(_CK_PLL1, PLL1, MUX(MUX_PLL12), GATE_PLL1, _PLL1, 0),
+ CLK_PLL(_CK_PLL2, PLL2, MUX(MUX_PLL12), GATE_PLL2, _PLL2, 0),
+ CLK_PLL(_CK_PLL3, PLL3, MUX(MUX_PLL3), GATE_PLL3, _PLL3, 0),
+ CLK_PLL(_CK_PLL4, PLL4, MUX(MUX_PLL4), GATE_PLL4, _PLL4, 0),
+
+ STM32_COMPOSITE(_PLL1P, PLL1_P, _CK_PLL1, CLK_IS_CRITICAL, GATE_PLL1_DIVP, DIV_PLL1DIVP),
+ STM32_DIV(_PLL1P_DIV, _NO_ID, _CK_PLL1, 0, DIV_MPU),
+
+ STM32_COMPOSITE(_PLL2P, PLL2_P, _CK_PLL2, CLK_IS_CRITICAL, GATE_PLL2_DIVP, DIV_PLL2DIVP),
+ STM32_COMPOSITE(_PLL2Q, PLL2_Q, _CK_PLL2, 0, GATE_PLL2_DIVQ, DIV_PLL2DIVQ),
+ STM32_COMPOSITE(_PLL2R, PLL2_R, _CK_PLL2, CLK_IS_CRITICAL, GATE_PLL2_DIVR, DIV_PLL2DIVR),
+
+ STM32_COMPOSITE(_PLL3P, PLL3_P, _CK_PLL3, 0, GATE_PLL3_DIVP, DIV_PLL3DIVP),
+ STM32_COMPOSITE(_PLL3Q, PLL3_Q, _CK_PLL3, 0, GATE_PLL3_DIVQ, DIV_PLL3DIVQ),
+ STM32_COMPOSITE(_PLL3R, PLL3_R, _CK_PLL3, 0, GATE_PLL3_DIVR, DIV_PLL3DIVR),
+
+ STM32_COMPOSITE(_PLL4P, PLL4_P, _CK_PLL4, 0, GATE_PLL4_DIVP, DIV_PLL4DIVP),
+ STM32_COMPOSITE(_PLL4Q, PLL4_Q, _CK_PLL4, 0, GATE_PLL4_DIVQ, DIV_PLL4DIVQ),
+ STM32_COMPOSITE(_PLL4R, PLL4_R, _CK_PLL4, 0, GATE_PLL4_DIVR, DIV_PLL4DIVR),
+
+ STM32_MUX(_CKMPU, CK_MPU, MUX_MPU, 0),
+ STM32_DIV(_CKAXI, CK_AXI, MUX(MUX_AXI), 0, DIV_AXI),
+ STM32_DIV(_CKMLAHB, CK_MLAHB, MUX(MUX_MLAHB), CLK_IS_CRITICAL, DIV_MLAHB),
+ STM32_MUX(_CKPER, CK_PER, MUX(MUX_CKPER), 0),
+
+ STM32_DIV(_PCLK1, PCLK1, _CKMLAHB, 0, DIV_APB1),
+ STM32_DIV(_PCLK2, PCLK2, _CKMLAHB, 0, DIV_APB2),
+ STM32_DIV(_PCLK3, PCLK3, _CKMLAHB, 0, DIV_APB3),
+ STM32_DIV(_PCLK4, PCLK4, _CKAXI, 0, DIV_APB4),
+ STM32_DIV(_PCLK5, PCLK5, _CKAXI, 0, DIV_APB5),
+ STM32_DIV(_PCLK6, PCLK6, _CKMLAHB, 0, DIV_APB6),
+
+ CK_TIMER(_CKTIMG1, CK_TIMG1, _PCLK1, 0, RCC_APB1DIVR, RCC_TIMG1PRER),
+ CK_TIMER(_CKTIMG2, CK_TIMG2, _PCLK2, 0, RCC_APB2DIVR, RCC_TIMG2PRER),
+ CK_TIMER(_CKTIMG3, CK_TIMG3, _PCLK6, 0, RCC_APB6DIVR, RCC_TIMG3PRER),
+
+ /* END ROOT CLOCKS */
+
+ STM32_GATE(_DDRC1, DDRC1, _CKAXI, CLK_IS_CRITICAL, GATE_DDRC1),
+ STM32_GATE(_DDRC1LP, DDRC1LP, _CKAXI, CLK_IS_CRITICAL, GATE_DDRC1LP),
+ STM32_GATE(_DDRPHYC, DDRPHYC, _PLL2R, CLK_IS_CRITICAL, GATE_DDRPHYC),
+ STM32_GATE(_DDRPHYCLP, DDRPHYCLP, _PLL2R, CLK_IS_CRITICAL, GATE_DDRPHYCLP),
+ STM32_GATE(_DDRCAPB, DDRCAPB, _PCLK4, CLK_IS_CRITICAL, GATE_DDRCAPB),
+ STM32_GATE(_DDRCAPBLP, DDRCAPBLP, _PCLK4, CLK_IS_CRITICAL, GATE_DDRCAPBLP),
+ STM32_GATE(_AXIDCG, AXIDCG, _CKAXI, CLK_IS_CRITICAL, GATE_AXIDCG),
+ STM32_GATE(_DDRPHYCAPB, DDRPHYCAPB, _PCLK4, CLK_IS_CRITICAL, GATE_DDRPHYCAPB),
+ STM32_GATE(_DDRPHYCAPBLP, DDRPHYCAPBLP, _PCLK4, CLK_IS_CRITICAL, GATE_DDRPHYCAPBLP),
+
+ STM32_GATE(_SYSCFG, SYSCFG, _PCLK3, 0, GATE_SYSCFG),
+ STM32_GATE(_DDRPERFM, DDRPERFM, _PCLK4, 0, GATE_DDRPERFM),
+ STM32_GATE(_IWDG2APB, IWDG2, _PCLK4, 0, GATE_IWDG2APB),
+ STM32_GATE(_USBPHY_K, USBPHY_K, MUX(MUX_USBPHY), 0, GATE_USBPHY),
+ STM32_GATE(_USBO_K, USBO_K, MUX(MUX_USBO), 0, GATE_USBO),
+
+ STM32_GATE(_RTCAPB, RTCAPB, _PCLK5, CLK_IS_CRITICAL, GATE_RTCAPB),
+ STM32_GATE(_TZC, TZC, _PCLK5, CLK_IS_CRITICAL, GATE_TZC),
+ STM32_GATE(_ETZPC, TZPC, _PCLK5, CLK_IS_CRITICAL, GATE_ETZPC),
+ STM32_GATE(_IWDG1APB, IWDG1, _PCLK5, 0, GATE_IWDG1APB),
+ STM32_GATE(_BSEC, BSEC, _PCLK5, CLK_IS_CRITICAL, GATE_BSEC),
+ STM32_GATE(_STGENC, STGEN_K, MUX(MUX_STGEN), CLK_IS_CRITICAL, GATE_STGENC),
+
+ STM32_GATE(_USART1_K, USART1_K, MUX(MUX_UART1), 0, GATE_USART1),
+ STM32_GATE(_USART2_K, USART2_K, MUX(MUX_UART2), 0, GATE_USART2),
+ STM32_GATE(_I2C3_K, I2C3_K, MUX(MUX_I2C3), 0, GATE_I2C3),
+ STM32_GATE(_I2C4_K, I2C4_K, MUX(MUX_I2C4), 0, GATE_I2C4),
+ STM32_GATE(_I2C5_K, I2C5_K, MUX(MUX_I2C5), 0, GATE_I2C5),
+ STM32_GATE(_TIM12, TIM12_K, _CKTIMG3, 0, GATE_TIM12),
+ STM32_GATE(_TIM15, TIM15_K, _CKTIMG3, 0, GATE_TIM15),
+
+ STM32_GATE(_RTCCK, RTC, MUX(MUX_RTC), 0, GATE_RTCCK),
+
+ STM32_GATE(_GPIOA, GPIOA, _CKMLAHB, 0, GATE_GPIOA),
+ STM32_GATE(_GPIOB, GPIOB, _CKMLAHB, 0, GATE_GPIOB),
+ STM32_GATE(_GPIOC, GPIOC, _CKMLAHB, 0, GATE_GPIOC),
+ STM32_GATE(_GPIOD, GPIOD, _CKMLAHB, 0, GATE_GPIOD),
+ STM32_GATE(_GPIOE, GPIOE, _CKMLAHB, 0, GATE_GPIOE),
+ STM32_GATE(_GPIOF, GPIOF, _CKMLAHB, 0, GATE_GPIOF),
+ STM32_GATE(_GPIOG, GPIOG, _CKMLAHB, 0, GATE_GPIOG),
+ STM32_GATE(_GPIOH, GPIOH, _CKMLAHB, 0, GATE_GPIOH),
+ STM32_GATE(_GPIOI, GPIOI, _CKMLAHB, 0, GATE_GPIOI),
+
+ STM32_GATE(_PKA, PKA, _CKAXI, 0, GATE_PKA),
+ STM32_GATE(_SAES_K, SAES_K, MUX(MUX_SAES), 0, GATE_SAES),
+ STM32_GATE(_CRYP1, CRYP1, _PCLK5, 0, GATE_CRYP1),
+ STM32_GATE(_HASH1, HASH1, _PCLK5, 0, GATE_HASH1),
+
+ STM32_GATE(_RNG1_K, RNG1_K, MUX(MUX_RNG1), 0, GATE_RNG1),
+ STM32_GATE(_BKPSRAM, BKPSRAM, _PCLK5, CLK_IS_CRITICAL, GATE_BKPSRAM),
+
+ STM32_GATE(_SDMMC1_K, SDMMC1_K, MUX(MUX_SDMMC1), 0, GATE_SDMMC1),
+ STM32_GATE(_SDMMC2_K, SDMMC2_K, MUX(MUX_SDMMC2), 0, GATE_SDMMC2),
+ STM32_GATE(_DBGCK, CK_DBG, _CKAXI, 0, GATE_DBGCK),
+
+/* TODO: CHECK CLOCK FOR BL2/BL32 AND IF ONLY FOR TEST OR NOT */
+ STM32_GATE(_USART3_K, USART3_K, MUX(MUX_UART35), 0, GATE_USART3),
+ STM32_GATE(_UART4_K, UART4_K, MUX(MUX_UART4), 0, GATE_UART4),
+ STM32_GATE(_UART5_K, UART5_K, MUX(MUX_UART35), 0, GATE_UART5),
+ STM32_GATE(_UART7_K, UART7_K, MUX(MUX_UART78), 0, GATE_UART7),
+ STM32_GATE(_UART8_K, UART8_K, MUX(MUX_UART78), 0, GATE_UART8),
+ STM32_GATE(_USART6_K, USART6_K, MUX(MUX_UART6), 0, GATE_USART6),
+ STM32_GATE(_MCE, MCE, _CKAXI, CLK_IS_CRITICAL, GATE_MCE),
+ STM32_GATE(_FMC_K, FMC_K, MUX(MUX_FMC), 0, GATE_FMC),
+ STM32_GATE(_QSPI_K, QSPI_K, MUX(MUX_QSPI), 0, GATE_QSPI),
+
+ STM32_COMPOSITE(_MCO1_K, CK_MCO1, MUX(MUX_MCO1), 0, GATE_MCO1, DIV_MCO1),
+ STM32_COMPOSITE(_MCO2_K, CK_MCO2, MUX(MUX_MCO2), 0, GATE_MCO2, DIV_MCO2),
+ STM32_COMPOSITE(_TRACECK, CK_TRACE, _CKAXI, 0, GATE_TRACECK, DIV_TRACE),
+
+#if defined(IMAGE_BL32)
+ STM32_GATE(_TIM2, TIM2_K, _CKTIMG1, 0, GATE_TIM2),
+ STM32_GATE(_TIM3, TIM3_K, _CKTIMG1, 0, GATE_TIM3),
+ STM32_GATE(_TIM4, TIM4_K, _CKTIMG1, 0, GATE_TIM4),
+ STM32_GATE(_TIM5, TIM5_K, _CKTIMG1, 0, GATE_TIM5),
+ STM32_GATE(_TIM6, TIM6_K, _CKTIMG1, 0, GATE_TIM6),
+ STM32_GATE(_TIM7, TIM7_K, _CKTIMG1, 0, GATE_TIM7),
+ STM32_GATE(_TIM13, TIM13_K, _CKTIMG3, 0, GATE_TIM13),
+ STM32_GATE(_TIM14, TIM14_K, _CKTIMG3, 0, GATE_TIM14),
+ STM32_GATE(_LPTIM1_K, LPTIM1_K, MUX(MUX_LPTIM1), 0, GATE_LPTIM1),
+ STM32_GATE(_SPI2_K, SPI2_K, MUX(MUX_SPI23), 0, GATE_SPI2),
+ STM32_GATE(_SPI3_K, SPI3_K, MUX(MUX_SPI23), 0, GATE_SPI3),
+ STM32_GATE(_SPDIF_K, SPDIF_K, MUX(MUX_SPDIF), 0, GATE_SPDIF),
+ STM32_GATE(_TIM1, TIM1_K, _CKTIMG2, 0, GATE_TIM1),
+ STM32_GATE(_TIM8, TIM8_K, _CKTIMG2, 0, GATE_TIM8),
+ STM32_GATE(_TIM16, TIM16_K, _CKTIMG3, 0, GATE_TIM16),
+ STM32_GATE(_TIM17, TIM17_K, _CKTIMG3, 0, GATE_TIM17),
+ STM32_GATE(_SPI1_K, SPI1_K, MUX(MUX_SPI1), 0, GATE_SPI1),
+ STM32_GATE(_SPI4_K, SPI4_K, MUX(MUX_SPI4), 0, GATE_SPI4),
+ STM32_GATE(_SPI5_K, SPI5_K, MUX(MUX_SPI5), 0, GATE_SPI5),
+ STM32_GATE(_SAI1_K, SAI1_K, MUX(MUX_SAI1), 0, GATE_SAI1),
+ STM32_GATE(_SAI2_K, SAI2_K, MUX(MUX_SAI2), 0, GATE_SAI2),
+ STM32_GATE(_DFSDM, DFSDM_K, MUX(MUX_SAI1), 0, GATE_DFSDM),
+ STM32_GATE(_FDCAN_K, FDCAN_K, MUX(MUX_FDCAN), 0, GATE_FDCAN),
+ STM32_GATE(_USBH, USBH, _CKAXI, 0, GATE_USBH),
+ STM32_GATE(_I2C1_K, I2C1_K, MUX(MUX_I2C12), 0, GATE_I2C1),
+ STM32_GATE(_I2C2_K, I2C2_K, MUX(MUX_I2C12), 0, GATE_I2C2),
+ STM32_GATE(_ADFSDM, ADFSDM_K, MUX(MUX_SAI1), 0, GATE_ADFSDM),
+ STM32_GATE(_LPTIM2_K, LPTIM2_K, MUX(MUX_LPTIM2), 0, GATE_LPTIM2),
+ STM32_GATE(_LPTIM3_K, LPTIM3_K, MUX(MUX_LPTIM3), 0, GATE_LPTIM3),
+ STM32_GATE(_LPTIM4_K, LPTIM4_K, MUX(MUX_LPTIM45), 0, GATE_LPTIM4),
+ STM32_GATE(_LPTIM5_K, LPTIM5_K, MUX(MUX_LPTIM45), 0, GATE_LPTIM5),
+ STM32_GATE(_VREF, VREF, _PCLK3, 0, GATE_VREF),
+ STM32_GATE(_DTS, TMPSENS, _PCLK3, 0, GATE_DTS),
+ STM32_GATE(_PMBCTRL, PMBCTRL, _PCLK3, 0, GATE_HDP),
+ STM32_GATE(_HDP, HDP, _PCLK3, 0, GATE_PMBCTRL),
+ STM32_GATE(_STGENRO, STGENRO, _PCLK4, 0, GATE_DCMIPP),
+ STM32_GATE(_DCMIPP_K, DCMIPP_K, MUX(MUX_DCMIPP), 0, GATE_DCMIPP),
+ STM32_GATE(_DMAMUX1, DMAMUX1, _CKAXI, 0, GATE_DMAMUX1),
+ STM32_GATE(_DMAMUX2, DMAMUX2, _CKAXI, 0, GATE_DMAMUX2),
+ STM32_GATE(_DMA3, DMA3, _CKAXI, 0, GATE_DMAMUX2),
+ STM32_GATE(_ADC1_K, ADC1_K, MUX(MUX_ADC1), 0, GATE_ADC1),
+ STM32_GATE(_ADC2_K, ADC2_K, MUX(MUX_ADC2), 0, GATE_ADC2),
+ STM32_GATE(_TSC, TSC, _CKAXI, 0, GATE_TSC),
+ STM32_GATE(_AXIMC, AXIMC, _CKAXI, 0, GATE_AXIMC),
+ STM32_GATE(_CRC1, CRC1, _CKAXI, 0, GATE_ETH1TX),
+ STM32_GATE(_ETH1CK, ETH1CK_K, MUX(MUX_ETH1), 0, GATE_ETH1CK),
+ STM32_GATE(_ETH1TX, ETH1TX, _CKAXI, 0, GATE_ETH1TX),
+ STM32_GATE(_ETH1RX, ETH1RX, _CKAXI, 0, GATE_ETH1RX),
+ STM32_GATE(_ETH2CK, ETH2CK_K, MUX(MUX_ETH2), 0, GATE_ETH2CK),
+ STM32_GATE(_ETH2TX, ETH2TX, _CKAXI, 0, GATE_ETH2TX),
+ STM32_GATE(_ETH2RX, ETH2RX, _CKAXI, 0, GATE_ETH2RX),
+ STM32_GATE(_ETH2MAC, ETH2MAC, _CKAXI, 0, GATE_ETH2MAC),
+#endif
+};
+
+static struct stm32_pll_dt_cfg mp13_pll[_PLL_NB];
+
+static struct stm32_osci_dt_cfg mp13_osci[NB_OSCILLATOR];
+
+static uint32_t mp13_clksrc[MUX_MAX];
+
+static uint32_t mp13_clkdiv[DIV_MAX];
+
+static struct stm32_clk_platdata stm32mp13_clock_pdata = {
+ .osci = mp13_osci,
+ .nosci = NB_OSCILLATOR,
+ .pll = mp13_pll,
+ .npll = _PLL_NB,
+ .clksrc = mp13_clksrc,
+ .nclksrc = MUX_MAX,
+ .clkdiv = mp13_clkdiv,
+ .nclkdiv = DIV_MAX,
+};
+
+static struct stm32_clk_priv stm32mp13_clock_data = {
+ .base = RCC_BASE,
+ .num = ARRAY_SIZE(stm32mp13_clk),
+ .clks = stm32mp13_clk,
+ .parents = parent_mp13,
+ .nb_parents = ARRAY_SIZE(parent_mp13),
+ .gates = gates_mp13,
+ .nb_gates = ARRAY_SIZE(gates_mp13),
+ .div = dividers_mp13,
+ .nb_div = ARRAY_SIZE(dividers_mp13),
+ .osci_data = stm32mp13_osc_data,
+ .nb_osci_data = ARRAY_SIZE(stm32mp13_osc_data),
+ .gate_refcounts = refcounts_mp13,
+ .pdata = &stm32mp13_clock_pdata,
+};
+
+static int stm32mp1_init_clock_tree(void)
+{
+ struct stm32_clk_priv *priv = clk_stm32_get_priv();
+ int ret;
+
+#if STM32MP_USB_PROGRAMMER
+ int usbphy_p = _clk_stm32_get_parent(priv, _USBPHY_K);
+ int usbo_p = _clk_stm32_get_parent(priv, _USBO_K);
+
+ /* Don't initialize PLL4, when used by BOOTROM */
+ pll4_bootrom = stm32mp1_clk_is_pll4_used_by_bootrom(priv, usbphy_p);
+#endif
+
+ /*
+ * Switch ON oscillators found in device-tree.
+ * Note: HSI already ON after BootROM stage.
+ */
+ stm32_clk_oscillators_enable(priv);
+
+ /* Come back to HSI */
+ ret = stm32mp1_come_back_to_hsi();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32_clk_hsidiv_configure(priv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32_clk_stgen_configure(priv, _STGENC);
+ if (ret != 0) {
+ panic();
+ }
+
+ ret = stm32_clk_dividers_configure(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ ret = stm32_clk_pll_configure(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Wait LSE ready before to use it */
+ ret = stm32_clk_oscillators_wait_lse_ready(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Configure with expected clock source */
+ ret = stm32_clk_source_configure(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Configure LSE css after RTC source configuration */
+ ret = stm32_clk_oscillators_lse_set_css(priv);
+ if (ret != 0) {
+ panic();
+ }
+
+#if STM32MP_USB_PROGRAMMER
+ ret = stm32mp1_clk_check_usb_conflict(priv, usbphy_p, usbo_p);
+ if (ret != 0) {
+ return ret;
+ }
+#endif
+ /* reconfigure STGEN with DT config */
+ ret = stm32_clk_stgen_configure(priv, _STGENC);
+ if (ret != 0) {
+ panic();
+ }
+
+ /* Software Self-Refresh mode (SSR) during DDR initilialization */
+ mmio_clrsetbits_32(priv->base + RCC_DDRITFCR,
+ RCC_DDRITFCR_DDRCKMOD_MASK,
+ RCC_DDRITFCR_DDRCKMOD_SSR <<
+ RCC_DDRITFCR_DDRCKMOD_SHIFT);
+
+ return 0;
+}
+
+#define LSEDRV_MEDIUM_HIGH 2
+
+static int clk_stm32_parse_oscillator_fdt(void *fdt, int node, const char *name,
+ struct stm32_osci_dt_cfg *osci)
+{
+ int subnode = 0;
+
+ /* default value oscillator not found, freq=0 */
+ osci->freq = 0;
+
+ fdt_for_each_subnode(subnode, fdt, node) {
+ const char *cchar = NULL;
+ const fdt32_t *cuint = NULL;
+ int ret = 0;
+
+ cchar = fdt_get_name(fdt, subnode, &ret);
+ if (cchar == NULL) {
+ return ret;
+ }
+
+ if (strncmp(cchar, name, (size_t)ret) ||
+ fdt_get_status(subnode) == DT_DISABLED) {
+ continue;
+ }
+
+ cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret);
+ if (cuint == NULL) {
+ return ret;
+ }
+
+ osci->freq = fdt32_to_cpu(*cuint);
+
+ if (fdt_getprop(fdt, subnode, "st,bypass", NULL) != NULL) {
+ osci->bypass = true;
+ }
+
+ if (fdt_getprop(fdt, subnode, "st,digbypass", NULL) != NULL) {
+ osci->digbyp = true;
+ }
+
+ if (fdt_getprop(fdt, subnode, "st,css", NULL) != NULL) {
+ osci->css = true;
+ }
+
+ osci->drive = fdt_read_uint32_default(fdt, subnode, "st,drive", LSEDRV_MEDIUM_HIGH);
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_parse_fdt_all_oscillator(void *fdt, struct stm32_clk_platdata *pdata)
+{
+ int fdt_err = 0;
+ uint32_t i = 0;
+ int node = 0;
+
+ node = fdt_path_offset(fdt, "/clocks");
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ for (i = 0; i < pdata->nosci; i++) {
+ const char *name = NULL;
+
+ name = clk_stm32_get_oscillator_name((enum stm32_osc)i);
+ if (name == NULL) {
+ continue;
+ }
+
+ fdt_err = clk_stm32_parse_oscillator_fdt(fdt, node, name, &pdata->osci[i]);
+ if (fdt_err < 0) {
+ panic();
+ }
+ }
+
+ return 0;
+}
+
+#define RCC_PLL_NAME_SIZE 12
+
+static int clk_stm32_load_vco_config(void *fdt, int subnode, struct stm32_pll_vco *vco)
+{
+ int err = 0;
+
+ err = fdt_read_uint32_array(fdt, subnode, "divmn", (int)PLL_DIV_MN_NB, vco->div_mn);
+ if (err != 0) {
+ return err;
+ }
+
+ err = fdt_read_uint32_array(fdt, subnode, "csg", (int)PLL_CSG_NB, vco->csg);
+
+ vco->csg_enabled = (err == 0);
+
+ if (err == -FDT_ERR_NOTFOUND) {
+ err = 0;
+ }
+
+ if (err != 0) {
+ return err;
+ }
+
+ vco->status = RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN | RCC_PLLNCR_PLLON;
+
+ vco->frac = fdt_read_uint32_default(fdt, subnode, "frac", 0);
+
+ vco->src = fdt_read_uint32_default(fdt, subnode, "src", UINT32_MAX);
+
+ return 0;
+}
+
+static int clk_stm32_load_output_config(void *fdt, int subnode, struct stm32_pll_output *output)
+{
+ int err = 0;
+
+ err = fdt_read_uint32_array(fdt, subnode, "st,pll_div_pqr", (int)PLL_DIV_PQR_NB,
+ output->output);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+static int clk_stm32_parse_pll_fdt(void *fdt, int subnode, struct stm32_pll_dt_cfg *pll)
+{
+ const fdt32_t *cuint = NULL;
+ int subnode_pll = 0;
+ int subnode_vco = 0;
+ int err = 0;
+
+ cuint = fdt_getprop(fdt, subnode, "st,pll", NULL);
+ if (!cuint) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ subnode_pll = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (subnode_pll < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ cuint = fdt_getprop(fdt, subnode_pll, "st,pll_vco", NULL);
+ if (!cuint) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ subnode_vco = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (subnode_vco < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ err = clk_stm32_load_vco_config(fdt, subnode_vco, &pll->vco);
+ if (err != 0) {
+ return err;
+ }
+
+ err = clk_stm32_load_output_config(fdt, subnode_pll, &pll->output);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+static int stm32_clk_parse_fdt_all_pll(void *fdt, int node, struct stm32_clk_platdata *pdata)
+{
+ size_t i = 0U;
+
+ for (i = _PLL1; i < pdata->npll; i++) {
+ struct stm32_pll_dt_cfg *pll = &pdata->pll[i];
+ char name[RCC_PLL_NAME_SIZE];
+ int subnode = 0;
+ int err = 0;
+
+ snprintf(name, sizeof(name), "st,pll@%u", i);
+
+ subnode = fdt_subnode_offset(fdt, node, name);
+ if (!fdt_check_node(subnode)) {
+ continue;
+ }
+
+ err = clk_stm32_parse_pll_fdt(fdt, subnode, pll);
+ if (err != 0) {
+ panic();
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_clk_parse_fdt(struct stm32_clk_platdata *pdata)
+{
+ void *fdt = NULL;
+ int node;
+ uint32_t err;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ if (node < 0) {
+ panic();
+ }
+
+ err = stm32_clk_parse_fdt_all_oscillator(fdt, pdata);
+ if (err != 0) {
+ return err;
+ }
+
+ err = stm32_clk_parse_fdt_all_pll(fdt, node, pdata);
+ if (err != 0) {
+ return err;
+ }
+
+ err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clkdiv", pdata->clkdiv, &pdata->nclkdiv);
+ if (err != 0) {
+ return err;
+ }
+
+ err = stm32_clk_parse_fdt_by_name(fdt, node, "st,clksrc", pdata->clksrc, &pdata->nclksrc);
+ if (err != 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+int stm32mp1_clk_init(void)
+{
+ return 0;
+}
+
+int stm32mp1_clk_probe(void)
+{
+ uintptr_t base = RCC_BASE;
+ int ret;
+
+ ret = stm32_clk_parse_fdt(&stm32mp13_clock_pdata);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_stm32_init(&stm32mp13_clock_data, base);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32mp1_init_clock_tree();
+ if (ret != 0) {
+ return ret;
+ }
+
+ clk_stm32_enable_critical_clocks();
+
+ return 0;
+}
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index 564bd87989..818fd8596b 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -9,16 +9,12 @@
#include <stdint.h>
#include <stdio.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
-#include <drivers/generic_delay_timer.h>
#include <drivers/st/stm32mp_clkfunc.h>
#include <drivers/st/stm32mp1_clk.h>
#include <drivers/st/stm32mp1_rcc.h>
@@ -26,8 +22,11 @@
#include <lib/mmio.h>
#include <lib/spinlock.h>
#include <lib/utils_def.h>
+#include <libfdt.h>
#include <plat/common/platform.h>
+#include <platform_def.h>
+
#define MAX_HSI_HZ 64000000
#define USB_PHY_48_MHZ 48000000
@@ -56,6 +55,7 @@ enum stm32mp1_parent_id {
_HSI_KER = NB_OSC,
_HSE_KER,
_HSE_KER_DIV2,
+ _HSE_RTC,
_CSI_KER,
_PLL1_P,
_PLL1_Q,
@@ -107,7 +107,7 @@ enum stm32mp1_parent_sel {
_USBPHY_SEL,
_USBO_SEL,
_MPU_SEL,
- _PER_SEL,
+ _CKPER_SEL,
_RTC_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
@@ -125,6 +125,7 @@ static const uint8_t parent_id_clock_id[_PARENT_NB] = {
[_HSI_KER] = CK_HSI,
[_HSE_KER] = CK_HSE,
[_HSE_KER_DIV2] = CK_HSE_DIV2,
+ [_HSE_RTC] = _UNKNOWN_ID,
[_CSI_KER] = CK_CSI,
[_PLL1_P] = PLL1_P,
[_PLL1_Q] = PLL1_Q,
@@ -231,7 +232,6 @@ enum stm32mp1_plltype {
struct stm32mp1_pll {
uint8_t refclk_min;
uint8_t refclk_max;
- uint8_t divn_max;
};
struct stm32mp1_clk_gate {
@@ -239,6 +239,7 @@ struct stm32mp1_clk_gate {
uint8_t bit;
uint8_t index;
uint8_t set_clr;
+ uint8_t secure;
uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
};
@@ -264,45 +265,49 @@ struct stm32mp1_clk_pll {
};
/* Clocks with selectable source and non set/clr register access */
-#define _CLK_SELEC(off, b, idx, s) \
+#define _CLK_SELEC(sec, off, b, idx, s) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 0, \
+ .secure = (sec), \
.sel = (s), \
.fixed = _UNKNOWN_ID, \
}
/* Clocks with fixed source and non set/clr register access */
-#define _CLK_FIXED(off, b, idx, f) \
+#define _CLK_FIXED(sec, off, b, idx, f) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 0, \
+ .secure = (sec), \
.sel = _UNKNOWN_SEL, \
.fixed = (f), \
}
/* Clocks with selectable source and set/clr register access */
-#define _CLK_SC_SELEC(off, b, idx, s) \
+#define _CLK_SC_SELEC(sec, off, b, idx, s) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 1, \
+ .secure = (sec), \
.sel = (s), \
.fixed = _UNKNOWN_ID, \
}
/* Clocks with fixed source and set/clr register access */
-#define _CLK_SC_FIXED(off, b, idx, f) \
+#define _CLK_SC_FIXED(sec, off, b, idx, f) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 1, \
+ .secure = (sec), \
.sel = _UNKNOWN_SEL, \
.fixed = (f), \
}
@@ -336,81 +341,94 @@ struct stm32mp1_clk_pll {
#define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate)
+#define SEC 1
+#define N_S 0
+
static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
- _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
- _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
- _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
- _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
- _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
- _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
-
- _CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
- _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
-
- _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
- _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
-
- _CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
-
- _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
-
- _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
- _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
- _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
- _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
- _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
- _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
-
- _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
-
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
-
- _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
- _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
- _CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
- _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
-
- _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
- _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
-
- _CLK_SELEC(RCC_BDCR, 20, RTC, _RTC_SEL),
- _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+
+ _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),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
+
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
+
+#if defined(IMAGE_BL32)
+ _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),
+#endif
+
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
+
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
+ _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
+
+#if defined(IMAGE_BL2)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
+#endif
+ _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),
+#if defined(IMAGE_BL32)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
+#endif
+
+ _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
+ _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
};
static const uint8_t i2c12_parents[] = {
@@ -465,12 +483,12 @@ static const uint8_t fmc_parents[] = {
_ACLK, _PLL3_R, _PLL4_P, _CK_PER
};
-static const uint8_t ass_parents[] = {
- _HSI, _HSE, _PLL2
+static const uint8_t axiss_parents[] = {
+ _HSI, _HSE, _PLL2_P
};
-static const uint8_t mss_parents[] = {
- _HSI, _HSE, _CSI, _PLL3
+static const uint8_t mcuss_parents[] = {
+ _HSI, _HSE, _CSI, _PLL3_P
};
static const uint8_t usbphy_parents[] = {
@@ -490,7 +508,7 @@ static const uint8_t per_parents[] = {
};
static const uint8_t rtc_parents[] = {
- _UNKNOWN_ID, _LSE, _LSI, _HSE
+ _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC
};
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
@@ -502,7 +520,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
_CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
- _CLK_PARENT_SEL(PER, RCC_CPERCKSELR, per_parents),
+ _CLK_PARENT_SEL(CKPER, RCC_CPERCKSELR, per_parents),
_CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
@@ -512,8 +530,8 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
- _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, ass_parents),
- _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mss_parents),
+ _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
+ _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
};
@@ -524,12 +542,10 @@ 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,
},
};
@@ -587,6 +603,7 @@ static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
[_HSI_KER] = "HSI_KER",
[_HSE_KER] = "HSE_KER",
[_HSE_KER_DIV2] = "HSE_KER_DIV2",
+ [_HSE_RTC] = "HSE_RTC",
[_CSI_KER] = "CSI_KER",
[_PLL1_P] = "PLL1_P",
[_PLL1_Q] = "PLL1_Q",
@@ -625,6 +642,13 @@ static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
return &stm32mp1_clk_gate[idx];
}
+#if defined(IMAGE_BL32)
+static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
+{
+ return gate->secure == N_S;
+}
+#endif
+
static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
{
return &stm32mp1_clk_sel[idx];
@@ -695,7 +719,7 @@ static int stm32mp1_clk_get_gated_id(unsigned long id)
}
}
- ERROR("%s: clk id %d not found\n", __func__, (uint32_t)id);
+ ERROR("%s: clk id %lu not found\n", __func__, id);
return -EINVAL;
}
@@ -847,9 +871,7 @@ static unsigned long get_clock_rate(int p)
reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
clkdiv = reg & RCC_MPUDIV_MASK;
- if (clkdiv != 0U) {
- clock /= stm32mp1_mpu_div[clkdiv];
- }
+ clock >>= stm32mp1_mpu_div[clkdiv];
break;
default:
break;
@@ -969,6 +991,10 @@ static unsigned long get_clock_rate(int p)
case _HSE_KER_DIV2:
clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
break;
+ case _HSE_RTC:
+ clock = stm32mp1_clk_get_fixed(_HSE);
+ clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U;
+ break;
case _LSI:
clock = stm32mp1_clk_get_fixed(_LSI);
break;
@@ -1057,17 +1083,6 @@ static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
}
-unsigned int stm32mp1_clk_get_refcount(unsigned long id)
-{
- int i = stm32mp1_clk_get_gated_id(id);
-
- if (i < 0) {
- panic();
- }
-
- return gate_refcounts[i];
-}
-
/* Oscillators and PLLs are not gated at runtime */
static bool clock_is_always_on(unsigned long id)
{
@@ -1086,17 +1101,20 @@ static bool clock_is_always_on(unsigned long id)
case PLL3_P:
case PLL3_Q:
case PLL3_R:
+ case CK_AXI:
+ case CK_MPU:
+ case CK_MCU:
+ case RTC:
return true;
default:
return false;
}
}
-void __stm32mp1_clk_enable(unsigned long id, bool secure)
+static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
{
const struct stm32mp1_clk_gate *gate;
int i;
- unsigned int *refcnt;
if (clock_is_always_on(id)) {
return;
@@ -1104,27 +1122,44 @@ void __stm32mp1_clk_enable(unsigned long id, bool secure)
i = stm32mp1_clk_get_gated_id(id);
if (i < 0) {
- ERROR("Clock %d can't be enabled\n", (uint32_t)id);
+ ERROR("Clock %lu can't be enabled\n", id);
panic();
}
gate = gate_ref(i);
- refcnt = &gate_refcounts[i];
+
+ if (!with_refcnt) {
+ __clk_enable(gate);
+ return;
+ }
+
+#if defined(IMAGE_BL32)
+ if (gate_is_non_secure(gate)) {
+ /* Enable non-secure clock w/o any refcounting */
+ __clk_enable(gate);
+ return;
+ }
+#endif
stm32mp1_clk_lock(&refcount_lock);
- if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) {
+ if (gate_refcounts[i] == 0U) {
__clk_enable(gate);
}
+ gate_refcounts[i]++;
+ if (gate_refcounts[i] == UINT_MAX) {
+ ERROR("Clock %lu refcount reached max value\n", id);
+ panic();
+ }
+
stm32mp1_clk_unlock(&refcount_lock);
}
-void __stm32mp1_clk_disable(unsigned long id, bool secure)
+static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
{
const struct stm32mp1_clk_gate *gate;
int i;
- unsigned int *refcnt;
if (clock_is_always_on(id)) {
return;
@@ -1132,33 +1167,52 @@ void __stm32mp1_clk_disable(unsigned long id, bool secure)
i = stm32mp1_clk_get_gated_id(id);
if (i < 0) {
- ERROR("Clock %d can't be disabled\n", (uint32_t)id);
+ ERROR("Clock %lu can't be disabled\n", id);
panic();
}
gate = gate_ref(i);
- refcnt = &gate_refcounts[i];
+
+ if (!with_refcnt) {
+ __clk_disable(gate);
+ return;
+ }
+
+#if defined(IMAGE_BL32)
+ if (gate_is_non_secure(gate)) {
+ /* Don't disable non-secure clocks */
+ return;
+ }
+#endif
stm32mp1_clk_lock(&refcount_lock);
- if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) {
+ if (gate_refcounts[i] == 0U) {
+ ERROR("Clock %lu refcount reached 0\n", id);
+ panic();
+ }
+ gate_refcounts[i]--;
+
+ if (gate_refcounts[i] == 0U) {
__clk_disable(gate);
}
stm32mp1_clk_unlock(&refcount_lock);
}
-void stm32mp_clk_enable(unsigned long id)
+static int stm32mp_clk_enable(unsigned long id)
{
__stm32mp1_clk_enable(id, true);
+
+ return 0;
}
-void stm32mp_clk_disable(unsigned long id)
+static void stm32mp_clk_disable(unsigned long id)
{
__stm32mp1_clk_disable(id, true);
}
-bool stm32mp_clk_is_enabled(unsigned long id)
+static bool stm32mp_clk_is_enabled(unsigned long id)
{
int i;
@@ -1174,15 +1228,55 @@ bool stm32mp_clk_is_enabled(unsigned long id)
return __clk_is_enabled(gate_ref(i));
}
-unsigned long stm32mp_clk_get_rate(unsigned long id)
+static unsigned long stm32mp_clk_get_rate(unsigned long id)
{
+ uintptr_t rcc_base = stm32mp_rcc_base();
int p = stm32mp1_clk_get_parent(id);
+ uint32_t prescaler, timpre;
+ unsigned long parent_rate;
if (p < 0) {
return 0;
}
- return get_clock_rate(p);
+ parent_rate = get_clock_rate(p);
+
+ switch (id) {
+ case TIM2_K:
+ case TIM3_K:
+ case TIM4_K:
+ case TIM5_K:
+ case TIM6_K:
+ case TIM7_K:
+ case TIM12_K:
+ case TIM13_K:
+ case TIM14_K:
+ prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
+ RCC_APBXDIV_MASK;
+ timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
+ RCC_TIMGXPRER_TIMGXPRE;
+ break;
+
+ case TIM1_K:
+ case TIM8_K:
+ case TIM15_K:
+ case TIM16_K:
+ case TIM17_K:
+ prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
+ RCC_APBXDIV_MASK;
+ timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
+ RCC_TIMGXPRER_TIMGXPRE;
+ break;
+
+ default:
+ return parent_rate;
+ }
+
+ if (prescaler == 0U) {
+ return parent_rate;
+ }
+
+ return parent_rate * (timpre + 1U) * 2U;
}
static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
@@ -1299,6 +1393,13 @@ static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
if (css) {
mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
}
+
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+ if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
+ (!(digbyp || bypass))) {
+ panic();
+ }
+#endif
}
static void stm32mp1_csi_set(bool enable)
@@ -1460,7 +1561,7 @@ static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
/* Wait PLL lock */
while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
if (timeout_elapsed(timeout)) {
- ERROR("PLL%d start failed @ 0x%lx: 0x%x\n",
+ ERROR("PLL%u start failed @ 0x%lx: 0x%x\n",
pll_id, pllxcr, mmio_read_32(pllxcr));
return -ETIMEDOUT;
}
@@ -1489,7 +1590,7 @@ static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
/* Wait PLL stopped */
while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
if (timeout_elapsed(timeout)) {
- ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n",
+ ERROR("PLL%u stop failed @ 0x%lx: 0x%x\n",
pll_id, pllxcr, mmio_read_32(pllxcr));
return -ETIMEDOUT;
}
@@ -1652,7 +1753,7 @@ static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
(clksrc != (uint32_t)CLK_RTC_DISABLED)) {
mmio_clrsetbits_32(address,
RCC_BDCR_RTCSRC_MASK,
- clksrc << RCC_BDCR_RTCSRC_SHIFT);
+ (clksrc & RCC_SELR_SRC_MASK) << RCC_BDCR_RTCSRC_SHIFT);
mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
}
@@ -1662,87 +1763,75 @@ static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
}
}
-static void stm32mp1_stgen_config(void)
+static void stm32mp1_pkcs_config(uint32_t pkcs)
{
- uint32_t cntfid0;
- unsigned long rate;
- unsigned long long counter;
-
- cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
- rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K));
+ uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
+ uint32_t value = pkcs & 0xFU;
+ uint32_t mask = 0xFU;
- if (cntfid0 == rate) {
- return;
+ if ((pkcs & BIT(31)) != 0U) {
+ mask <<= 4;
+ value <<= 4;
}
- mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
- counter = (unsigned long long)mmio_read_32(STGEN_BASE + CNTCVL_OFF);
- counter |= ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF)) << 32;
- counter = (counter * rate / cntfid0);
-
- mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
- mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
- mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
- mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
-
- write_cntfrq((u_register_t)rate);
-
- /* Need to update timer with new frequency */
- generic_delay_timer_init();
+ mmio_clrsetbits_32(address, mask, value);
}
-void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
+static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg,
+ uint32_t *fracv, uint32_t *csg,
+ bool *csg_set)
{
- unsigned long long cnt;
+ void *fdt;
+ int ret;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
- cnt = ((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
- mmio_read_32(STGEN_BASE + CNTCVL_OFF);
+ ret = fdt_read_uint32_array(fdt, plloff, "cfg", (uint32_t)PLLCFG_NB,
+ pllcfg);
+ if (ret < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
- cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U;
+ *fracv = fdt_read_uint32_default(fdt, plloff, "frac", 0);
- mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
- mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
- mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
- mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
-}
+ ret = fdt_read_uint32_array(fdt, plloff, "csg", (uint32_t)PLLCSG_NB,
+ csg);
-static void stm32mp1_pkcs_config(uint32_t pkcs)
-{
- uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
- uint32_t value = pkcs & 0xFU;
- uint32_t mask = 0xFU;
+ *csg_set = (ret == 0);
- if ((pkcs & BIT(31)) != 0U) {
- mask <<= 4;
- value <<= 4;
+ if (ret == -FDT_ERR_NOTFOUND) {
+ ret = 0;
}
- mmio_clrsetbits_32(address, mask, value);
+ return ret;
}
int stm32mp1_clk_init(void)
{
uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t pllfracv[_PLL_NB];
+ uint32_t pllcsg[_PLL_NB][PLLCSG_NB];
unsigned int clksrc[CLKSRC_NB];
unsigned int clkdiv[CLKDIV_NB];
unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
int plloff[_PLL_NB];
int ret, len;
enum stm32mp1_pll_id i;
+ bool pllcsg_set[_PLL_NB];
+ bool pllcfg_valid[_PLL_NB];
bool lse_css = false;
bool pll3_preserve = false;
bool pll4_preserve = false;
bool pll4_bootrom = false;
const fdt32_t *pkcs_cell;
void *fdt;
+ int stgen_p = stm32mp1_clk_get_parent(STGEN_K);
+ int usbphy_p = stm32mp1_clk_get_parent(USBPHY_K);
if (fdt_get_address(&fdt) == 0) {
- return false;
- }
-
- /* Check status field to disable security */
- if (!fdt_get_rcc_secure_status()) {
- mmio_write_32(rcc_base + RCC_TZCR, 0);
+ return -FDT_ERR_NOTFOUND;
}
ret = fdt_rcc_read_uint32_array("st,clksrc", (uint32_t)CLKSRC_NB,
@@ -1760,17 +1849,19 @@ int stm32mp1_clk_init(void)
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
char name[12];
- snprintf(name, sizeof(name), "st,pll@%d", i);
+ snprintf(name, sizeof(name), "st,pll@%u", i);
plloff[i] = fdt_rcc_subnode_offset(name);
- if (!fdt_check_node(plloff[i])) {
+ pllcfg_valid[i] = fdt_check_node(plloff[i]);
+ if (!pllcfg_valid[i]) {
continue;
}
- ret = fdt_read_uint32_array(fdt, plloff[i], "cfg",
- (int)PLLCFG_NB, pllcfg[i]);
- if (ret < 0) {
- return -FDT_ERR_NOTFOUND;
+ ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i],
+ &pllfracv[i], pllcsg[i],
+ &pllcsg_set[i]);
+ if (ret != 0) {
+ return ret;
}
}
@@ -1785,22 +1876,24 @@ int stm32mp1_clk_init(void)
stm32mp1_lsi_set(true);
}
if (stm32mp1_osc[_LSE] != 0U) {
+ const char *name = stm32mp_osc_node_label[_LSE];
bool bypass, digbyp;
uint32_t lsedrv;
- bypass = fdt_osc_read_bool(_LSE, "st,bypass");
- digbyp = fdt_osc_read_bool(_LSE, "st,digbypass");
- lse_css = fdt_osc_read_bool(_LSE, "st,css");
- lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive",
+ bypass = fdt_clk_read_bool(name, "st,bypass");
+ digbyp = fdt_clk_read_bool(name, "st,digbypass");
+ lse_css = fdt_clk_read_bool(name, "st,css");
+ lsedrv = fdt_clk_read_uint32_default(name, "st,drive",
LSEDRV_MEDIUM_HIGH);
stm32mp1_lse_enable(bypass, digbyp, lsedrv);
}
if (stm32mp1_osc[_HSE] != 0U) {
+ const char *name = stm32mp_osc_node_label[_HSE];
bool bypass, digbyp, css;
- bypass = fdt_osc_read_bool(_HSE, "st,bypass");
- digbyp = fdt_osc_read_bool(_HSE, "st,digbypass");
- css = fdt_osc_read_bool(_HSE, "st,css");
+ bypass = fdt_clk_read_bool(name, "st,bypass");
+ digbyp = fdt_clk_read_bool(name, "st,digbypass");
+ css = fdt_clk_read_bool(name, "st,css");
stm32mp1_hse_enable(bypass, digbyp, css);
}
/*
@@ -1825,14 +1918,28 @@ int stm32mp1_clk_init(void)
if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
- pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
+ if (pllcfg_valid[_PLL3]) {
+ pll3_preserve =
+ stm32mp1_check_pll_conf(_PLL3,
clksrc[CLKSRC_PLL3],
pllcfg[_PLL3],
plloff[_PLL3]);
- pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
+ }
+
+ if (pllcfg_valid[_PLL4]) {
+ pll4_preserve =
+ stm32mp1_check_pll_conf(_PLL4,
clksrc[CLKSRC_PLL4],
pllcfg[_PLL4],
plloff[_PLL4]);
+ }
+ }
+ /* Don't initialize PLL4, when used by BOOTROM */
+ if ((stm32mp_get_boot_itf_selected() ==
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) &&
+ ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
+ pll4_bootrom = true;
+ pll4_preserve = true;
}
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
@@ -1853,7 +1960,8 @@ int stm32mp1_clk_init(void)
if (ret != 0) {
return ret;
}
- stm32mp1_stgen_config();
+
+ stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
}
/* Select DIV */
@@ -1915,15 +2023,12 @@ int stm32mp1_clk_init(void)
/* Configure and start PLLs */
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
- uint32_t fracv;
- uint32_t csg[PLLCSG_NB];
-
if (((i == _PLL3) && pll3_preserve) ||
((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
continue;
}
- if (!fdt_check_node(plloff[i])) {
+ if (!pllcfg_valid[i]) {
continue;
}
@@ -1933,25 +2038,20 @@ int stm32mp1_clk_init(void)
continue;
}
- fracv = fdt_read_uint32_default(fdt, plloff[i], "frac", 0);
-
- ret = stm32mp1_pll_config(i, pllcfg[i], fracv);
+ ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]);
if (ret != 0) {
return ret;
}
- ret = fdt_read_uint32_array(fdt, plloff[i], "csg",
- (uint32_t)PLLCSG_NB, csg);
- if (ret == 0) {
- stm32mp1_pll_csg(i, csg);
- } else if (ret != -FDT_ERR_NOTFOUND) {
- return ret;
+
+ if (pllcsg_set[i]) {
+ stm32mp1_pll_csg(i, pllcsg[i]);
}
stm32mp1_pll_start(i);
}
- /* Wait and start PLLs ouptut when ready */
+ /* Wait and start PLLs output when ready */
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
- if (!fdt_check_node(plloff[i])) {
+ if (!pllcfg_valid[i]) {
continue;
}
@@ -1985,6 +2085,11 @@ int stm32mp1_clk_init(void)
if (pkcs_cell != NULL) {
bool ckper_disabled = false;
uint32_t j;
+ uint32_t usbreg_bootrom = 0U;
+
+ if (pll4_bootrom) {
+ usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR);
+ }
for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
@@ -2005,13 +2110,33 @@ int stm32mp1_clk_init(void)
if (ckper_disabled) {
stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
}
+
+ if (pll4_bootrom) {
+ uint32_t usbreg_value, usbreg_mask;
+ const struct stm32mp1_clk_sel *sel;
+
+ sel = clk_sel_ref(_USBPHY_SEL);
+ usbreg_mask = (uint32_t)sel->msk << sel->src;
+ sel = clk_sel_ref(_USBO_SEL);
+ usbreg_mask |= (uint32_t)sel->msk << sel->src;
+
+ usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) &
+ usbreg_mask;
+ usbreg_bootrom &= usbreg_mask;
+ if (usbreg_bootrom != usbreg_value) {
+ VERBOSE("forbidden new USB clk path\n");
+ VERBOSE("vs bootrom on USB boot\n");
+ return -FDT_ERR_BADVALUE;
+ }
+ }
}
/* Switch OFF HSI if not found in device-tree */
if (stm32mp1_osc[_HSI] == 0U) {
stm32mp1_hsi_set(false);
}
- stm32mp1_stgen_config();
+
+ stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
/* Software Self-Refresh mode (SSR) during DDR initilialization */
mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
@@ -2152,6 +2277,7 @@ static void secure_parent_clocks(unsigned long parent_id)
case _HSE:
case _HSE_KER:
case _HSE_KER_DIV2:
+ case _HSE_RTC:
case _LSE:
break;
@@ -2200,6 +2326,17 @@ void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
}
#endif /* STM32MP_SHARED_RESOURCES */
+void stm32mp1_clk_mcuss_protect(bool enable)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ if (enable) {
+ mmio_setbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+ } else {
+ mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+ }
+}
+
static void sync_earlyboot_clocks_state(void)
{
unsigned int idx;
@@ -2210,6 +2347,7 @@ static void sync_earlyboot_clocks_state(void)
DDRC2, DDRC2LP,
DDRCAPB, DDRPHYCAPB, DDRPHYCAPBLP,
DDRPHYC, DDRPHYCLP,
+ RTCAPB,
TZC1, TZC2,
TZPC,
STGEN_K,
@@ -2218,17 +2356,29 @@ static void sync_earlyboot_clocks_state(void)
for (idx = 0U; idx < ARRAY_SIZE(secure_enable); idx++) {
stm32mp_clk_enable(secure_enable[idx]);
}
-
- if (!stm32mp_is_single_core()) {
- stm32mp1_clk_enable_secure(RTCAPB);
- }
}
+static const struct clk_ops stm32mp_clk_ops = {
+ .enable = stm32mp_clk_enable,
+ .disable = stm32mp_clk_disable,
+ .is_enabled = stm32mp_clk_is_enabled,
+ .get_rate = stm32mp_clk_get_rate,
+ .get_parent = stm32mp1_clk_get_parent,
+};
+
int stm32mp1_clk_probe(void)
{
+#if defined(IMAGE_BL32)
+ if (!fdt_get_rcc_secure_state()) {
+ mmio_write_32(stm32mp_rcc_base() + RCC_TZCR, 0U);
+ }
+#endif
+
stm32mp1_osc_init();
sync_earlyboot_clocks_state();
+ clk_register(&stm32mp_clk_ops);
+
return 0;
}
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
index 8333f6dfbf..379547fd11 100644
--- a/drivers/st/clk/stm32mp_clkfunc.c
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -1,18 +1,21 @@
/*
- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2023, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
+#include <arch_helpers.h>
#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
+#include <drivers/generic_delay_timer.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
/*
* Get the frequency of an oscillator from its name in device tree.
@@ -43,7 +46,8 @@ int fdt_osc_read_freq(const char *name, uint32_t *freq)
return ret;
}
- if (strncmp(cchar, name, (size_t)ret) == 0) {
+ if ((strncmp(cchar, name, (size_t)ret) == 0) &&
+ (fdt_get_status(subnode) != DT_DISABLED)) {
const fdt32_t *cuint;
cuint = fdt_getprop(fdt, subnode, "clock-frequency",
@@ -65,11 +69,11 @@ int fdt_osc_read_freq(const char *name, uint32_t *freq)
/*
* Check the presence of an oscillator property from its id.
- * @param osc_id: oscillator ID
+ * @param node_label: clock node name
* @param prop_name: property name
* @return: true/false regarding search result.
*/
-bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
+bool fdt_clk_read_bool(const char *node_label, const char *prop_name)
{
int node, subnode;
void *fdt;
@@ -78,10 +82,6 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
return false;
}
- if (osc_id >= NB_OSC) {
- return false;
- }
-
node = fdt_path_offset(fdt, "/clocks");
if (node < 0) {
return false;
@@ -96,8 +96,7 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
return false;
}
- if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
- (size_t)ret) != 0) {
+ if (strncmp(cchar, node_label, (size_t)ret) != 0) {
continue;
}
@@ -110,13 +109,13 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
}
/*
- * Get the value of a oscillator property from its ID.
- * @param osc_id: oscillator ID
+ * Get the value of a oscillator property from its name.
+ * @param node_label: oscillator name
* @param prop_name: property name
* @param dflt_value: default value
* @return oscillator value on success, default value if property not found.
*/
-uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
+uint32_t fdt_clk_read_uint32_default(const char *node_label,
const char *prop_name, uint32_t dflt_value)
{
int node, subnode;
@@ -126,10 +125,6 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
return dflt_value;
}
- if (osc_id >= NB_OSC) {
- return dflt_value;
- }
-
node = fdt_path_offset(fdt, "/clocks");
if (node < 0) {
return dflt_value;
@@ -144,8 +139,7 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
return dflt_value;
}
- if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
- (size_t)ret) != 0) {
+ if (strncmp(cchar, node_label, (size_t)ret) != 0) {
continue;
}
@@ -161,9 +155,15 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
* @param fdt: Device tree reference
* @return: Node offset or a negative value on error
*/
-int fdt_get_rcc_node(void *fdt)
+static int fdt_get_rcc_node(void *fdt)
{
- return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ static int node;
+
+ if (node <= 0) {
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ }
+
+ return node;
}
/*
@@ -248,26 +248,26 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
return cuint;
}
+#if defined(IMAGE_BL32)
/*
- * Get the secure status for rcc node in device tree.
- * @return: true if rcc is available from secure world, false if not.
+ * Get the secure state for rcc node in device tree.
+ * @return: true if rcc is configured for secure world access, false if not.
*/
-bool fdt_get_rcc_secure_status(void)
+bool fdt_get_rcc_secure_state(void)
{
- int node;
void *fdt;
if (fdt_get_address(&fdt) == 0) {
return false;
}
- node = fdt_get_rcc_node(fdt);
- if (node < 0) {
+ if (fdt_node_offset_by_compatible(fdt, -1, DT_RCC_SEC_CLK_COMPAT) < 0) {
return false;
}
- return !!(fdt_get_status(node) & DT_SECURE);
+ return true;
}
+#endif
/*
* Get the clock ID of the given node in device tree.
@@ -291,3 +291,104 @@ int fdt_get_clock_id(int node)
cuint++;
return (int)fdt32_to_cpu(*cuint);
}
+
+/*
+ * Get the frequency of the specified UART instance.
+ * @param instance: UART interface registers base address.
+ * @return: clock frequency on success, 0 value on failure.
+ */
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
+{
+ void *fdt;
+ int node;
+ int clk_id;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return 0UL;
+ }
+
+ /* Check for UART nodes */
+ node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
+ if (node < 0) {
+ return 0UL;
+ }
+
+ clk_id = fdt_get_clock_id(node);
+ if (clk_id < 0) {
+ return 0UL;
+ }
+
+ return clk_get_rate((unsigned long)clk_id);
+}
+
+/*******************************************************************************
+ * This function sets the STGEN counter value.
+ ******************************************************************************/
+static void stgen_set_counter(unsigned long long counter)
+{
+#ifdef __aarch64__
+ mmio_write_64(STGEN_BASE + CNTCV_OFF, counter);
+#else
+ mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
+ mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
+#endif
+}
+
+/*******************************************************************************
+ * This function configures and restores the STGEN counter depending on the
+ * connected clock.
+ ******************************************************************************/
+void stm32mp_stgen_config(unsigned long rate)
+{
+ uint32_t cntfid0;
+ unsigned long long counter;
+
+ cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
+
+ if (cntfid0 == rate) {
+ return;
+ }
+
+ mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+ counter = stm32mp_stgen_get_counter() * rate / cntfid0;
+
+ stgen_set_counter(counter);
+ mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
+ mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+
+ write_cntfrq_el0(rate);
+
+ /* Need to update timer with new frequency */
+ generic_delay_timer_init();
+}
+
+/*******************************************************************************
+ * This function returns the STGEN counter value.
+ ******************************************************************************/
+unsigned long long stm32mp_stgen_get_counter(void)
+{
+#ifdef __aarch64__
+ return mmio_read_64(STGEN_BASE + CNTCV_OFF);
+#else
+ return (((unsigned long long)mmio_read_32(STGEN_BASE + CNTCVU_OFF) << 32) |
+ mmio_read_32(STGEN_BASE + CNTCVL_OFF));
+#endif
+}
+
+/*******************************************************************************
+ * This function restores the STGEN counter value.
+ * It takes a first input value as a counter backup value to be restored and a
+ * offset in ms to be added.
+ ******************************************************************************/
+void stm32mp_stgen_restore_counter(unsigned long long value,
+ unsigned long long offset_in_ms)
+{
+ unsigned long long cnt;
+
+ cnt = value + ((offset_in_ms *
+ mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U);
+
+ mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+ stgen_set_counter(cnt);
+ mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+}
diff --git a/drivers/st/crypto/stm32_hash.c b/drivers/st/crypto/stm32_hash.c
index 317fd9eb88..e92f980003 100644
--- a/drivers/st/crypto/stm32_hash.c
+++ b/drivers/st/crypto/stm32_hash.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,20 +8,25 @@
#include <errno.h>
#include <stdint.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <arch_helpers.h>
#include <common/debug.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
#include <drivers/st/stm32_hash.h>
#include <drivers/st/stm32mp_reset.h>
#include <lib/mmio.h>
#include <lib/utils.h>
+#include <libfdt.h>
#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#if STM32_HASH_VER == 2
#define DT_HASH_COMPAT "st,stm32f756-hash"
+#endif
+#if STM32_HASH_VER == 4
+#define DT_HASH_COMPAT "st,stm32mp13-hash"
+#endif
#define HASH_CR 0x00U
#define HASH_DIN 0x04U
@@ -32,11 +37,22 @@
/* Control Register */
#define HASH_CR_INIT BIT(2)
#define HASH_CR_DATATYPE_SHIFT U(4)
-
+#if STM32_HASH_VER == 2
#define HASH_CR_ALGO_SHA1 0x0U
#define HASH_CR_ALGO_MD5 BIT(7)
#define HASH_CR_ALGO_SHA224 BIT(18)
#define HASH_CR_ALGO_SHA256 (BIT(18) | BIT(7))
+#endif
+#if STM32_HASH_VER == 4
+#define HASH_CR_ALGO_SHIFT U(17)
+#define HASH_CR_ALGO_SHA1 (0x0U << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA224 (0x2U << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA256 (0x3U << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA384 (0xCU << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA512_224 (0xDU << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA512_256 (0xEU << HASH_CR_ALGO_SHIFT)
+#define HASH_CR_ALGO_SHA512 (0xFU << HASH_CR_ALGO_SHIFT)
+#endif
/* Status Flags */
#define HASH_SR_DCIS BIT(1)
@@ -50,6 +66,10 @@
#define SHA1_DIGEST_SIZE 20U
#define SHA224_DIGEST_SIZE 28U
#define SHA256_DIGEST_SIZE 32U
+#define SHA384_DIGEST_SIZE 48U
+#define SHA512_224_DIGEST_SIZE 28U
+#define SHA512_256_DIGEST_SIZE 32U
+#define SHA512_DIGEST_SIZE 64U
#define RESET_TIMEOUT_US_1MS 1000U
#define HASH_TIMEOUT_US 10000U
@@ -130,10 +150,12 @@ static void hash_hw_init(enum stm32_hash_algo_mode mode)
reg = HASH_CR_INIT | (HASH_DATA_8_BITS << HASH_CR_DATATYPE_SHIFT);
switch (mode) {
+#if STM32_HASH_VER == 2
case HASH_MD5SUM:
reg |= HASH_CR_ALGO_MD5;
stm32_hash.digest_size = MD5_DIGEST_SIZE;
break;
+#endif
case HASH_SHA1:
reg |= HASH_CR_ALGO_SHA1;
stm32_hash.digest_size = SHA1_DIGEST_SIZE;
@@ -142,6 +164,16 @@ static void hash_hw_init(enum stm32_hash_algo_mode mode)
reg |= HASH_CR_ALGO_SHA224;
stm32_hash.digest_size = SHA224_DIGEST_SIZE;
break;
+#if STM32_HASH_VER == 4
+ case HASH_SHA384:
+ reg |= HASH_CR_ALGO_SHA384;
+ stm32_hash.digest_size = SHA384_DIGEST_SIZE;
+ break;
+ case HASH_SHA512:
+ reg |= HASH_CR_ALGO_SHA512;
+ stm32_hash.digest_size = SHA512_DIGEST_SIZE;
+ break;
+#endif
/* Default selected algo is SHA256 */
case HASH_SHA256:
default:
@@ -170,13 +202,12 @@ static int hash_get_digest(uint8_t *digest)
memcpy(digest + (i * sizeof(uint32_t)), &dsg, sizeof(uint32_t));
}
-#if defined(IMAGE_BL2)
/*
* Clean hardware context as HASH could be used later
* by non-secure software
*/
hash_hw_init(HASH_SHA256);
-#endif
+
return 0;
}
@@ -189,7 +220,7 @@ int stm32_hash_update(const uint8_t *buffer, size_t length)
return 0;
}
- stm32mp_clk_enable(stm32_hash.clock);
+ clk_enable(stm32_hash.clock);
if (stm32_remain.length != 0U) {
uint32_t copysize;
@@ -231,7 +262,7 @@ int stm32_hash_update(const uint8_t *buffer, size_t length)
}
exit:
- stm32mp_clk_disable(stm32_hash.clock);
+ clk_disable(stm32_hash.clock);
return ret;
}
@@ -240,12 +271,12 @@ int stm32_hash_final(uint8_t *digest)
{
int ret;
- stm32mp_clk_enable(stm32_hash.clock);
+ clk_enable(stm32_hash.clock);
if (stm32_remain.length != 0U) {
ret = hash_write_data(stm32_remain.buffer);
if (ret != 0) {
- stm32mp_clk_disable(stm32_hash.clock);
+ clk_disable(stm32_hash.clock);
return ret;
}
@@ -260,7 +291,7 @@ int stm32_hash_final(uint8_t *digest)
ret = hash_get_digest(digest);
- stm32mp_clk_disable(stm32_hash.clock);
+ clk_disable(stm32_hash.clock);
return ret;
}
@@ -280,11 +311,11 @@ int stm32_hash_final_update(const uint8_t *buffer, uint32_t length,
void stm32_hash_init(enum stm32_hash_algo_mode mode)
{
- stm32mp_clk_enable(stm32_hash.clock);
+ clk_enable(stm32_hash.clock);
hash_hw_init(mode);
- stm32mp_clk_disable(stm32_hash.clock);
+ clk_disable(stm32_hash.clock);
zeromem(&stm32_remain, sizeof(stm32_remain));
}
@@ -297,17 +328,9 @@ int stm32_hash_register(void)
for (node = dt_get_node(&hash_info, -1, DT_HASH_COMPAT);
node != -FDT_ERR_NOTFOUND;
node = dt_get_node(&hash_info, node, DT_HASH_COMPAT)) {
-#if defined(IMAGE_BL2)
if (hash_info.status != DT_DISABLED) {
break;
}
-#else
- /* BL32 uses hash if it is assigned only to secure world */
- if (hash_info.status == DT_SECURE) {
- stm32mp_register_secure_periph_iomem(hash_info.base);
- break;
- }
-#endif
}
if (node == -FDT_ERR_NOTFOUND) {
@@ -321,7 +344,7 @@ int stm32_hash_register(void)
stm32_hash.base = hash_info.base;
stm32_hash.clock = hash_info.clock;
- stm32mp_clk_enable(stm32_hash.clock);
+ clk_enable(stm32_hash.clock);
if (hash_info.reset >= 0) {
uint32_t id = (uint32_t)hash_info.reset;
@@ -335,7 +358,7 @@ int stm32_hash_register(void)
}
}
- stm32mp_clk_disable(stm32_hash.clock);
+ clk_disable(stm32_hash.clock);
return 0;
}
diff --git a/drivers/st/crypto/stm32_pka.c b/drivers/st/crypto/stm32_pka.c
new file mode 100644
index 0000000000..3054577420
--- /dev/null
+++ b/drivers/st/crypto/stm32_pka.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (c) 2022-2023, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_pka.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+
+#if !PKA_USE_NIST_P256 && !PKA_USE_BRAINPOOL_P256R1 && !PKA_USE_BRAINPOOL_P256T1 && \
+ !PKA_USE_NIST_P521
+#error "At least one ECDSA curve needs to be selected"
+#endif
+
+/*
+ * For our comprehension in this file
+ * _len are in BITs
+ * _size are in BYTEs
+ * _nbw are in number of PKA_word (PKA_word = u64)
+ */
+
+#define UINT8_LEN 8U
+#define UINT64_LEN (UINT8_LEN * sizeof(uint64_t))
+#define PKA_WORD_SIZE (sizeof(uint64_t))
+#define OP_NBW_FROM_LEN(len) (DIV_ROUND_UP_2EVAL((len), UINT64_LEN) + 1)
+#define OP_NBW_FROM_SIZE(s) OP_NBW_FROM_LEN((s) * UINT8_LEN)
+#define OP_SIZE_FROM_SIZE(s) (OP_NBW_FROM_SIZE(s) * PKA_WORD_SIZE)
+
+#define DT_PKA_COMPAT "st,stm32-pka64"
+
+#define MAX_ECC_SIZE_LEN 640U
+#define MAX_EO_NBW OP_NBW_FROM_LEN(MAX_ECC_SIZE_LEN)
+
+/* PKA registers */
+/* PKA control register */
+#define _PKA_CR 0x0U
+/* PKA status register */
+#define _PKA_SR 0x4U
+/* PKA clear flag register */
+#define _PKA_CLRFR 0x8U
+/* PKA version register */
+#define _PKA_VERR 0x1FF4U
+/* PKA identification register */
+#define _PKA_IPIDR 0x1FF8U
+
+/* PKA control register fields */
+#define _PKA_CR_MODE_MASK GENMASK_32(13, 8)
+#define _PKA_CR_MODE_SHIFT 8U
+#define _PKA_CR_MODE_ADD 0x9U
+#define _PKA_CR_MODE_ECDSA_VERIF 0x26U
+#define _PKA_CR_START BIT(1)
+#define _PKA_CR_EN BIT(0)
+
+/* PKA status register fields */
+#define _PKA_SR_BUSY BIT(16)
+#define _PKA_SR_LMF BIT(1)
+#define _PKA_SR_INITOK BIT(0)
+
+/* PKA it flag fields (used in CR, SR and CLRFR) */
+#define _PKA_IT_MASK (GENMASK_32(21, 19) | BIT(17))
+#define _PKA_IT_SHIFT 17U
+#define _PKA_IT_OPERR BIT(21)
+#define _PKA_IT_ADDRERR BIT(20)
+#define _PKA_IT_RAMERR BIT(19)
+#define _PKA_IT_PROCEND BIT(17)
+
+/* PKA version register fields */
+#define _PKA_VERR_MAJREV_MASK GENMASK_32(7, 4)
+#define _PKA_VERR_MAJREV_SHIFT 4U
+#define _PKA_VERR_MINREV_MASK GENMASK_32(3, 0)
+#define _PKA_VERR_MINREV_SHIFT 0U
+
+/* RAM magic offset */
+#define _PKA_RAM_START 0x400U
+#define _PKA_RAM_SIZE 5336U
+
+/* ECDSA verification */
+#define _PKA_RAM_N_LEN 0x408U /* 64 */
+#define _PKA_RAM_P_LEN 0x4C8U /* 64 */
+#define _PKA_RAM_A_SIGN 0x468U /* 64 */
+#define _PKA_RAM_A 0x470U /* EOS */
+#define _PKA_RAM_P 0x4D0U /* EOS */
+#define _PKA_RAM_XG 0x678U /* EOS */
+#define _PKA_RAM_YG 0x6D0U /* EOS */
+#define _PKA_RAM_XQ 0x12F8U /* EOS */
+#define _PKA_RAM_YQ 0x1350U /* EOS */
+#define _PKA_RAM_SIGN_R 0x10E0U /* EOS */
+#define _PKA_RAM_SIGN_S 0xC68U /* EOS */
+#define _PKA_RAM_HASH_Z 0x13A8U /* EOS */
+#define _PKA_RAM_PRIME_N 0x1088U /* EOS */
+#define _PKA_RAM_ECDSA_VERIFY 0x5D0U /* 64 */
+#define _PKA_RAM_ECDSA_VERIFY_VALID 0xD60DULL
+#define _PKA_RAM_ECDSA_VERIFY_INVALID 0xA3B7ULL
+
+#define PKA_TIMEOUT_US 1000000U
+#define TIMEOUT_US_1MS 1000U
+#define PKA_RESET_DELAY 20U
+
+struct curve_parameters {
+ uint32_t a_sign; /* 0 positive, 1 negative */
+ uint8_t *a; /* Curve coefficient |a| */
+ size_t a_size;
+ uint8_t *p; /* Curve modulus value */
+ uint32_t p_len;
+ uint8_t *xg; /* Curve base point G coordinate x */
+ size_t xg_size;
+ uint8_t *yg; /* Curve base point G coordinate y */
+ size_t yg_size;
+ uint8_t *n; /* Curve prime order n */
+ uint32_t n_len;
+};
+
+static const struct curve_parameters curve_def[] = {
+#if PKA_USE_NIST_P256
+ [PKA_NIST_P256] = {
+ .p_len = 256U,
+ .n_len = 256U,
+ .p = (uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ .n = (uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51},
+ .a_sign = 1U,
+ .a = (uint8_t[]){0x03},
+ .a_size = 1U,
+ .xg = (uint8_t[]){0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47,
+ 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
+ 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
+ 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96},
+ .xg_size = 32U,
+ .yg = (uint8_t[]){0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B,
+ 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
+ 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE,
+ 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5},
+ .yg_size = 32U,
+ },
+#endif
+#if PKA_USE_BRAINPOOL_P256R1
+ [PKA_BRAINPOOL_P256R1] = {
+ .p_len = 256,
+ .n_len = 256,
+ .p = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+ 0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+ 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x77},
+ .n = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+ 0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7,
+ 0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7},
+ .a = (uint8_t[]){0x7D, 0x5A, 0x09, 0x75, 0xFC, 0x2C, 0x30, 0x57,
+ 0xEE, 0xF6, 0x75, 0x30, 0x41, 0x7A, 0xFF, 0xE7,
+ 0xFB, 0x80, 0x55, 0xC1, 0x26, 0xDC, 0x5C, 0x6C,
+ 0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9},
+ .a_size = 32U,
+ .xg = (uint8_t[]){0x8B, 0xD2, 0xAE, 0xB9, 0xCB, 0x7E, 0x57, 0xCB,
+ 0x2C, 0x4B, 0x48, 0x2F, 0xFC, 0x81, 0xB7, 0xAF,
+ 0xB9, 0xDE, 0x27, 0xE1, 0xE3, 0xBD, 0x23, 0xC2,
+ 0x3A, 0x44, 0x53, 0xBD, 0x9A, 0xCE, 0x32, 0x62},
+ .xg_size = 32U,
+ .yg = (uint8_t[]){0x54, 0x7E, 0xF8, 0x35, 0xC3, 0xDA, 0xC4, 0xFD,
+ 0x97, 0xF8, 0x46, 0x1A, 0x14, 0x61, 0x1D, 0xC9,
+ 0xC2, 0x77, 0x45, 0x13, 0x2D, 0xED, 0x8E, 0x54,
+ 0x5C, 0x1D, 0x54, 0xC7, 0x2F, 0x04, 0x69, 0x97},
+ .yg_size = 32U,
+ },
+#endif
+#if PKA_USE_BRAINPOOL_P256T1
+ [PKA_BRAINPOOL_P256T1] = {
+ .p_len = 256,
+ .n_len = 256,
+ .p = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+ 0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+ 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x77},
+ .n = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+ 0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7,
+ 0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7},
+ .a = (uint8_t[]){0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+ 0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+ 0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+ 0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x74},
+ .a_size = 32U,
+ .xg = (uint8_t[]){0xA3, 0xE8, 0xEB, 0x3C, 0xC1, 0xCF, 0xE7, 0xB7,
+ 0x73, 0x22, 0x13, 0xB2, 0x3A, 0x65, 0x61, 0x49,
+ 0xAF, 0xA1, 0x42, 0xC4, 0x7A, 0xAF, 0xBC, 0x2B,
+ 0x79, 0xA1, 0x91, 0x56, 0x2E, 0x13, 0x05, 0xF4},
+ .xg_size = 32U,
+ .yg = (uint8_t[]){0x2D, 0x99, 0x6C, 0x82, 0x34, 0x39, 0xC5, 0x6D,
+ 0x7F, 0x7B, 0x22, 0xE1, 0x46, 0x44, 0x41, 0x7E,
+ 0x69, 0xBC, 0xB6, 0xDE, 0x39, 0xD0, 0x27, 0x00,
+ 0x1D, 0xAB, 0xE8, 0xF3, 0x5B, 0x25, 0xC9, 0xBE},
+ .yg_size = 32U,
+ },
+#endif
+#if PKA_USE_NIST_P521
+ [PKA_NIST_P521] = {
+ .p_len = 521,
+ .n_len = 521,
+ .p = (uint8_t[]){ 0x01, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ .n = (uint8_t[]){ 0x01, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa,
+ 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b,
+ 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0,
+ 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae,
+ 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09},
+ .a_sign = 1,
+ .a = (uint8_t[]){0x03},
+ .a_size = 1U,
+ .xg = (uint8_t[]){ 0xc6,
+ 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd,
+ 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42,
+ 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, 0xb5, 0x21,
+ 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba,
+ 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28,
+ 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8, 0xde,
+ 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b,
+ 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66},
+ .xg_size = 65U,
+ .yg = (uint8_t[]){ 0x01, 0x18,
+ 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04,
+ 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9,
+ 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68,
+ 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c,
+ 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40,
+ 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07, 0x61,
+ 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40,
+ 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50},
+ .yg_size = 66U,
+ },
+#endif
+};
+
+static struct stm32_pka_platdata pka_pdata;
+
+static int stm32_pka_parse_fdt(void)
+{
+ int node;
+ struct dt_node_info info;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ node = dt_get_node(&info, -1, DT_PKA_COMPAT);
+ if (node < 0) {
+ ERROR("No PKA entry in DT\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if ((info.base == 0) || (info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ pka_pdata.base = (uintptr_t)info.base;
+ pka_pdata.clock_id = (unsigned long)info.clock;
+ pka_pdata.reset_id = (unsigned int)info.reset;
+
+ return 0;
+}
+
+static int pka_wait_bit(uintptr_t base, uint32_t bit)
+{
+ uint64_t timeout = timeout_init_us(PKA_TIMEOUT_US);
+
+ while ((mmio_read_32(base + _PKA_SR) & bit) != bit) {
+ if (timeout_elapsed(timeout)) {
+ WARN("timeout waiting %x\n", bit);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+
+}
+
+static void pka_disable(uintptr_t base)
+{
+ mmio_clrbits_32(base + _PKA_CR, _PKA_CR_EN);
+}
+
+static int pka_enable(uintptr_t base, uint32_t mode)
+{
+ /* Set mode and disable interrupts */
+ mmio_clrsetbits_32(base + _PKA_CR, _PKA_IT_MASK | _PKA_CR_MODE_MASK,
+ _PKA_CR_MODE_MASK & (mode << _PKA_CR_MODE_SHIFT));
+
+ mmio_setbits_32(base + _PKA_CR, _PKA_CR_EN);
+
+ return pka_wait_bit(base, _PKA_SR_INITOK);
+}
+
+/*
+ * Data are already loaded in PKA internal RAM
+ * MODE is set
+ * We start process, and wait for its end.
+ */
+static int stm32_pka_process(uintptr_t base)
+{
+ mmio_setbits_32(base + _PKA_CR, _PKA_CR_START);
+
+ return pka_wait_bit(base, _PKA_IT_PROCEND);
+}
+
+/**
+ * @brief Write ECC operand to PKA RAM.
+ * @note PKA expect to write u64 word, each u64 are: the least significant bit is
+ * bit 0; the most significant bit is bit 63.
+ * We write eo_nbw (ECC operand Size) u64, value that depends of the chosen
+ * prime modulus length in bits.
+ * First less signicant u64 is written to low address
+ * Most significant u64 to higher address.
+ * And at last address we write a u64(0x0)
+ * @note This function doesn't only manage endianness (as bswap64 do), but also
+ * complete most significant incomplete u64 with 0 (if data is not a u64
+ * multiple), and fill u64 last address with 0.
+ * @param addr: PKA_RAM address to write the buffer 'data'
+ * @param data: is a BYTE list with most significant bytes first
+ * @param data_size: nb of byte in data
+ * @param eo_nbw: is ECC Operand size in 64bits word (including the extra 0)
+ * (note it depends of the prime modulus length, not the data size)
+ * @retval 0 if OK.
+ * -EINVAL if data_size and eo_nbw are inconsistent, ie data doesn't
+ * fit in defined eo_nbw, or eo_nbw bigger than hardware limit.
+ */
+static int write_eo_data(uintptr_t addr, uint8_t *data, unsigned int data_size,
+ unsigned int eo_nbw)
+{
+ uint32_t word_index;
+ int data_index;
+
+ if ((eo_nbw < OP_NBW_FROM_SIZE(data_size)) || (eo_nbw > MAX_EO_NBW)) {
+ return -EINVAL;
+ }
+
+ /* Fill value */
+ data_index = (int)data_size - 1;
+ for (word_index = 0U; word_index < eo_nbw; word_index++) {
+ uint64_t tmp = 0ULL;
+ unsigned int i = 0U; /* index in the tmp U64 word */
+
+ /* Stop if end of tmp or end of data */
+ while ((i < sizeof(tmp)) && (data_index >= 0)) {
+ tmp |= (uint64_t)(data[data_index]) << (UINT8_LEN * i);
+ i++; /* Move byte index in current (u64)tmp */
+ data_index--; /* Move to just next most significat byte */
+ }
+
+ mmio_write_64(addr + word_index * sizeof(tmp), tmp);
+ }
+
+ return 0;
+}
+
+static unsigned int get_ecc_op_nbword(enum stm32_pka_ecdsa_curve_id cid)
+{
+ if (cid >= ARRAY_SIZE(curve_def)) {
+ ERROR("CID %u is out of boundaries\n", cid);
+ panic();
+ }
+
+ return OP_NBW_FROM_LEN(curve_def[cid].n_len);
+}
+
+static int stm32_pka_ecdsa_verif_configure_curve(uintptr_t base, enum stm32_pka_ecdsa_curve_id cid)
+{
+ int ret;
+ unsigned int eo_nbw = get_ecc_op_nbword(cid);
+
+ mmio_write_64(base + _PKA_RAM_N_LEN, curve_def[cid].n_len);
+ mmio_write_64(base + _PKA_RAM_P_LEN, curve_def[cid].p_len);
+ mmio_write_64(base + _PKA_RAM_A_SIGN, curve_def[cid].a_sign);
+
+ ret = write_eo_data(base + _PKA_RAM_A, curve_def[cid].a, curve_def[cid].a_size, eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_PRIME_N,
+ curve_def[cid].n, div_round_up(curve_def[cid].n_len, UINT8_LEN),
+ eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_P, curve_def[cid].p,
+ div_round_up(curve_def[cid].p_len, UINT8_LEN), eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_XG, curve_def[cid].xg, curve_def[cid].xg_size, eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_YG, curve_def[cid].yg, curve_def[cid].yg_size, eo_nbw);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_pka_ecdsa_verif_check_return(uintptr_t base)
+{
+ uint64_t value;
+ uint32_t sr;
+
+ sr = mmio_read_32(base + _PKA_SR);
+ if ((sr & (_PKA_IT_OPERR | _PKA_IT_ADDRERR | _PKA_IT_RAMERR)) != 0) {
+ WARN("Detected error(s): %s%s%s\n",
+ (sr & _PKA_IT_OPERR) ? "Operation " : "",
+ (sr & _PKA_IT_ADDRERR) ? "Address " : "",
+ (sr & _PKA_IT_RAMERR) ? "RAM" : "");
+ return -EINVAL;
+ }
+
+ value = mmio_read_64(base + _PKA_RAM_ECDSA_VERIFY);
+ if (value == _PKA_RAM_ECDSA_VERIFY_VALID) {
+ return 0;
+ }
+
+ if (value == _PKA_RAM_ECDSA_VERIFY_INVALID) {
+ return -EAUTH;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * @brief Check if BigInt stored in data is 0
+ *
+ * @param data: a BYTE array with most significant bytes first
+ * @param size: data size
+ *
+ * @retval: true: if data represents a 0 value (ie all bytes == 0)
+ * false: if data represents a non-zero value.
+ */
+static bool is_zero(uint8_t *data, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0U; i < size; i++) {
+ if (data[i] != 0U) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief Compare two BigInt:
+ * @param xdata_a: a BYTE array with most significant bytes first
+ * @param size_a: nb of Byte of 'a'
+ * @param data_b: a BYTE array with most significant bytes first
+ * @param size_b: nb of Byte of 'b'
+ *
+ * @retval: true if data_a < data_b
+ * false if data_a >= data_b
+ */
+static bool is_smaller(uint8_t *data_a, unsigned int size_a,
+ uint8_t *data_b, unsigned int size_b)
+{
+ unsigned int i;
+
+ i = MAX(size_a, size_b) + 1U;
+ do {
+ uint8_t a, b;
+
+ i--;
+ if (size_a < i) {
+ a = 0U;
+ } else {
+ a = data_a[size_a - i];
+ }
+
+ if (size_b < i) {
+ b = 0U;
+ } else {
+ b = data_b[size_b - i];
+ }
+
+ if (a < b) {
+ return true;
+ }
+
+ if (a > b) {
+ return false;
+ }
+ } while (i != 0U);
+
+ return false;
+}
+
+static int stm32_pka_ecdsa_check_param(void *sig_r_ptr, unsigned int sig_r_size,
+ void *sig_s_ptr, unsigned int sig_s_size,
+ void *pk_x_ptr, unsigned int pk_x_size,
+ void *pk_y_ptr, unsigned int pk_y_size,
+ enum stm32_pka_ecdsa_curve_id cid)
+{
+ /* Public Key check */
+ /* Check Xq < p */
+ if (!is_smaller(pk_x_ptr, pk_x_size,
+ curve_def[cid].p, div_round_up(curve_def[cid].p_len, UINT8_LEN))) {
+ WARN("%s Xq < p inval\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Check Yq < p */
+ if (!is_smaller(pk_y_ptr, pk_y_size,
+ curve_def[cid].p, div_round_up(curve_def[cid].p_len, UINT8_LEN))) {
+ WARN("%s Yq < p inval\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Signature check */
+ /* Check 0 < r < n */
+ if (!is_smaller(sig_r_ptr, sig_r_size,
+ curve_def[cid].n, div_round_up(curve_def[cid].n_len, UINT8_LEN)) &&
+ !is_zero(sig_r_ptr, sig_r_size)) {
+ WARN("%s 0< r < n inval\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Check 0 < s < n */
+ if (!is_smaller(sig_s_ptr, sig_s_size,
+ curve_def[cid].n, div_round_up(curve_def[cid].n_len, UINT8_LEN)) &&
+ !is_zero(sig_s_ptr, sig_s_size)) {
+ WARN("%s 0< s < n inval\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Initialize the PKA driver.
+ * @param None.
+ * @retval 0 if OK, negative value else.
+ */
+int stm32_pka_init(void)
+{
+ int err;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ uint32_t ver;
+ uint32_t id;
+#endif
+
+ err = stm32_pka_parse_fdt();
+ if (err != 0) {
+ return err;
+ }
+
+ clk_enable(pka_pdata.clock_id);
+
+ if (stm32mp_reset_assert((unsigned long)pka_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+ udelay(PKA_RESET_DELAY);
+ if (stm32mp_reset_deassert((unsigned long)pka_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ id = mmio_read_32(pka_pdata.base + _PKA_IPIDR);
+ ver = mmio_read_32(pka_pdata.base + _PKA_VERR);
+
+ VERBOSE("STM32 PKA[%x] V%u.%u\n", id,
+ (ver & _PKA_VERR_MAJREV_MASK) >> _PKA_VERR_MAJREV_SHIFT,
+ (ver & _PKA_VERR_MINREV_MASK) >> _PKA_VERR_MINREV_SHIFT);
+#endif
+ return 0;
+}
+
+int stm32_pka_ecdsa_verif(void *hash, unsigned int hash_size,
+ void *sig_r_ptr, unsigned int sig_r_size,
+ void *sig_s_ptr, unsigned int sig_s_size,
+ void *pk_x_ptr, unsigned int pk_x_size,
+ void *pk_y_ptr, unsigned int pk_y_size,
+ enum stm32_pka_ecdsa_curve_id cid)
+{
+ int ret;
+ uintptr_t base = pka_pdata.base;
+ unsigned int eo_nbw = get_ecc_op_nbword(cid);
+
+ if ((hash == NULL) || (sig_r_ptr == NULL) || (sig_s_ptr == NULL) ||
+ (pk_x_ptr == NULL) || (pk_y_ptr == NULL)) {
+ INFO("%s invalid input param\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = stm32_pka_ecdsa_check_param(sig_r_ptr, sig_r_size,
+ sig_s_ptr, sig_s_size,
+ pk_x_ptr, pk_x_size,
+ pk_y_ptr, pk_y_size,
+ cid);
+ if (ret < 0) {
+ INFO("%s check param error %d\n", __func__, ret);
+ goto out;
+ }
+
+ if ((mmio_read_32(base + _PKA_SR) & _PKA_SR_BUSY) == _PKA_SR_BUSY) {
+ INFO("%s busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Fill PKA RAM */
+ /* With curve id values */
+ ret = stm32_pka_ecdsa_verif_configure_curve(base, cid);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* With pubkey */
+ ret = write_eo_data(base + _PKA_RAM_XQ, pk_x_ptr, pk_x_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_YQ, pk_y_ptr, pk_y_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* With hash */
+ ret = write_eo_data(base + _PKA_RAM_HASH_Z, hash, hash_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* With signature */
+ ret = write_eo_data(base + _PKA_RAM_SIGN_R, sig_r_ptr, sig_r_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = write_eo_data(base + _PKA_RAM_SIGN_S, sig_s_ptr, sig_s_size, eo_nbw);
+ if (ret < 0) {
+ goto out;
+ }
+
+ /* Set mode to ecdsa signature verification */
+ ret = pka_enable(base, _PKA_CR_MODE_ECDSA_VERIF);
+ if (ret < 0) {
+ WARN("%s set mode pka error %d\n", __func__, ret);
+ goto out;
+ }
+
+ /* Start processing and wait end */
+ ret = stm32_pka_process(base);
+ if (ret < 0) {
+ WARN("%s process error %d\n", __func__, ret);
+ goto out;
+ }
+
+ /* Check return status */
+ ret = stm32_pka_ecdsa_verif_check_return(base);
+
+ /* Unset end proc */
+ mmio_setbits_32(base + _PKA_CLRFR, _PKA_IT_PROCEND);
+
+out:
+ /* Disable PKA (will stop all pending process and reset RAM) */
+ pka_disable(base);
+
+ return ret;
+}
diff --git a/drivers/st/crypto/stm32_rng.c b/drivers/st/crypto/stm32_rng.c
new file mode 100644
index 0000000000..1342fd4549
--- /dev/null
+++ b/drivers/st/crypto/stm32_rng.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#if STM32_RNG_VER == 2
+#define DT_RNG_COMPAT "st,stm32-rng"
+#endif
+#if STM32_RNG_VER == 4
+#define DT_RNG_COMPAT "st,stm32mp13-rng"
+#endif
+#define RNG_CR 0x00U
+#define RNG_SR 0x04U
+#define RNG_DR 0x08U
+
+#define RNG_CR_RNGEN BIT(2)
+#define RNG_CR_IE BIT(3)
+#define RNG_CR_CED BIT(5)
+#define RNG_CR_CLKDIV GENMASK(19, 16)
+#define RNG_CR_CLKDIV_SHIFT 16U
+#define RNG_CR_CONDRST BIT(30)
+
+#define RNG_SR_DRDY BIT(0)
+#define RNG_SR_CECS BIT(1)
+#define RNG_SR_SECS BIT(2)
+#define RNG_SR_CEIS BIT(5)
+#define RNG_SR_SEIS BIT(6)
+
+#define RNG_TIMEOUT_US 100000U
+#define RNG_TIMEOUT_STEP_US 10U
+
+#define TIMEOUT_US_1MS 1000U
+
+#define RNG_NIST_CONFIG_A 0x00F40F00U
+#define RNG_NIST_CONFIG_B 0x01801000U
+#define RNG_NIST_CONFIG_C 0x00F00D00U
+#define RNG_NIST_CONFIG_MASK GENMASK(25, 8)
+
+#define RNG_MAX_NOISE_CLK_FREQ 48000000U
+
+struct stm32_rng_instance {
+ uintptr_t base;
+ unsigned long clock;
+};
+
+static struct stm32_rng_instance stm32_rng;
+
+static void seed_error_recovery(void)
+{
+ uint8_t i __maybe_unused;
+
+ /* Recommended by the SoC reference manual */
+ mmio_clrbits_32(stm32_rng.base + RNG_SR, RNG_SR_SEIS);
+ dmbsy();
+
+#if STM32_RNG_VER == 2
+ /* No Auto-reset on version 2, need to clean FIFO */
+ for (i = 12U; i != 0U; i--) {
+ (void)mmio_read_32(stm32_rng.base + RNG_DR);
+ }
+
+ dmbsy();
+#endif
+
+ if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_SEIS) != 0U) {
+ ERROR("RNG noise\n");
+ panic();
+ }
+}
+
+static uint32_t stm32_rng_clock_freq_restrain(void)
+{
+ unsigned long clock_rate;
+ uint32_t clock_div = 0U;
+
+ clock_rate = clk_get_rate(stm32_rng.clock);
+
+ /*
+ * Get the exponent to apply on the CLKDIV field in RNG_CR register
+ * No need to handle the case when clock-div > 0xF as it is physically
+ * impossible
+ */
+ while ((clock_rate >> clock_div) > RNG_MAX_NOISE_CLK_FREQ) {
+ clock_div++;
+ }
+
+ VERBOSE("RNG clk rate : %lu\n", clk_get_rate(stm32_rng.clock) >> clock_div);
+
+ return clock_div;
+}
+
+static int stm32_rng_enable(void)
+{
+ uint32_t sr;
+ uint64_t timeout;
+ uint32_t clock_div __maybe_unused;
+
+#if STM32_RNG_VER == 2
+ mmio_write_32(stm32_rng.base + RNG_CR, RNG_CR_RNGEN | RNG_CR_CED);
+#endif
+#if STM32_RNG_VER == 4
+ /* Reset internal block and disable CED bit */
+ clock_div = stm32_rng_clock_freq_restrain();
+
+ /* Update configuration fields */
+ mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_NIST_CONFIG_MASK,
+ RNG_NIST_CONFIG_A | RNG_CR_CONDRST | RNG_CR_CED);
+
+ mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CLKDIV,
+ (clock_div << RNG_CR_CLKDIV_SHIFT));
+
+ mmio_clrsetbits_32(stm32_rng.base + RNG_CR, RNG_CR_CONDRST, RNG_CR_RNGEN);
+#endif
+ timeout = timeout_init_us(RNG_TIMEOUT_US);
+ sr = mmio_read_32(stm32_rng.base + RNG_SR);
+ while ((sr & RNG_SR_DRDY) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ WARN("Timeout waiting\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((sr & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
+ seed_error_recovery();
+ timeout = timeout_init_us(RNG_TIMEOUT_US);
+ }
+
+ udelay(RNG_TIMEOUT_STEP_US);
+ sr = mmio_read_32(stm32_rng.base + RNG_SR);
+ }
+
+ VERBOSE("Init RNG done\n");
+
+ return 0;
+}
+
+/*
+ * stm32_rng_read - Read a number of random bytes from RNG
+ * out: pointer to the output buffer
+ * size: number of bytes to be read
+ * Return 0 on success, non-0 on failure
+ */
+int stm32_rng_read(uint8_t *out, uint32_t size)
+{
+ uint8_t *buf = out;
+ size_t len = size;
+ int nb_tries;
+ uint32_t data32;
+ int rc = 0;
+ unsigned int count;
+
+ if (stm32_rng.base == 0U) {
+ return -EPERM;
+ }
+
+ while (len != 0U) {
+ nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US;
+ do {
+ uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR);
+
+ if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
+ seed_error_recovery();
+ }
+
+ udelay(RNG_TIMEOUT_STEP_US);
+ nb_tries--;
+ if (nb_tries == 0) {
+ rc = -ETIMEDOUT;
+ goto bail;
+ }
+ } while ((mmio_read_32(stm32_rng.base + RNG_SR) &
+ RNG_SR_DRDY) == 0U);
+
+ count = 4U;
+ while (len != 0U) {
+ if ((mmio_read_32(stm32_rng.base + RNG_SR) & RNG_SR_DRDY) == 0U) {
+ break;
+ }
+
+ data32 = mmio_read_32(stm32_rng.base + RNG_DR);
+ count--;
+
+ memcpy(buf, &data32, MIN(len, sizeof(uint32_t)));
+ buf += MIN(len, sizeof(uint32_t));
+ len -= MIN(len, sizeof(uint32_t));
+
+ if (count == 0U) {
+ break;
+ }
+ }
+ }
+
+bail:
+ if (rc != 0) {
+ memset(out, 0, buf - out);
+ }
+
+ return rc;
+}
+
+/*
+ * stm32_rng_init: Initialize rng from DT
+ * return 0 on success, negative value on failure
+ */
+int stm32_rng_init(void)
+{
+ void *fdt;
+ struct dt_node_info dt_rng;
+ int node;
+
+ if (stm32_rng.base != 0U) {
+ /* Driver is already initialized */
+ return 0;
+ }
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT);
+ if (node < 0) {
+ return 0;
+ }
+
+ if (dt_rng.status == DT_DISABLED) {
+ return 0;
+ }
+
+ assert(dt_rng.base != 0U);
+
+ stm32_rng.base = dt_rng.base;
+
+ if (dt_rng.clock < 0) {
+ panic();
+ }
+
+ stm32_rng.clock = (unsigned long)dt_rng.clock;
+ clk_enable(stm32_rng.clock);
+
+ if (dt_rng.reset >= 0) {
+ int ret;
+
+ ret = stm32mp_reset_assert((unsigned long)dt_rng.reset,
+ TIMEOUT_US_1MS);
+ if (ret != 0) {
+ panic();
+ }
+
+ udelay(20);
+
+ ret = stm32mp_reset_deassert((unsigned long)dt_rng.reset,
+ TIMEOUT_US_1MS);
+ if (ret != 0) {
+ panic();
+ }
+ }
+
+ return stm32_rng_enable();
+}
diff --git a/drivers/st/crypto/stm32_saes.c b/drivers/st/crypto/stm32_saes.c
new file mode 100644
index 0000000000..f4da571fb4
--- /dev/null
+++ b/drivers/st/crypto/stm32_saes.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_saes.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#define UINT8_BIT 8U
+#define AES_BLOCK_SIZE_BIT 128U
+#define AES_BLOCK_SIZE (AES_BLOCK_SIZE_BIT / UINT8_BIT)
+
+#define AES_KEYSIZE_128 16U
+#define AES_KEYSIZE_256 32U
+#define AES_IVSIZE 16U
+
+/* SAES control register */
+#define _SAES_CR 0x0U
+/* SAES status register */
+#define _SAES_SR 0x04U
+/* SAES data input register */
+#define _SAES_DINR 0x08U
+/* SAES data output register */
+#define _SAES_DOUTR 0x0CU
+/* SAES key registers [0-3] */
+#define _SAES_KEYR0 0x10U
+#define _SAES_KEYR1 0x14U
+#define _SAES_KEYR2 0x18U
+#define _SAES_KEYR3 0x1CU
+/* SAES initialization vector registers [0-3] */
+#define _SAES_IVR0 0x20U
+#define _SAES_IVR1 0x24U
+#define _SAES_IVR2 0x28U
+#define _SAES_IVR3 0x2CU
+/* SAES key registers [4-7] */
+#define _SAES_KEYR4 0x30U
+#define _SAES_KEYR5 0x34U
+#define _SAES_KEYR6 0x38U
+#define _SAES_KEYR7 0x3CU
+/* SAES suspend registers [0-7] */
+#define _SAES_SUSPR0 0x40U
+#define _SAES_SUSPR1 0x44U
+#define _SAES_SUSPR2 0x48U
+#define _SAES_SUSPR3 0x4CU
+#define _SAES_SUSPR4 0x50U
+#define _SAES_SUSPR5 0x54U
+#define _SAES_SUSPR6 0x58U
+#define _SAES_SUSPR7 0x5CU
+/* SAES Interrupt Enable Register */
+#define _SAES_IER 0x300U
+/* SAES Interrupt Status Register */
+#define _SAES_ISR 0x304U
+/* SAES Interrupt Clear Register */
+#define _SAES_ICR 0x308U
+
+/* SAES control register fields */
+#define _SAES_CR_RESET_VALUE 0x0U
+#define _SAES_CR_IPRST BIT(31)
+#define _SAES_CR_KEYSEL_MASK GENMASK(30, 28)
+#define _SAES_CR_KEYSEL_SHIFT 28U
+#define _SAES_CR_KEYSEL_SOFT 0x0U
+#define _SAES_CR_KEYSEL_DHUK 0x1U
+#define _SAES_CR_KEYSEL_BHK 0x2U
+#define _SAES_CR_KEYSEL_BHU_XOR_BH_K 0x4U
+#define _SAES_CR_KEYSEL_TEST 0x7U
+#define _SAES_CR_KSHAREID_MASK GENMASK(27, 26)
+#define _SAES_CR_KSHAREID_SHIFT 26U
+#define _SAES_CR_KSHAREID_CRYP 0x0U
+#define _SAES_CR_KEYMOD_MASK GENMASK(25, 24)
+#define _SAES_CR_KEYMOD_SHIFT 24U
+#define _SAES_CR_KEYMOD_NORMAL 0x0U
+#define _SAES_CR_KEYMOD_WRAPPED 0x1U
+#define _SAES_CR_KEYMOD_SHARED 0x2U
+#define _SAES_CR_NPBLB_MASK GENMASK(23, 20)
+#define _SAES_CR_NPBLB_SHIFT 20U
+#define _SAES_CR_KEYPROT BIT(19)
+#define _SAES_CR_KEYSIZE BIT(18)
+#define _SAES_CR_GCMPH_MASK GENMASK(14, 13)
+#define _SAES_CR_GCMPH_SHIFT 13U
+#define _SAES_CR_GCMPH_INIT 0U
+#define _SAES_CR_GCMPH_HEADER 1U
+#define _SAES_CR_GCMPH_PAYLOAD 2U
+#define _SAES_CR_GCMPH_FINAL 3U
+#define _SAES_CR_DMAOUTEN BIT(12)
+#define _SAES_CR_DMAINEN BIT(11)
+#define _SAES_CR_CHMOD_MASK (BIT(16) | GENMASK(6, 5))
+#define _SAES_CR_CHMOD_SHIFT 5U
+#define _SAES_CR_CHMOD_ECB 0x0U
+#define _SAES_CR_CHMOD_CBC 0x1U
+#define _SAES_CR_CHMOD_CTR 0x2U
+#define _SAES_CR_CHMOD_GCM 0x3U
+#define _SAES_CR_CHMOD_GMAC 0x3U
+#define _SAES_CR_CHMOD_CCM 0x800U
+#define _SAES_CR_MODE_MASK GENMASK(4, 3)
+#define _SAES_CR_MODE_SHIFT 3U
+#define _SAES_CR_MODE_ENC 0U
+#define _SAES_CR_MODE_KEYPREP 1U
+#define _SAES_CR_MODE_DEC 2U
+#define _SAES_CR_DATATYPE_MASK GENMASK(2, 1)
+#define _SAES_CR_DATATYPE_SHIFT 1U
+#define _SAES_CR_DATATYPE_NONE 0U
+#define _SAES_CR_DATATYPE_HALF_WORD 1U
+#define _SAES_CR_DATATYPE_BYTE 2U
+#define _SAES_CR_DATATYPE_BIT 3U
+#define _SAES_CR_EN BIT(0)
+
+/* SAES status register fields */
+#define _SAES_SR_KEYVALID BIT(7)
+#define _SAES_SR_BUSY BIT(3)
+#define _SAES_SR_WRERR BIT(2)
+#define _SAES_SR_RDERR BIT(1)
+#define _SAES_SR_CCF BIT(0)
+
+/* SAES interrupt registers fields */
+#define _SAES_I_RNG_ERR BIT(3)
+#define _SAES_I_KEY_ERR BIT(2)
+#define _SAES_I_RW_ERR BIT(1)
+#define _SAES_I_CC BIT(0)
+
+#define SAES_TIMEOUT_US 100000U
+#define TIMEOUT_US_1MS 1000U
+#define SAES_RESET_DELAY 20U
+
+#define IS_CHAINING_MODE(mod, cr) \
+ (((cr) & _SAES_CR_CHMOD_MASK) == (_SAES_CR_CHMOD_##mod << _SAES_CR_CHMOD_SHIFT))
+
+#define SET_CHAINING_MODE(mod, cr) \
+ mmio_clrsetbits_32((cr), _SAES_CR_CHMOD_MASK, _SAES_CR_CHMOD_##mod << _SAES_CR_CHMOD_SHIFT)
+
+static struct stm32_saes_platdata saes_pdata;
+
+static int stm32_saes_parse_fdt(struct stm32_saes_platdata *pdata)
+{
+ int node;
+ struct dt_node_info info;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ node = dt_get_node(&info, -1, DT_SAES_COMPAT);
+ if (node < 0) {
+ ERROR("No SAES entry in DT\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if ((info.base == 0U) || (info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ pdata->base = (uintptr_t)info.base;
+ pdata->clock_id = (unsigned long)info.clock;
+ pdata->reset_id = (unsigned int)info.reset;
+
+ return 0;
+}
+
+static bool does_chaining_mode_need_iv(uint32_t cr)
+{
+ return !(IS_CHAINING_MODE(ECB, cr));
+}
+
+static bool is_encrypt(uint32_t cr)
+{
+ return (cr & _SAES_CR_MODE_MASK) == (_SAES_CR_MODE_ENC << _SAES_CR_MODE_SHIFT);
+}
+
+static bool is_decrypt(uint32_t cr)
+{
+ return (cr & _SAES_CR_MODE_MASK) == (_SAES_CR_MODE_DEC << _SAES_CR_MODE_SHIFT);
+}
+
+static int wait_computation_completed(uintptr_t base)
+{
+ uint64_t timeout = timeout_init_us(SAES_TIMEOUT_US);
+
+ while ((mmio_read_32(base + _SAES_SR) & _SAES_SR_CCF) != _SAES_SR_CCF) {
+ if (timeout_elapsed(timeout)) {
+ WARN("%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static void clear_computation_completed(uintptr_t base)
+{
+ mmio_setbits_32(base + _SAES_ICR, _SAES_I_CC);
+}
+
+static int saes_start(struct stm32_saes_context *ctx)
+{
+ uint64_t timeout;
+
+ /* Reset IP */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+ udelay(SAES_RESET_DELAY);
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+
+ timeout = timeout_init_us(SAES_TIMEOUT_US);
+ while ((mmio_read_32(ctx->base + _SAES_SR) & _SAES_SR_BUSY) == _SAES_SR_BUSY) {
+ if (timeout_elapsed(timeout)) {
+ WARN("%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static void saes_end(struct stm32_saes_context *ctx, int prev_error)
+{
+ if (prev_error != 0) {
+ /* Reset IP */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+ udelay(SAES_RESET_DELAY);
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+ }
+
+ /* Disable the SAES peripheral */
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+}
+
+static void saes_write_iv(struct stm32_saes_context *ctx)
+{
+ /* If chaining mode need to restore IV */
+ if (does_chaining_mode_need_iv(ctx->cr)) {
+ uint8_t i;
+
+ /* Restore the _SAES_IVRx */
+ for (i = 0U; i < AES_IVSIZE / sizeof(uint32_t); i++) {
+ mmio_write_32(ctx->base + _SAES_IVR0 + i * sizeof(uint32_t), ctx->iv[i]);
+ }
+ }
+
+}
+
+static void saes_write_key(struct stm32_saes_context *ctx)
+{
+ /* Restore the _SAES_KEYRx if SOFTWARE key */
+ if ((ctx->cr & _SAES_CR_KEYSEL_MASK) == (_SAES_CR_KEYSEL_SOFT << _SAES_CR_KEYSEL_SHIFT)) {
+ uint8_t i;
+
+ for (i = 0U; i < AES_KEYSIZE_128 / sizeof(uint32_t); i++) {
+ mmio_write_32(ctx->base + _SAES_KEYR0 + i * sizeof(uint32_t), ctx->key[i]);
+ }
+
+ if ((ctx->cr & _SAES_CR_KEYSIZE) == _SAES_CR_KEYSIZE) {
+ for (i = 0U; i < (AES_KEYSIZE_256 / 2U) / sizeof(uint32_t); i++) {
+ mmio_write_32(ctx->base + _SAES_KEYR4 + i * sizeof(uint32_t),
+ ctx->key[i + 4U]);
+ }
+ }
+ }
+}
+
+static int saes_prepare_key(struct stm32_saes_context *ctx)
+{
+ /* Disable the SAES peripheral */
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ /* Set key size */
+ if ((ctx->cr & _SAES_CR_KEYSIZE) != 0U) {
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_KEYSIZE);
+ } else {
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_KEYSIZE);
+ }
+
+ saes_write_key(ctx);
+
+ /* For ECB/CBC decryption, key preparation mode must be selected to populate the key */
+ if ((IS_CHAINING_MODE(ECB, ctx->cr) || IS_CHAINING_MODE(CBC, ctx->cr)) &&
+ is_decrypt(ctx->cr)) {
+ int ret;
+
+ /* Select Mode 2 */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_KEYPREP << _SAES_CR_MODE_SHIFT);
+
+ /* Enable SAES */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ /* Wait Computation completed */
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ return ret;
+ }
+
+ clear_computation_completed(ctx->base);
+
+ /* Set Mode 3 */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_DEC << _SAES_CR_MODE_SHIFT);
+ }
+
+ return 0;
+}
+
+static int save_context(struct stm32_saes_context *ctx)
+{
+ if ((mmio_read_32(ctx->base + _SAES_SR) & _SAES_SR_CCF) != 0U) {
+ /* Device should not be in a processing phase */
+ return -EINVAL;
+ }
+
+ /* Save CR */
+ ctx->cr = mmio_read_32(ctx->base + _SAES_CR);
+
+ /* If chaining mode need to save current IV */
+ if (does_chaining_mode_need_iv(ctx->cr)) {
+ uint8_t i;
+
+ /* Save IV */
+ for (i = 0U; i < AES_IVSIZE / sizeof(uint32_t); i++) {
+ ctx->iv[i] = mmio_read_32(ctx->base + _SAES_IVR0 + i * sizeof(uint32_t));
+ }
+ }
+
+ /* Disable the SAES peripheral */
+ mmio_clrbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ return 0;
+}
+
+/* To resume the processing of a message */
+static int restore_context(struct stm32_saes_context *ctx)
+{
+ int ret;
+
+ /* IP should be disabled */
+ if ((mmio_read_32(ctx->base + _SAES_CR) & _SAES_CR_EN) != 0U) {
+ VERBOSE("%s: Device is still enabled\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Reset internal state */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_IPRST);
+
+ /* Restore the _SAES_CR */
+ mmio_write_32(ctx->base + _SAES_CR, ctx->cr);
+
+ /* Preparation decrypt key */
+ ret = saes_prepare_key(ctx);
+ if (ret != 0) {
+ return ret;
+ }
+
+ saes_write_iv(ctx);
+
+ /* Enable the SAES peripheral */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ return 0;
+}
+
+/**
+ * @brief Initialize SAES driver.
+ * @param None.
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_driver_init(void)
+{
+ int err;
+
+ err = stm32_saes_parse_fdt(&saes_pdata);
+ if (err != 0) {
+ return err;
+ }
+
+ clk_enable(saes_pdata.clock_id);
+ if (stm32mp_reset_assert(saes_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+ udelay(SAES_RESET_DELAY);
+ if (stm32mp_reset_deassert(saes_pdata.reset_id, TIMEOUT_US_1MS) != 0) {
+ panic();
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Start a AES computation.
+ * @param ctx: SAES process context
+ * @param is_dec: true if decryption, false if encryption
+ * @param ch_mode: define the chaining mode
+ * @param key_select: define where the key comes from.
+ * @param key: pointer to key (if key_select is KEY_SOFT, else unused)
+ * @param key_size: key size
+ * @param iv: pointer to initialization vectore (unsed if ch_mode is ECB)
+ * @param iv_size: iv size
+ * @note this function doesn't access to hardware but store in ctx the values
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_init(struct stm32_saes_context *ctx, bool is_dec,
+ enum stm32_saes_chaining_mode ch_mode, enum stm32_saes_key_selection key_select,
+ const void *key, size_t key_size, const void *iv, size_t iv_size)
+{
+ unsigned int i;
+ const uint32_t *iv_u32;
+ const uint32_t *key_u32;
+
+ ctx->assoc_len = 0U;
+ ctx->load_len = 0U;
+
+ ctx->base = saes_pdata.base;
+ ctx->cr = _SAES_CR_RESET_VALUE;
+
+ /* We want buffer to be u32 aligned */
+ assert((uintptr_t)key % __alignof__(uint32_t) == 0);
+ assert((uintptr_t)iv % __alignof__(uint32_t) == 0);
+
+ iv_u32 = iv;
+ key_u32 = key;
+
+ if (is_dec) {
+ /* Save Mode 3 = decrypt */
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_DEC << _SAES_CR_MODE_SHIFT);
+ } else {
+ /* Save Mode 1 = crypt */
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_MODE_MASK,
+ _SAES_CR_MODE_ENC << _SAES_CR_MODE_SHIFT);
+ }
+
+ /* Save chaining mode */
+ switch (ch_mode) {
+ case STM32_SAES_MODE_ECB:
+ SET_CHAINING_MODE(ECB, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_CBC:
+ SET_CHAINING_MODE(CBC, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_CTR:
+ SET_CHAINING_MODE(CTR, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_GCM:
+ SET_CHAINING_MODE(GCM, (uintptr_t)&(ctx->cr));
+ break;
+ case STM32_SAES_MODE_CCM:
+ SET_CHAINING_MODE(CCM, (uintptr_t)&(ctx->cr));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* We will use HW Byte swap (_SAES_CR_DATATYPE_BYTE) for data.
+ * so we won't need to
+ * htobe32(data) before write to DINR
+ * nor
+ * be32toh after reading from DOUTR
+ *
+ * But note that wrap key only accept _SAES_CR_DATATYPE_NONE
+ */
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_DATATYPE_MASK,
+ _SAES_CR_DATATYPE_BYTE << _SAES_CR_DATATYPE_SHIFT);
+
+ /* Configure keysize */
+ switch (key_size) {
+ case AES_KEYSIZE_128:
+ mmio_clrbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSIZE);
+ break;
+ case AES_KEYSIZE_256:
+ mmio_setbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSIZE);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Configure key */
+ switch (key_select) {
+ case STM32_SAES_KEY_SOFT:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_SOFT << _SAES_CR_KEYSEL_SHIFT);
+ /* Save key */
+ switch (key_size) {
+ case AES_KEYSIZE_128:
+ /* First 16 bytes == 4 u32 */
+ for (i = 0U; i < AES_KEYSIZE_128 / sizeof(uint32_t); i++) {
+ mmio_write_32((uintptr_t)(ctx->key + i), htobe32(key_u32[3 - i]));
+ /* /!\ we save the key in HW byte order
+ * and word order : key[i] is for _SAES_KEYRi
+ */
+ }
+ break;
+ case AES_KEYSIZE_256:
+ for (i = 0U; i < AES_KEYSIZE_256 / sizeof(uint32_t); i++) {
+ mmio_write_32((uintptr_t)(ctx->key + i), htobe32(key_u32[7 - i]));
+ /* /!\ we save the key in HW byte order
+ * and word order : key[i] is for _SAES_KEYRi
+ */
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ break;
+ case STM32_SAES_KEY_DHU:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_DHUK << _SAES_CR_KEYSEL_SHIFT);
+ break;
+ case STM32_SAES_KEY_BH:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_BHK << _SAES_CR_KEYSEL_SHIFT);
+ break;
+ case STM32_SAES_KEY_BHU_XOR_BH:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_BHU_XOR_BH_K << _SAES_CR_KEYSEL_SHIFT);
+ break;
+ case STM32_SAES_KEY_WRAPPED:
+ mmio_clrsetbits_32((uintptr_t)&(ctx->cr), _SAES_CR_KEYSEL_MASK,
+ _SAES_CR_KEYSEL_SOFT << _SAES_CR_KEYSEL_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Save IV */
+ if (ch_mode != STM32_SAES_MODE_ECB) {
+ if ((iv == NULL) || (iv_size != AES_IVSIZE)) {
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < AES_IVSIZE / sizeof(uint32_t); i++) {
+ mmio_write_32((uintptr_t)(ctx->iv + i), htobe32(iv_u32[3 - i]));
+ /* /!\ We save the iv in HW byte order */
+ }
+ }
+
+ return saes_start(ctx);
+}
+
+/**
+ * @brief Update (or start) a AES authentificate process of associated data (CCM or GCM).
+ * @param ctx: SAES process context
+ * @param last_block: true if last assoc data block
+ * @param data: pointer to associated data
+ * @param data_size: data size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_update_assodata(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data, size_t data_size)
+{
+ int ret;
+ uint32_t *data_u32;
+ unsigned int i = 0U;
+
+ /* We want buffers to be u32 aligned */
+ assert((uintptr_t)data % __alignof__(uint32_t) == 0);
+ data_u32 = (uint32_t *)data;
+
+ /* Init phase */
+ ret = restore_context(ctx);
+ if (ret != 0) {
+ goto out;
+ }
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ return ret;
+ }
+
+ clear_computation_completed(ctx->base);
+
+ if ((data == NULL) || (data_size == 0U)) {
+ /* No associated data */
+ /* ret already = 0 */
+ goto out;
+ }
+
+ /* There is an header/associated data phase */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_GCMPH_MASK,
+ _SAES_CR_GCMPH_HEADER << _SAES_CR_GCMPH_SHIFT);
+
+ /* Enable the SAES peripheral */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+
+ while (i < round_down(data_size, AES_BLOCK_SIZE)) {
+ unsigned int w; /* Word index */
+
+ w = i / sizeof(uint32_t);
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_u32[w + 3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ clear_computation_completed(ctx->base);
+
+ /* Process next block */
+ i += AES_BLOCK_SIZE;
+ ctx->assoc_len += AES_BLOCK_SIZE_BIT;
+ }
+
+ /* Manage last block if not a block size multiple */
+ if ((last_block) && (i < data_size)) {
+ /* We don't manage unaligned last block yet */
+ ret = -ENODEV;
+ goto out;
+ }
+
+out:
+ if (ret != 0) {
+ saes_end(ctx, ret);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Update (or start) a AES authenticate and de/encrypt with payload data (CCM or GCM).
+ * @param ctx: SAES process context
+ * @param last_block: true if last payload data block
+ * @param data_in: pointer to payload
+ * @param data_out: pointer where to save de/encrypted payload
+ * @param data_size: payload size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_update_load(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data_in, uint8_t *data_out, size_t data_size)
+{
+ int ret = 0;
+ uint32_t *data_in_u32;
+ uint32_t *data_out_u32;
+ unsigned int i = 0U;
+ uint32_t prev_cr;
+
+ /* We want buffers to be u32 aligned */
+ assert((uintptr_t)data_in % __alignof__(uint32_t) == 0);
+ assert((uintptr_t)data_out % __alignof__(uint32_t) == 0);
+ data_in_u32 = (uint32_t *)data_in;
+ data_out_u32 = (uint32_t *)data_out;
+
+ prev_cr = mmio_read_32(ctx->base + _SAES_CR);
+
+ if ((data_in == NULL) || (data_size == 0U)) {
+ /* there is no data */
+ goto out;
+ }
+
+ /* There is a load phase */
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_GCMPH_MASK,
+ _SAES_CR_GCMPH_PAYLOAD << _SAES_CR_GCMPH_SHIFT);
+
+ if ((prev_cr & _SAES_CR_GCMPH_MASK) ==
+ (_SAES_CR_GCMPH_INIT << _SAES_CR_GCMPH_SHIFT)) {
+ /* Still in initialization phase, no header
+ * We need to enable the SAES peripheral
+ */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+ }
+
+ while (i < round_down(data_size, AES_BLOCK_SIZE)) {
+ unsigned int w; /* Word index */
+
+ w = i / sizeof(uint32_t);
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ data_out_u32[w + 0U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 1U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 2U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 3U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ /* Process next block */
+ i += AES_BLOCK_SIZE;
+ ctx->load_len += AES_BLOCK_SIZE_BIT;
+ }
+ /* Manage last block if not a block size multiple */
+ if ((last_block) && (i < data_size)) {
+ uint32_t block_in[AES_BLOCK_SIZE / sizeof(uint32_t)] = {0};
+ uint32_t block_out[AES_BLOCK_SIZE / sizeof(uint32_t)] = {0};
+
+ memcpy(block_in, data_in + i, data_size - i);
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, block_in[3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ VERBOSE("%s %d\n", __func__, __LINE__);
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ block_out[0U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ block_out[1U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ block_out[2U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ block_out[3U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ memcpy(data_out + i, block_out, data_size - i);
+
+ ctx->load_len += (data_size - i) * UINT8_BIT;
+ }
+
+out:
+ if (ret != 0) {
+ saes_end(ctx, ret);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Get authentication tag for AES authenticated algorithms (CCM or GCM).
+ * @param ctx: SAES process context
+ * @param tag: pointer where to save the tag
+ * @param data_size: tag size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_final(struct stm32_saes_context *ctx, uint8_t *tag,
+ size_t tag_size)
+{
+ int ret;
+ uint32_t tag_u32[4];
+ uint32_t prev_cr;
+
+ prev_cr = mmio_read_32(ctx->base + _SAES_CR);
+
+ mmio_clrsetbits_32(ctx->base + _SAES_CR, _SAES_CR_GCMPH_MASK,
+ _SAES_CR_GCMPH_FINAL << _SAES_CR_GCMPH_SHIFT);
+
+ if ((prev_cr & _SAES_CR_GCMPH_MASK) == (_SAES_CR_GCMPH_INIT << _SAES_CR_GCMPH_SHIFT)) {
+ /* Still in initialization phase, no header
+ * We need to enable the SAES peripheral
+ */
+ mmio_setbits_32(ctx->base + _SAES_CR, _SAES_CR_EN);
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, 0);
+ mmio_write_32(ctx->base + _SAES_DINR, ctx->assoc_len);
+ mmio_write_32(ctx->base + _SAES_DINR, 0);
+ mmio_write_32(ctx->base + _SAES_DINR, ctx->load_len);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ tag_u32[0] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ tag_u32[1] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ tag_u32[2] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ tag_u32[3] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ memcpy(tag, tag_u32, MIN(sizeof(tag_u32), tag_size));
+
+out:
+ saes_end(ctx, ret);
+
+ return ret;
+}
+
+/**
+ * @brief Update (or start) a AES de/encrypt process (ECB, CBC or CTR).
+ * @param ctx: SAES process context
+ * @param last_block: true if last payload data block
+ * @param data_in: pointer to payload
+ * @param data_out: pointer where to save de/encrypted payload
+ * @param data_size: payload size
+ *
+ * @retval 0 if OK; negative value else.
+ */
+int stm32_saes_update(struct stm32_saes_context *ctx, bool last_block,
+ uint8_t *data_in, uint8_t *data_out, size_t data_size)
+{
+ int ret;
+ uint32_t *data_in_u32;
+ uint32_t *data_out_u32;
+ unsigned int i = 0U;
+
+ /* We want buffers to be u32 aligned */
+ assert((uintptr_t)data_in % __alignof__(uint32_t) == 0);
+ assert((uintptr_t)data_out % __alignof__(uint32_t) == 0);
+ data_in_u32 = (uint32_t *)data_in;
+ data_out_u32 = (uint32_t *)data_out;
+
+ if ((!last_block) &&
+ (round_down(data_size, AES_BLOCK_SIZE) != data_size)) {
+ ERROR("%s: non last block must be multiple of 128 bits\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* In CBC encryption we need to manage specifically last 2 128bits
+ * blocks if total size in not a block size aligned
+ * work TODO. Currently return ENODEV.
+ * Morevoer as we need to know last 2 block, if unaligned and
+ * call with less than two block, return -EINVAL.
+ */
+ if (last_block && IS_CHAINING_MODE(CBC, ctx->cr) && is_encrypt(ctx->cr) &&
+ (round_down(data_size, AES_BLOCK_SIZE) != data_size)) {
+ if (data_size < AES_BLOCK_SIZE * 2U) {
+ ERROR("if CBC, last part size should be at least 2 * AES_BLOCK_SIZE\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ /* Moreover the CBC specific padding for encrypt is not yet implemented */
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = restore_context(ctx);
+ if (ret != 0) {
+ goto out;
+ }
+
+ while (i < round_down(data_size, AES_BLOCK_SIZE)) {
+ unsigned int w; /* Word index */
+
+ w = i / sizeof(uint32_t);
+ /* No need to htobe() as we configure the HW to swap bytes */
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 0U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 1U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 2U]);
+ mmio_write_32(ctx->base + _SAES_DINR, data_in_u32[w + 3U]);
+
+ ret = wait_computation_completed(ctx->base);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* No need to htobe() as we configure the HW to swap bytes */
+ data_out_u32[w + 0U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 1U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 2U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+ data_out_u32[w + 3U] = mmio_read_32(ctx->base + _SAES_DOUTR);
+
+ clear_computation_completed(ctx->base);
+
+ /* Process next block */
+ i += AES_BLOCK_SIZE;
+ }
+ /* Manage last block if not a block size multiple */
+
+ if ((last_block) && (i < data_size)) {
+ /* In and out buffer have same size so should be AES_BLOCK_SIZE multiple */
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (!last_block) {
+ ret = save_context(ctx);
+ }
+
+out:
+ /* If last block or error, end of SAES process */
+ if (last_block || (ret != 0)) {
+ saes_end(ctx, ret);
+ }
+
+ return ret;
+}
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
index 7d89d027e6..27d8b2c000 100644
--- a/drivers/st/ddr/stm32mp1_ddr.c
+++ b/drivers/st/ddr/stm32mp1_ddr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -7,46 +7,58 @@
#include <errno.h>
#include <stddef.h>
-#include <platform_def.h>
-
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
-#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stm32mp1_ddr.h>
#include <drivers/st/stm32mp1_ddr_regs.h>
#include <drivers/st/stm32mp1_pwr.h>
#include <drivers/st/stm32mp1_ram.h>
+#include <drivers/st/stm32mp_ddr.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
-struct reg_desc {
- const char *name;
- uint16_t offset; /* Offset for base address */
- uint8_t par_offset; /* Offset for parameter array */
-};
-
-#define INVALID_OFFSET 0xFFU
-
-#define TIMEOUT_US_1S 1000000U
+#include <platform_def.h>
#define DDRCTL_REG(x, y) \
{ \
.name = #x, \
- .offset = offsetof(struct stm32mp1_ddrctl, x), \
+ .offset = offsetof(struct stm32mp_ddrctl, x), \
.par_offset = offsetof(struct y, x) \
}
#define DDRPHY_REG(x, y) \
{ \
.name = #x, \
- .offset = offsetof(struct stm32mp1_ddrphy, x), \
+ .offset = offsetof(struct stm32mp_ddrphy, x), \
.par_offset = offsetof(struct y, x) \
}
+/*
+ * PARAMETERS: value get from device tree :
+ * size / order need to be aligned with binding
+ * modification NOT ALLOWED !!!
+ */
+#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */
+#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */
+#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */
+#if STM32MP_DDR_DUAL_AXI_PORT
+#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */
+#else
+#define DDRCTL_REG_PERF_SIZE 11 /* st,ctl-perf */
+#endif
+
+#if STM32MP_DDR_32BIT_INTERFACE
+#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
+#else
+#define DDRPHY_REG_REG_SIZE 9 /* st,phy-reg */
+#endif
+#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
+
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
-static const struct reg_desc ddr_reg[] = {
+static const struct stm32mp_ddr_reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
DDRCTL_REG_REG(mstr),
DDRCTL_REG_REG(mrctrl0),
DDRCTL_REG_REG(mrctrl1),
@@ -75,7 +87,7 @@ static const struct reg_desc ddr_reg[] = {
};
#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
-static const struct reg_desc ddr_timing[] = {
+static const struct stm32mp_ddr_reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
DDRCTL_REG_TIMING(rfshtmg),
DDRCTL_REG_TIMING(dramtmg0),
DDRCTL_REG_TIMING(dramtmg1),
@@ -91,7 +103,7 @@ static const struct reg_desc ddr_timing[] = {
};
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
-static const struct reg_desc ddr_map[] = {
+static const struct stm32mp_ddr_reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
DDRCTL_REG_MAP(addrmap1),
DDRCTL_REG_MAP(addrmap2),
DDRCTL_REG_MAP(addrmap3),
@@ -104,7 +116,7 @@ static const struct reg_desc ddr_map[] = {
};
#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
-static const struct reg_desc ddr_perf[] = {
+static const struct stm32mp_ddr_reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
DDRCTL_REG_PERF(sched),
DDRCTL_REG_PERF(sched1),
DDRCTL_REG_PERF(perfhpr1),
@@ -116,16 +128,18 @@ static const struct reg_desc ddr_perf[] = {
DDRCTL_REG_PERF(pcfgqos1_0),
DDRCTL_REG_PERF(pcfgwqos0_0),
DDRCTL_REG_PERF(pcfgwqos1_0),
+#if STM32MP_DDR_DUAL_AXI_PORT
DDRCTL_REG_PERF(pcfgr_1),
DDRCTL_REG_PERF(pcfgw_1),
DDRCTL_REG_PERF(pcfgqos0_1),
DDRCTL_REG_PERF(pcfgqos1_1),
DDRCTL_REG_PERF(pcfgwqos0_1),
DDRCTL_REG_PERF(pcfgwqos1_1),
+#endif
};
#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
-static const struct reg_desc ddrphy_reg[] = {
+static const struct stm32mp_ddr_reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {
DDRPHY_REG_REG(pgcr),
DDRPHY_REG_REG(aciocr),
DDRPHY_REG_REG(dxccr),
@@ -135,12 +149,14 @@ static const struct reg_desc ddrphy_reg[] = {
DDRPHY_REG_REG(zq0cr1),
DDRPHY_REG_REG(dx0gcr),
DDRPHY_REG_REG(dx1gcr),
+#if STM32MP_DDR_32BIT_INTERFACE
DDRPHY_REG_REG(dx2gcr),
DDRPHY_REG_REG(dx3gcr),
+#endif
};
#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
-static const struct reg_desc ddrphy_timing[] = {
+static const struct stm32mp_ddr_reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
DDRPHY_REG_TIMING(ptr0),
DDRPHY_REG_TIMING(ptr1),
DDRPHY_REG_TIMING(ptr2),
@@ -153,174 +169,49 @@ static const struct reg_desc ddrphy_timing[] = {
DDRPHY_REG_TIMING(mr3),
};
-#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
-static const struct reg_desc ddrphy_cal[] = {
- DDRPHY_REG_CAL(dx0dllcr),
- DDRPHY_REG_CAL(dx0dqtr),
- DDRPHY_REG_CAL(dx0dqstr),
- DDRPHY_REG_CAL(dx1dllcr),
- DDRPHY_REG_CAL(dx1dqtr),
- DDRPHY_REG_CAL(dx1dqstr),
- DDRPHY_REG_CAL(dx2dllcr),
- DDRPHY_REG_CAL(dx2dqtr),
- DDRPHY_REG_CAL(dx2dqstr),
- DDRPHY_REG_CAL(dx3dllcr),
- DDRPHY_REG_CAL(dx3dqtr),
- DDRPHY_REG_CAL(dx3dqstr),
-};
-
-#define DDR_REG_DYN(x) \
- { \
- .name = #x, \
- .offset = offsetof(struct stm32mp1_ddrctl, x), \
- .par_offset = INVALID_OFFSET \
- }
-
-static const struct reg_desc ddr_dyn[] = {
- DDR_REG_DYN(stat),
- DDR_REG_DYN(init0),
- DDR_REG_DYN(dfimisc),
- DDR_REG_DYN(dfistat),
- DDR_REG_DYN(swctl),
- DDR_REG_DYN(swstat),
- DDR_REG_DYN(pctrl_0),
- DDR_REG_DYN(pctrl_1),
-};
-
-#define DDRPHY_REG_DYN(x) \
- { \
- .name = #x, \
- .offset = offsetof(struct stm32mp1_ddrphy, x), \
- .par_offset = INVALID_OFFSET \
- }
-
-static const struct reg_desc ddrphy_dyn[] = {
- DDRPHY_REG_DYN(pir),
- DDRPHY_REG_DYN(pgsr),
-};
-
-enum reg_type {
- REG_REG,
- REG_TIMING,
- REG_PERF,
- REG_MAP,
- REGPHY_REG,
- REGPHY_TIMING,
- REGPHY_CAL,
/*
- * Dynamic registers => managed in driver or not changed,
- * can be dumped in interactive mode.
+ * REGISTERS ARRAY: used to parse device tree and interactive mode
*/
- REG_DYN,
- REGPHY_DYN,
- REG_TYPE_NB
-};
-
-enum base_type {
- DDR_BASE,
- DDRPHY_BASE,
- NONE_BASE
-};
-
-struct ddr_reg_info {
- const char *name;
- const struct reg_desc *desc;
- uint8_t size;
- enum base_type base;
-};
-
-static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
+static const struct stm32mp_ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
.name = "static",
.desc = ddr_reg,
- .size = ARRAY_SIZE(ddr_reg),
+ .size = DDRCTL_REG_REG_SIZE,
.base = DDR_BASE
},
[REG_TIMING] = {
.name = "timing",
.desc = ddr_timing,
- .size = ARRAY_SIZE(ddr_timing),
+ .size = DDRCTL_REG_TIMING_SIZE,
.base = DDR_BASE
},
[REG_PERF] = {
.name = "perf",
.desc = ddr_perf,
- .size = ARRAY_SIZE(ddr_perf),
+ .size = DDRCTL_REG_PERF_SIZE,
.base = DDR_BASE
},
[REG_MAP] = {
.name = "map",
.desc = ddr_map,
- .size = ARRAY_SIZE(ddr_map),
+ .size = DDRCTL_REG_MAP_SIZE,
.base = DDR_BASE
},
[REGPHY_REG] = {
.name = "static",
.desc = ddrphy_reg,
- .size = ARRAY_SIZE(ddrphy_reg),
+ .size = DDRPHY_REG_REG_SIZE,
.base = DDRPHY_BASE
},
[REGPHY_TIMING] = {
.name = "timing",
.desc = ddrphy_timing,
- .size = ARRAY_SIZE(ddrphy_timing),
- .base = DDRPHY_BASE
- },
- [REGPHY_CAL] = {
- .name = "cal",
- .desc = ddrphy_cal,
- .size = ARRAY_SIZE(ddrphy_cal),
- .base = DDRPHY_BASE
- },
- [REG_DYN] = {
- .name = "dyn",
- .desc = ddr_dyn,
- .size = ARRAY_SIZE(ddr_dyn),
- .base = DDR_BASE
- },
- [REGPHY_DYN] = {
- .name = "dyn",
- .desc = ddrphy_dyn,
- .size = ARRAY_SIZE(ddrphy_dyn),
+ .size = DDRPHY_REG_TIMING_SIZE,
.base = DDRPHY_BASE
},
};
-static uintptr_t get_base_addr(const struct ddr_info *priv, enum base_type base)
-{
- if (base == DDRPHY_BASE) {
- return (uintptr_t)priv->phy;
- } else {
- return (uintptr_t)priv->ctl;
- }
-}
-
-static void set_reg(const struct ddr_info *priv,
- enum reg_type type,
- const void *param)
-{
- unsigned int i;
- unsigned int value;
- enum base_type base = ddr_registers[type].base;
- uintptr_t base_addr = get_base_addr(priv, base);
- const struct reg_desc *desc = ddr_registers[type].desc;
-
- VERBOSE("init %s\n", ddr_registers[type].name);
- for (i = 0; i < ddr_registers[type].size; i++) {
- uintptr_t ptr = base_addr + desc[i].offset;
-
- if (desc[i].par_offset == INVALID_OFFSET) {
- ERROR("invalid parameter offset for %s", desc[i].name);
- panic();
- } else {
- value = *((uint32_t *)((uintptr_t)param +
- desc[i].par_offset));
- mmio_write_32(ptr, value);
- }
- }
-}
-
-static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
+static void stm32mp1_ddrphy_idone_wait(struct stm32mp_ddrphy *phy)
{
uint32_t pgsr;
int error = 0;
@@ -365,7 +256,7 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
(uintptr_t)&phy->pgsr, pgsr);
}
-static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
+static void stm32mp1_ddrphy_init(struct stm32mp_ddrphy *phy, uint32_t pir)
{
uint32_t pir_init = pir | DDRPHYC_PIR_INIT;
@@ -381,40 +272,8 @@ static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
stm32mp1_ddrphy_idone_wait(phy);
}
-/* Start quasi dynamic register update */
-static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl)
-{
- mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
- VERBOSE("[0x%lx] swctl = 0x%x\n",
- (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
-}
-
/* Wait quasi dynamic register update */
-static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
-{
- uint64_t timeout;
- uint32_t swstat;
-
- mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
- VERBOSE("[0x%lx] swctl = 0x%x\n",
- (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
-
- timeout = timeout_init_us(TIMEOUT_US_1S);
- do {
- swstat = mmio_read_32((uintptr_t)&ctl->swstat);
- VERBOSE("[0x%lx] swstat = 0x%x ",
- (uintptr_t)&ctl->swstat, swstat);
- if (timeout_elapsed(timeout)) {
- panic();
- }
- } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U);
-
- VERBOSE("[0x%lx] swstat = 0x%x\n",
- (uintptr_t)&ctl->swstat, swstat);
-}
-
-/* Wait quasi dynamic register update */
-static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
+static void stm32mp1_wait_operating_mode(struct stm32mp_ddr_priv *priv, uint32_t mode)
{
uint64_t timeout;
uint32_t stat;
@@ -463,7 +322,7 @@ static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
}
/* Mode Register Writes (MRW or MRS) */
-static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
+static void stm32mp1_mode_register_write(struct stm32mp_ddr_priv *priv, uint8_t addr,
uint32_t data)
{
uint32_t mrctrl0;
@@ -518,7 +377,7 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
}
/* Switch DDR3 from DLL-on to DLL-off */
-static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
+static void stm32mp1_ddr3_dll_off(struct stm32mp_ddr_priv *priv)
{
uint32_t mr1 = mmio_read_32((uintptr_t)&priv->phy->mr1);
uint32_t mr2 = mmio_read_32((uintptr_t)&priv->phy->mr2);
@@ -609,14 +468,14 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
* 9. Set the MSTR.dll_off_mode = 1.
* warning: MSTR.dll_off_mode is a quasi-dynamic type 2 field
*/
- stm32mp1_start_sw_done(priv->ctl);
+ stm32mp_ddr_start_sw_done(priv->ctl);
mmio_setbits_32((uintptr_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE);
VERBOSE("[0x%lx] mstr = 0x%x\n",
(uintptr_t)&priv->ctl->mstr,
mmio_read_32((uintptr_t)&priv->ctl->mstr));
- stm32mp1_wait_sw_done_ack(priv->ctl);
+ stm32mp_ddr_wait_sw_done_ack(priv->ctl);
/* 10. Change the clock frequency to the desired value. */
@@ -627,7 +486,7 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
*/
/* Change Bypass Mode Frequency Range */
- if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) {
+ if (clk_get_rate(DDRPHYC) < 100000000U) {
mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr,
DDRPHYC_DLLGCR_BPS200);
} else {
@@ -641,10 +500,12 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
DDRPHYC_DXNDLLCR_DLLDIS);
mmio_setbits_32((uintptr_t)&priv->phy->dx1dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
+#if STM32MP_DDR_32BIT_INTERFACE
mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
mmio_setbits_32((uintptr_t)&priv->phy->dx3dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
+#endif
/* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */
mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl,
@@ -669,22 +530,22 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
mmio_read_32((uintptr_t)&priv->ctl->dbg1));
}
-static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
+static void stm32mp1_refresh_disable(struct stm32mp_ddrctl *ctl)
{
- stm32mp1_start_sw_done(ctl);
+ stm32mp_ddr_start_sw_done(ctl);
/* Quasi-dynamic register update*/
mmio_setbits_32((uintptr_t)&ctl->rfshctl3,
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
mmio_clrbits_32((uintptr_t)&ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
- stm32mp1_wait_sw_done_ack(ctl);
+ stm32mp_ddr_wait_sw_done_ack(ctl);
}
-static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
+static void stm32mp1_refresh_restore(struct stm32mp_ddrctl *ctl,
uint32_t rfshctl3, uint32_t pwrctl)
{
- stm32mp1_start_sw_done(ctl);
+ stm32mp_ddr_start_sw_done(ctl);
if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) {
mmio_clrbits_32((uintptr_t)&ctl->rfshctl3,
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
@@ -695,30 +556,21 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
}
mmio_setbits_32((uintptr_t)&ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
- stm32mp1_wait_sw_done_ack(ctl);
+ stm32mp_ddr_wait_sw_done_ack(ctl);
}
-static int board_ddr_power_init(enum ddr_type ddr_type)
-{
- if (dt_pmic_status() > 0) {
- return pmic_ddr_power_init(ddr_type);
- }
-
- return 0;
-}
-
-void stm32mp1_ddr_init(struct ddr_info *priv,
- struct stm32mp1_ddr_config *config)
+void stm32mp1_ddr_init(struct stm32mp_ddr_priv *priv,
+ struct stm32mp_ddr_config *config)
{
uint32_t pir;
int ret = -EINVAL;
if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
- ret = board_ddr_power_init(STM32MP_DDR3);
+ ret = stm32mp_board_ddr_power_init(STM32MP_DDR3);
} else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) {
- ret = board_ddr_power_init(STM32MP_LPDDR2);
+ ret = stm32mp_board_ddr_power_init(STM32MP_LPDDR2);
} else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) != 0U) {
- ret = board_ddr_power_init(STM32MP_LPDDR3);
+ ret = stm32mp_board_ddr_power_init(STM32MP_LPDDR3);
} else {
ERROR("DDR type not supported\n");
}
@@ -728,7 +580,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
}
VERBOSE("name = %s\n", config->info.name);
- VERBOSE("speed = %d kHz\n", config->info.speed);
+ VERBOSE("speed = %u kHz\n", config->info.speed);
VERBOSE("size = 0x%x\n", config->info.size);
/* DDR INIT SEQUENCE */
@@ -773,7 +625,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
(uintptr_t)&priv->ctl->dfimisc,
mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
- set_reg(priv, REG_REG, &config->c_reg);
+ stm32mp_ddr_set_reg(priv, REG_REG, &config->c_reg, ddr_registers);
/* DDR3 = don't set DLLOFF for init mode */
if ((config->c_reg.mstr &
@@ -787,8 +639,8 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
mmio_read_32((uintptr_t)&priv->ctl->mstr));
}
- set_reg(priv, REG_TIMING, &config->c_timing);
- set_reg(priv, REG_MAP, &config->c_map);
+ stm32mp_ddr_set_reg(priv, REG_TIMING, &config->c_timing, ddr_registers);
+ stm32mp_ddr_set_reg(priv, REG_MAP, &config->c_map, ddr_registers);
/* Skip CTRL init, SDRAM init is done by PHY PUBL */
mmio_clrsetbits_32((uintptr_t)&priv->ctl->init0,
@@ -798,7 +650,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
(uintptr_t)&priv->ctl->init0,
mmio_read_32((uintptr_t)&priv->ctl->init0));
- set_reg(priv, REG_PERF, &config->c_perf);
+ stm32mp_ddr_set_reg(priv, REG_PERF, &config->c_perf, ddr_registers);
/* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */
mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
@@ -809,9 +661,8 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
* 3. start PHY init by accessing relevant PUBL registers
* (DXGCR, DCR, PTR*, MR*, DTPR*)
*/
- set_reg(priv, REGPHY_REG, &config->p_reg);
- set_reg(priv, REGPHY_TIMING, &config->p_timing);
- set_reg(priv, REGPHY_CAL, &config->p_cal);
+ stm32mp_ddr_set_reg(priv, REGPHY_REG, &config->p_reg, ddr_registers);
+ stm32mp_ddr_set_reg(priv, REGPHY_TIMING, &config->p_timing, ddr_registers);
/* DDR3 = don't set DLLOFF for init mode */
if ((config->c_reg.mstr &
@@ -849,7 +700,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
* 6. SET DFIMISC.dfi_init_complete_en to 1
* Enable quasi-dynamic register programming.
*/
- stm32mp1_start_sw_done(priv->ctl);
+ stm32mp_ddr_start_sw_done(priv->ctl);
mmio_setbits_32((uintptr_t)&priv->ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
@@ -857,7 +708,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
(uintptr_t)&priv->ctl->dfimisc,
mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
- stm32mp1_wait_sw_done_ack(priv->ctl);
+ stm32mp_ddr_wait_sw_done_ack(priv->ctl);
/*
* 7. Wait for DWC_ddr_umctl2 to move to normal operation mode
@@ -891,30 +742,23 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
/*
* 10. configure PUBL PIR register to specify which training step
* to run
- * Warning : RVTRN is not supported by this PUBL
+ * RVTRN is executed only on LPDDR2/LPDDR3
*/
- stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+ pir = DDRPHYC_PIR_QSTRN;
+ if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) == 0U) {
+ pir |= DDRPHYC_PIR_RVTRN;
+ }
+
+ stm32mp1_ddrphy_init(priv->phy, pir);
/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
stm32mp1_ddrphy_idone_wait(priv->phy);
/*
- * 12. set back registers in step 8 to the orginal values if desidered
+ * 12. set back registers in step 8 to the original values if desidered
*/
stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
config->c_reg.pwrctl);
- /* Enable uMCTL2 AXI port 0 */
- mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0,
- DDRCTRL_PCTRL_N_PORT_EN);
- VERBOSE("[0x%lx] pctrl_0 = 0x%x\n",
- (uintptr_t)&priv->ctl->pctrl_0,
- mmio_read_32((uintptr_t)&priv->ctl->pctrl_0));
-
- /* Enable uMCTL2 AXI port 1 */
- mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_1,
- DDRCTRL_PCTRL_N_PORT_EN);
- VERBOSE("[0x%lx] pctrl_1 = 0x%x\n",
- (uintptr_t)&priv->ctl->pctrl_1,
- mmio_read_32((uintptr_t)&priv->ctl->pctrl_1));
+ stm32mp_ddr_enable_axi_port(priv->ctl);
}
diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c
index fcb4cfcfdf..e0621b5131 100644
--- a/drivers/st/ddr/stm32mp1_ddr_helpers.c
+++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c
@@ -1,21 +1,23 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <platform_def.h>
-
#include <drivers/st/stm32mp1_ddr_helpers.h>
#include <lib/mmio.h>
+#include <platform_def.h>
+
void ddr_enable_clock(void)
{
stm32mp1_clk_rcc_regs_lock();
mmio_setbits_32(stm32mp_rcc_base() + RCC_DDRITFCR,
RCC_DDRITFCR_DDRC1EN |
+#if STM32MP_DDR_DUAL_AXI_PORT
RCC_DDRITFCR_DDRC2EN |
+#endif
RCC_DDRITFCR_DDRPHYCEN |
RCC_DDRITFCR_DDRPHYCAPBEN |
RCC_DDRITFCR_DDRCAPBEN);
diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c
index b21c8949fe..c96fa04fec 100644
--- a/drivers/st/ddr/stm32mp1_ram.c
+++ b/drivers/st/ddr/stm32mp1_ram.c
@@ -1,37 +1,37 @@
/*
- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2023, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#include <errno.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
#include <drivers/st/stm32mp1_ddr.h>
#include <drivers/st/stm32mp1_ddr_helpers.h>
#include <drivers/st/stm32mp1_ram.h>
+#include <drivers/st/stm32mp_ddr.h>
+#include <drivers/st/stm32mp_ddr_test.h>
+#include <drivers/st/stm32mp_ram.h>
#include <lib/mmio.h>
+#include <libfdt.h>
-#define DDR_PATTERN 0xAAAAAAAAU
-#define DDR_ANTIPATTERN 0x55555555U
+#include <platform_def.h>
-static struct ddr_info ddr_priv_data;
+static struct stm32mp_ddr_priv ddr_priv_data;
-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
+int stm32mp1_ddr_clk_enable(struct stm32mp_ddr_priv *priv, uint32_t mem_speed)
{
unsigned long ddrphy_clk, ddr_clk, mem_speed_hz;
ddr_enable_clock();
- ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC);
+ ddrphy_clk = clk_get_rate(DDRPHYC);
- VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n",
+ VERBOSE("DDR: mem_speed (%u kHz), RCC %lu kHz\n",
mem_speed, ddrphy_clk / 1000U);
mem_speed_hz = mem_speed * 1000U;
@@ -43,157 +43,30 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
ddr_clk = mem_speed_hz - ddrphy_clk;
}
if (ddr_clk > (mem_speed_hz / 10)) {
- ERROR("DDR expected freq %d kHz, current is %ld kHz\n",
+ ERROR("DDR expected freq %u kHz, current is %lu kHz\n",
mem_speed, ddrphy_clk / 1000U);
return -1;
}
return 0;
}
-/*******************************************************************************
- * This function tests the DDR data bus wiring.
- * This is inspired from the Data Bus Test algorithm written by Michael Barr
- * in "Programming Embedded Systems in C and C++" book.
- * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
- * File: memtest.c - This source code belongs to Public Domain.
- * Returns 0 if success, and address value else.
- ******************************************************************************/
-static uint32_t ddr_test_data_bus(void)
-{
- uint32_t pattern;
-
- for (pattern = 1U; pattern != 0U; pattern <<= 1) {
- mmio_write_32(STM32MP_DDR_BASE, pattern);
-
- if (mmio_read_32(STM32MP_DDR_BASE) != pattern) {
- return (uint32_t)STM32MP_DDR_BASE;
- }
- }
-
- return 0;
-}
-
-/*******************************************************************************
- * This function tests the DDR address bus wiring.
- * This is inspired from the Data Bus Test algorithm written by Michael Barr
- * in "Programming Embedded Systems in C and C++" book.
- * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
- * File: memtest.c - This source code belongs to Public Domain.
- * Returns 0 if success, and address value else.
- ******************************************************************************/
-static uint32_t ddr_test_addr_bus(void)
-{
- uint64_t addressmask = (ddr_priv_data.info.size - 1U);
- uint64_t offset;
- uint64_t testoffset = 0;
-
- /* Write the default pattern at each of the power-of-two offsets. */
- for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
- offset <<= 1) {
- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset,
- DDR_PATTERN);
- }
-
- /* Check for address bits stuck high. */
- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
- DDR_ANTIPATTERN);
-
- for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
- offset <<= 1) {
- if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) !=
- DDR_PATTERN) {
- return (uint32_t)(STM32MP_DDR_BASE + offset);
- }
- }
-
- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN);
-
- /* Check for address bits stuck low or shorted. */
- for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
- testoffset <<= 1) {
- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
- DDR_ANTIPATTERN);
-
- if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
- return STM32MP_DDR_BASE;
- }
-
- for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
- offset <<= 1) {
- if ((mmio_read_32(STM32MP_DDR_BASE +
- (uint32_t)offset) != DDR_PATTERN) &&
- (offset != testoffset)) {
- return (uint32_t)(STM32MP_DDR_BASE + offset);
- }
- }
-
- mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
- DDR_PATTERN);
- }
-
- return 0;
-}
-
-/*******************************************************************************
- * This function checks the DDR size. It has to be run with Data Cache off.
- * This test is run before data have been put in DDR, and is only done for
- * cold boot. The DDR data can then be overwritten, and it is not useful to
- * restore its content.
- * Returns DDR computed size.
- ******************************************************************************/
-static uint32_t ddr_check_size(void)
-{
- uint32_t offset = sizeof(uint32_t);
-
- mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
-
- while (offset < STM32MP_DDR_MAX_SIZE) {
- mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
- dsb();
-
- if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
- break;
- }
-
- offset <<= 1;
- }
-
- INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U));
-
- return offset;
-}
-
static int stm32mp1_ddr_setup(void)
{
- struct ddr_info *priv = &ddr_priv_data;
+ struct stm32mp_ddr_priv *priv = &ddr_priv_data;
int ret;
- struct stm32mp1_ddr_config config;
- int node, len;
- uint32_t uret, idx;
+ struct stm32mp_ddr_config config;
+ int node;
+ uintptr_t uret;
+ size_t retsize;
void *fdt;
-#define PARAM(x, y) \
- { \
- .name = x, \
- .offset = offsetof(struct stm32mp1_ddr_config, y), \
- .size = sizeof(config.y) / sizeof(uint32_t) \
- }
-
-#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
-#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
-
- const struct {
- const char *name; /* Name in DT */
- const uint32_t offset; /* Offset in config struct */
- const uint32_t size; /* Size of parameters */
- } param[] = {
+ const struct stm32mp_ddr_param param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
CTL_PARAM(map),
CTL_PARAM(perf),
PHY_PARAM(reg),
PHY_PARAM(timing),
- PHY_PARAM(cal)
};
if (fdt_get_address(&fdt) == 0) {
@@ -206,36 +79,14 @@ static int stm32mp1_ddr_setup(void)
return -EINVAL;
}
- ret = fdt_read_uint32(fdt, node, "st,mem-speed", &config.info.speed);
+ ret = stm32mp_ddr_dt_get_info(fdt, node, &config.info);
if (ret < 0) {
- VERBOSE("%s: no st,mem-speed\n", __func__);
- return -EINVAL;
+ return ret;
}
- ret = fdt_read_uint32(fdt, node, "st,mem-size", &config.info.size);
+
+ ret = stm32mp_ddr_dt_get_param(fdt, node, param, ARRAY_SIZE(param), (uintptr_t)&config);
if (ret < 0) {
- VERBOSE("%s: no st,mem-size\n", __func__);
- return -EINVAL;
- }
- config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len);
- if (config.info.name == NULL) {
- VERBOSE("%s: no st,mem-name\n", __func__);
- return -EINVAL;
- }
- INFO("RAM: %s\n", config.info.name);
-
- for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
- ret = fdt_read_uint32_array(fdt, node, param[idx].name,
- param[idx].size,
- (void *)((uintptr_t)&config +
- param[idx].offset));
-
- VERBOSE("%s: %s[0x%x] = %d\n", __func__,
- param[idx].name, param[idx].size, ret);
- if (ret != 0) {
- ERROR("%s: Cannot read %s\n",
- __func__, param[idx].name);
- return -EINVAL;
- }
+ return ret;
}
/* Disable axidcg clock gating during init */
@@ -255,27 +106,29 @@ static int stm32mp1_ddr_setup(void)
panic();
}
- uret = ddr_test_data_bus();
- if (uret != 0U) {
- ERROR("DDR data bus test: can't access memory @ 0x%x\n",
+ uret = stm32mp_ddr_test_data_bus();
+ if (uret != 0UL) {
+ ERROR("DDR data bus test: can't access memory @ 0x%lx\n",
uret);
panic();
}
- uret = ddr_test_addr_bus();
- if (uret != 0U) {
- ERROR("DDR addr bus test: can't access memory @ 0x%x\n",
+ uret = stm32mp_ddr_test_addr_bus(config.info.size);
+ if (uret != 0UL) {
+ ERROR("DDR addr bus test: can't access memory @ 0x%lx\n",
uret);
panic();
}
- uret = ddr_check_size();
- if (uret < config.info.size) {
- ERROR("DDR size: 0x%x does not match DT config: 0x%x\n",
- uret, config.info.size);
+ retsize = stm32mp_ddr_check_size();
+ if (retsize < config.info.size) {
+ ERROR("DDR size: 0x%zx does not match DT config: 0x%zx\n",
+ retsize, config.info.size);
panic();
}
+ INFO("Memory size = 0x%zx (%zu MB)\n", retsize, retsize / (1024U * 1024U));
+
if (stm32mp_unmap_ddr() != 0) {
panic();
}
@@ -285,12 +138,12 @@ static int stm32mp1_ddr_setup(void)
int stm32mp1_ddr_probe(void)
{
- struct ddr_info *priv = &ddr_priv_data;
+ struct stm32mp_ddr_priv *priv = &ddr_priv_data;
VERBOSE("STM32MP DDR probe\n");
- priv->ctl = (struct stm32mp1_ddrctl *)stm32mp_ddrctrl_base();
- priv->phy = (struct stm32mp1_ddrphy *)stm32mp_ddrphyc_base();
+ priv->ctl = (struct stm32mp_ddrctl *)stm32mp_ddrctrl_base();
+ priv->phy = (struct stm32mp_ddrphy *)stm32mp_ddrphyc_base();
priv->pwr = stm32mp_pwr_base();
priv->rcc = stm32mp_rcc_base();
diff --git a/drivers/st/ddr/stm32mp_ddr.c b/drivers/st/ddr/stm32mp_ddr.c
new file mode 100644
index 0000000000..6776e3ba8c
--- /dev/null
+++ b/drivers/st/ddr/stm32mp_ddr.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_ddr.h>
+#include <drivers/st/stm32mp_ddrctrl_regs.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define INVALID_OFFSET 0xFFU
+
+static uintptr_t get_base_addr(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_base_type base)
+{
+ if (base == DDRPHY_BASE) {
+ return (uintptr_t)priv->phy;
+ } else {
+ return (uintptr_t)priv->ctl;
+ }
+}
+
+void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_reg_type type,
+ const void *param, const struct stm32mp_ddr_reg_info *ddr_registers)
+{
+ unsigned int i;
+ unsigned int value;
+ enum stm32mp_ddr_base_type base = ddr_registers[type].base;
+ uintptr_t base_addr = get_base_addr(priv, base);
+ const struct stm32mp_ddr_reg_desc *desc = ddr_registers[type].desc;
+
+ VERBOSE("init %s\n", ddr_registers[type].name);
+ for (i = 0; i < ddr_registers[type].size; i++) {
+ uintptr_t ptr = base_addr + desc[i].offset;
+
+ if (desc[i].par_offset == INVALID_OFFSET) {
+ ERROR("invalid parameter offset for %s", desc[i].name);
+ panic();
+ } else {
+ value = *((uint32_t *)((uintptr_t)param +
+ desc[i].par_offset));
+ mmio_write_32(ptr, value);
+ }
+ }
+}
+
+/* Start quasi dynamic register update */
+void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl)
+{
+ mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+ VERBOSE("[0x%lx] swctl = 0x%x\n",
+ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
+}
+
+/* Wait quasi dynamic register update */
+void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl)
+{
+ uint64_t timeout;
+ uint32_t swstat;
+
+ mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+ VERBOSE("[0x%lx] swctl = 0x%x\n",
+ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
+
+ timeout = timeout_init_us(TIMEOUT_US_1S);
+ do {
+ swstat = mmio_read_32((uintptr_t)&ctl->swstat);
+ VERBOSE("[0x%lx] swstat = 0x%x ",
+ (uintptr_t)&ctl->swstat, swstat);
+ if (timeout_elapsed(timeout)) {
+ panic();
+ }
+ } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U);
+
+ VERBOSE("[0x%lx] swstat = 0x%x\n",
+ (uintptr_t)&ctl->swstat, swstat);
+}
+
+void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl)
+{
+ /* Enable uMCTL2 AXI port 0 */
+ mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
+ VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0,
+ mmio_read_32((uintptr_t)&ctl->pctrl_0));
+
+#if STM32MP_DDR_DUAL_AXI_PORT
+ /* Enable uMCTL2 AXI port 1 */
+ mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
+ VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1,
+ mmio_read_32((uintptr_t)&ctl->pctrl_1));
+#endif
+
+}
+
+int stm32mp_board_ddr_power_init(enum ddr_type ddr_type)
+{
+ if (dt_pmic_status() > 0) {
+ return pmic_ddr_power_init(ddr_type);
+ }
+
+ return 0;
+}
diff --git a/drivers/st/ddr/stm32mp_ddr_test.c b/drivers/st/ddr/stm32mp_ddr_test.c
new file mode 100644
index 0000000000..0f6aff1db4
--- /dev/null
+++ b/drivers/st/ddr/stm32mp_ddr_test.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022-2023, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/st/stm32mp_ddr_test.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define DDR_PATTERN 0xAAAAAAAAU
+#define DDR_ANTIPATTERN 0x55555555U
+
+/*******************************************************************************
+ * This function tests a simple read/write access to the DDR.
+ * Note that the previous content is restored after test.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+uintptr_t stm32mp_ddr_test_rw_access(void)
+{
+ uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE);
+
+ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
+
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
+ return STM32MP_DDR_BASE;
+ }
+
+ mmio_write_32(STM32MP_DDR_BASE, saved_value);
+
+ return 0UL;
+}
+
+/*******************************************************************************
+ * This function tests the DDR data bus wiring.
+ * This is inspired from the Data Bus Test algorithm written by Michael Barr
+ * in "Programming Embedded Systems in C and C++" book.
+ * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
+ * File: memtest.c - This source code belongs to Public Domain.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+uintptr_t stm32mp_ddr_test_data_bus(void)
+{
+ uint32_t pattern;
+
+ for (pattern = 1U; pattern != 0U; pattern <<= 1U) {
+ mmio_write_32(STM32MP_DDR_BASE, pattern);
+
+ if (mmio_read_32(STM32MP_DDR_BASE) != pattern) {
+ return STM32MP_DDR_BASE;
+ }
+ }
+
+ return 0UL;
+}
+
+/*******************************************************************************
+ * This function tests the DDR address bus wiring.
+ * This is inspired from the Data Bus Test algorithm written by Michael Barr
+ * in "Programming Embedded Systems in C and C++" book.
+ * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
+ * File: memtest.c - This source code belongs to Public Domain.
+ * size: size in bytes of the DDR memory device.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+uintptr_t stm32mp_ddr_test_addr_bus(size_t size)
+{
+ size_t addressmask = size - 1U;
+ size_t offset;
+ size_t testoffset = 0U;
+
+ /* Write the default pattern at each of the power-of-two offsets. */
+ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+ offset <<= 1U) {
+ mmio_write_32(STM32MP_DDR_BASE + offset, DDR_PATTERN);
+ }
+
+ /* Check for address bits stuck high. */
+ mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
+
+ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+ offset <<= 1U) {
+ if (mmio_read_32(STM32MP_DDR_BASE + offset) != DDR_PATTERN) {
+ return STM32MP_DDR_BASE + offset;
+ }
+ }
+
+ mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
+
+ /* Check for address bits stuck low or shorted. */
+ for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
+ testoffset <<= 1U) {
+ mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_ANTIPATTERN);
+
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
+ return STM32MP_DDR_BASE;
+ }
+
+ for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+ offset <<= 1) {
+ if ((mmio_read_32(STM32MP_DDR_BASE + offset) != DDR_PATTERN) &&
+ (offset != testoffset)) {
+ return STM32MP_DDR_BASE + offset;
+ }
+ }
+
+ mmio_write_32(STM32MP_DDR_BASE + testoffset, DDR_PATTERN);
+ }
+
+ return 0UL;
+}
+
+/*******************************************************************************
+ * This function checks the DDR size. It has to be run with Data Cache off.
+ * This test is run before data have been put in DDR, and is only done for
+ * cold boot. The DDR data can then be overwritten, and it is not useful to
+ * restore its content.
+ * Returns DDR computed size.
+ ******************************************************************************/
+size_t stm32mp_ddr_check_size(void)
+{
+ size_t offset = sizeof(uint32_t);
+
+ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
+
+ while (offset < STM32MP_DDR_MAX_SIZE) {
+ mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
+ dsb();
+
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
+ break;
+ }
+
+ offset <<= 1U;
+ }
+
+ return offset;
+}
diff --git a/drivers/st/ddr/stm32mp_ram.c b/drivers/st/ddr/stm32mp_ram.c
new file mode 100644
index 0000000000..28dc17d0ba
--- /dev/null
+++ b/drivers/st/ddr/stm32mp_ram.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022-2023, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/st/stm32mp_ram.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+int stm32mp_ddr_dt_get_info(void *fdt, int node, struct stm32mp_ddr_info *info)
+{
+ int ret;
+
+ ret = fdt_read_uint32(fdt, node, "st,mem-speed", &info->speed);
+ if (ret < 0) {
+ VERBOSE("%s: no st,mem-speed\n", __func__);
+ return -EINVAL;
+ }
+ info->size = dt_get_ddr_size();
+ if (info->size == 0U) {
+ VERBOSE("%s: no st,mem-size\n", __func__);
+ return -EINVAL;
+ }
+ info->name = fdt_getprop(fdt, node, "st,mem-name", NULL);
+ if (info->name == NULL) {
+ VERBOSE("%s: no st,mem-name\n", __func__);
+ return -EINVAL;
+ }
+
+ INFO("RAM: %s\n", info->name);
+
+ return 0;
+}
+
+int stm32mp_ddr_dt_get_param(void *fdt, int node, const struct stm32mp_ddr_param *param,
+ uint32_t param_size, uintptr_t config)
+{
+ int ret;
+ uint32_t idx;
+
+ for (idx = 0U; idx < param_size; idx++) {
+ ret = fdt_read_uint32_array(fdt, node, param[idx].name, param[idx].size,
+ (void *)(config + param[idx].offset));
+
+ VERBOSE("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret);
+ if (ret != 0) {
+ ERROR("%s: Cannot read %s, error=%d\n", __func__, param[idx].name, ret);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c
index ff52a22d9d..4c3c26d94a 100644
--- a/drivers/st/etzpc/etzpc.c
+++ b/drivers/st/etzpc/etzpc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -225,20 +225,8 @@ uintptr_t etzpc_get_base_address(void)
int etzpc_init(void)
{
uint32_t hwcfg;
- int node;
- struct dt_node_info etzpc_info;
- node = dt_get_node(&etzpc_info, -1, ETZPC_COMPAT);
- if (node < 0) {
- return -EIO;
- }
-
- /* Check ETZPC is secure only */
- if (etzpc_info.status != DT_SECURE) {
- return -EACCES;
- }
-
- etzpc_dev.base = etzpc_info.base;
+ etzpc_dev.base = STM32MP1_ETZPC_BASE;
hwcfg = mmio_read_32(etzpc_dev.base + ETZPC_HWCFGR);
diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
index 453069baea..9bdc854789 100644
--- a/drivers/st/fmc/stm32_fmc2_nand.c
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -9,11 +9,8 @@
#include <limits.h>
#include <stdint.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <common/debug.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
#include <drivers/raw_nand.h>
#include <drivers/st/stm32_fmc2_nand.h>
@@ -21,6 +18,9 @@
#include <drivers/st/stm32mp_reset.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
/* Timeout for device interface reset */
#define TIMEOUT_US_1_MS 1000U
@@ -162,7 +162,7 @@ static uintptr_t fmc2_base(void)
static void stm32_fmc2_nand_setup_timing(void)
{
struct stm32_fmc2_nand_timings tims;
- unsigned long hclk = stm32mp_clk_get_rate(stm32_fmc2.clock_id);
+ unsigned long hclk = clk_get_rate(stm32_fmc2.clock_id);
unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
unsigned long timing, tar, tclr, thiz, twait;
unsigned long tset_mem, tset_att, thold_mem, thold_att;
@@ -515,7 +515,7 @@ static int stm32_fmc2_read_page(struct nand_device *nand,
unsigned int s;
int ret;
- VERBOSE(">%s page %i buffer %lx\n", __func__, page, buffer);
+ VERBOSE(">%s page %u buffer %lx\n", __func__, page, buffer);
ret = nand_read_page_cmd(page, 0U, 0U, 0U);
if (ret != 0) {
@@ -909,7 +909,7 @@ int stm32_fmc2_init(void)
}
/* Enable Clock */
- stm32mp_clk_enable(stm32_fmc2.clock_id);
+ clk_enable(stm32_fmc2.clock_id);
/* Reset IP */
ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
index 7d63262d71..a4a64ca723 100644
--- a/drivers/st/gpio/stm32_gpio.c
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,16 +8,16 @@
#include <errno.h>
#include <stdbool.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <common/bl_common.h>
#include <common/debug.h>
+#include <drivers/clk.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32mp_clkfunc.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
#define DT_GPIO_BANK_SHIFT 12
#define DT_GPIO_BANK_MASK GENMASK(16, 12)
@@ -25,6 +25,10 @@
#define DT_GPIO_PIN_MASK GENMASK(11, 8)
#define DT_GPIO_MODE_MASK GENMASK(7, 0)
+static void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t type,
+ uint32_t speed, uint32_t pull, uint32_t od,
+ uint32_t alternate, uint8_t status);
+
/*******************************************************************************
* This function gets GPIO bank node in DT.
* Returns node offset if status is okay in DT, else return 0
@@ -99,6 +103,8 @@ static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
uint32_t pin;
uint32_t mode;
uint32_t alternate = GPIO_ALTERNATE_(0);
+ uint32_t type;
+ uint32_t od = GPIO_OD_OUTPUT_LOW;
int bank_node;
int clk;
@@ -128,7 +134,23 @@ static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
}
if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
- mode |= GPIO_OPEN_DRAIN;
+ type = GPIO_TYPE_OPEN_DRAIN;
+ } else {
+ type = GPIO_TYPE_PUSH_PULL;
+ }
+
+ if (fdt_getprop(fdt, node, "output-high", NULL) != NULL) {
+ if (mode == GPIO_MODE_INPUT) {
+ mode = GPIO_MODE_OUTPUT;
+ od = GPIO_OD_OUTPUT_HIGH;
+ }
+ }
+
+ if (fdt_getprop(fdt, node, "output-low", NULL) != NULL) {
+ if (mode == GPIO_MODE_INPUT) {
+ mode = GPIO_MODE_OUTPUT;
+ od = GPIO_OD_OUTPUT_LOW;
+ }
}
bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node);
@@ -145,7 +167,7 @@ static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
/* Platform knows the clock: assert it is okay */
assert((unsigned long)clk == stm32_get_gpio_bank_clock(bank));
- set_gpio(bank, pin, mode, speed, pull, alternate, status);
+ set_gpio(bank, pin, mode, type, speed, pull, od, alternate, status);
}
return 0;
@@ -159,7 +181,7 @@ static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
int dt_set_pinctrl_config(int node)
{
const fdt32_t *cuint;
- int lenp = 0;
+ int lenp;
uint32_t i;
uint8_t status;
void *fdt;
@@ -200,51 +222,53 @@ int dt_set_pinctrl_config(int node)
return 0;
}
-void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
- uint32_t pull, uint32_t alternate, uint8_t status)
+static void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t type,
+ uint32_t speed, uint32_t pull, uint32_t od,
+ uint32_t alternate, uint8_t status)
{
uintptr_t base = stm32_get_gpio_bank_base(bank);
unsigned long clock = stm32_get_gpio_bank_clock(bank);
assert(pin <= GPIO_PIN_MAX);
- stm32mp_clk_enable(clock);
+ clk_enable(clock);
- mmio_clrbits_32(base + GPIO_MODE_OFFSET,
- ((uint32_t)GPIO_MODE_MASK << (pin << 1)));
- mmio_setbits_32(base + GPIO_MODE_OFFSET,
- (mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
+ mmio_clrsetbits_32(base + GPIO_MODE_OFFSET,
+ (uint32_t)GPIO_MODE_MASK << (pin << 1U),
+ mode << (pin << 1U));
- if ((mode & GPIO_OPEN_DRAIN) != 0U) {
- mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
- } else {
- mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
- }
+ mmio_clrsetbits_32(base + GPIO_TYPE_OFFSET,
+ (uint32_t)GPIO_TYPE_MASK << pin,
+ type << pin);
- mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
- ((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
- mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
+ mmio_clrsetbits_32(base + GPIO_SPEED_OFFSET,
+ (uint32_t)GPIO_SPEED_MASK << (pin << 1U),
+ speed << (pin << 1U));
- mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
- ((uint32_t)GPIO_PULL_MASK << (pin << 1)));
- mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
+ mmio_clrsetbits_32(base + GPIO_PUPD_OFFSET,
+ (uint32_t)GPIO_PULL_MASK << (pin << 1U),
+ pull << (pin << 1U));
if (pin < GPIO_ALT_LOWER_LIMIT) {
- mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
- ((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
- mmio_setbits_32(base + GPIO_AFRL_OFFSET,
- alternate << (pin << 2));
+ mmio_clrsetbits_32(base + GPIO_AFRL_OFFSET,
+ (uint32_t)GPIO_ALTERNATE_MASK << (pin << 2U),
+ alternate << (pin << 2U));
} else {
- mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
- ((uint32_t)GPIO_ALTERNATE_MASK <<
- ((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
- mmio_setbits_32(base + GPIO_AFRH_OFFSET,
- alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
- 2));
+ uint32_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2U;
+
+ mmio_clrsetbits_32(base + GPIO_AFRH_OFFSET,
+ (uint32_t)GPIO_ALTERNATE_MASK << shift,
+ alternate << shift);
}
+ mmio_clrsetbits_32(base + GPIO_OD_OFFSET,
+ (uint32_t)GPIO_OD_MASK << pin,
+ od << pin);
+
VERBOSE("GPIO %u mode set to 0x%x\n", bank,
mmio_read_32(base + GPIO_MODE_OFFSET));
+ VERBOSE("GPIO %u type set to 0x%x\n", bank,
+ mmio_read_32(base + GPIO_TYPE_OFFSET));
VERBOSE("GPIO %u speed set to 0x%x\n", bank,
mmio_read_32(base + GPIO_SPEED_OFFSET));
VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
@@ -253,16 +277,22 @@ void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
mmio_read_32(base + GPIO_AFRL_OFFSET));
VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
mmio_read_32(base + GPIO_AFRH_OFFSET));
+ VERBOSE("GPIO %u output data set to 0x%x\n", bank,
+ mmio_read_32(base + GPIO_OD_OFFSET));
- stm32mp_clk_disable(clock);
+ clk_disable(clock);
if (status == DT_SECURE) {
stm32mp_register_secure_gpio(bank, pin);
+#if !IMAGE_BL2
set_gpio_secure_cfg(bank, pin, true);
+#endif
} else {
stm32mp_register_non_secure_gpio(bank, pin);
+#if !IMAGE_BL2
set_gpio_secure_cfg(bank, pin, false);
+#endif
}
}
@@ -273,7 +303,7 @@ void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
assert(pin <= GPIO_PIN_MAX);
- stm32mp_clk_enable(clock);
+ clk_enable(clock);
if (secure) {
mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
@@ -281,5 +311,13 @@ void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
}
- stm32mp_clk_disable(clock);
+ clk_disable(clock);
+}
+
+void set_gpio_reset_cfg(uint32_t bank, uint32_t pin)
+{
+ set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_TYPE_PUSH_PULL,
+ GPIO_SPEED_LOW, GPIO_NO_PULL, GPIO_OD_OUTPUT_LOW,
+ GPIO_ALTERNATE_(0), DT_DISABLED);
+ set_gpio_secure_cfg(bank, pin, stm32_gpio_is_secure_at_reset(bank));
}
diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
index ed880522b0..32cecff6a3 100644
--- a/drivers/st/i2c/stm32_i2c.c
+++ b/drivers/st/i2c/stm32_i2c.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,16 +8,17 @@
#include <stdbool.h>
#include <stdlib.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32_i2c.h>
#include <lib/mmio.h>
#include <lib/utils.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
/* STM32 I2C registers offsets */
#define I2C_CR1 0x00U
@@ -96,40 +97,29 @@ static int i2c_config_analog_filter(struct i2c_handle_s *hi2c,
int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
struct stm32_i2c_init_s *init)
{
- const fdt32_t *cuint;
-
- cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL);
- if (cuint == NULL) {
- init->rise_time = STM32_I2C_RISE_TIME_DEFAULT;
- } else {
- init->rise_time = fdt32_to_cpu(*cuint);
- }
-
- cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL);
- if (cuint == NULL) {
- init->fall_time = STM32_I2C_FALL_TIME_DEFAULT;
- } else {
- init->fall_time = fdt32_to_cpu(*cuint);
- }
-
- cuint = fdt_getprop(fdt, node, "clock-frequency", NULL);
- if (cuint == NULL) {
- init->speed_mode = STM32_I2C_SPEED_DEFAULT;
- } else {
- switch (fdt32_to_cpu(*cuint)) {
- case STANDARD_RATE:
- init->speed_mode = I2C_SPEED_STANDARD;
- break;
- case FAST_RATE:
- init->speed_mode = I2C_SPEED_FAST;
- break;
- case FAST_PLUS_RATE:
- init->speed_mode = I2C_SPEED_FAST_PLUS;
- break;
- default:
- init->speed_mode = STM32_I2C_SPEED_DEFAULT;
- break;
- }
+ uint32_t read_val;
+
+ init->rise_time = fdt_read_uint32_default(fdt, node,
+ "i2c-scl-rising-time-ns",
+ STM32_I2C_RISE_TIME_DEFAULT);
+
+ init->fall_time = fdt_read_uint32_default(fdt, node,
+ "i2c-scl-falling-time-ns",
+ STM32_I2C_FALL_TIME_DEFAULT);
+
+ read_val = fdt_read_uint32_default(fdt, node, "clock-frequency",
+ STANDARD_RATE);
+ switch (read_val) {
+ case FAST_PLUS_RATE:
+ init->speed_mode = I2C_SPEED_FAST_PLUS;
+ break;
+ case FAST_RATE:
+ init->speed_mode = I2C_SPEED_FAST;
+ break;
+ case STANDARD_RATE:
+ default:
+ init->speed_mode = I2C_SPEED_STANDARD;
+ break;
}
return dt_set_pinctrl_config(node);
@@ -158,7 +148,7 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c,
hi2c->i2c_state = I2C_STATE_BUSY;
- stm32mp_clk_enable(hi2c->clock);
+ clk_enable(hi2c->clock);
/* Disable the selected I2C peripheral */
mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
@@ -220,11 +210,11 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c,
I2C_ANALOGFILTER_DISABLE);
if (rc != 0) {
ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
- stm32mp_clk_disable(hi2c->clock);
+ clk_disable(hi2c->clock);
return rc;
}
- stm32mp_clk_disable(hi2c->clock);
+ clk_disable(hi2c->clock);
return rc;
}
@@ -548,7 +538,7 @@ static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
return -EINVAL;
}
- stm32mp_clk_enable(hi2c->clock);
+ clk_enable(hi2c->clock);
hi2c->lock = 1;
@@ -648,7 +638,7 @@ static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
bail:
hi2c->lock = 0;
- stm32mp_clk_disable(hi2c->clock);
+ clk_disable(hi2c->clock);
return rc;
}
@@ -729,7 +719,7 @@ static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
return -EINVAL;
}
- stm32mp_clk_enable(hi2c->clock);
+ clk_enable(hi2c->clock);
hi2c->lock = 1;
@@ -817,7 +807,7 @@ static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
bail:
hi2c->lock = 0;
- stm32mp_clk_disable(hi2c->clock);
+ clk_disable(hi2c->clock);
return rc;
}
@@ -882,7 +872,7 @@ bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
return rc;
}
- stm32mp_clk_enable(hi2c->clock);
+ clk_enable(hi2c->clock);
hi2c->lock = 1;
hi2c->i2c_mode = I2C_MODE_NONE;
@@ -974,7 +964,7 @@ bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
bail:
hi2c->lock = 0;
- stm32mp_clk_disable(hi2c->clock);
+ clk_disable(hi2c->clock);
return rc;
}
diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c
deleted file mode 100644
index 2bf88e6f75..0000000000
--- a/drivers/st/io/io_mmc.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include <common/debug.h>
-#include <drivers/io/io_driver.h>
-#include <drivers/io/io_storage.h>
-#include <drivers/mmc.h>
-#include <drivers/st/io_mmc.h>
-#include <drivers/st/stm32_sdmmc2.h>
-
-/* SDMMC device functions */
-static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info);
-static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
- io_entity_t *entity);
-static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
-static int mmc_block_seek(io_entity_t *entity, int mode,
- signed long long offset);
-static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
- size_t *length_read);
-static int mmc_block_close(io_entity_t *entity);
-static int mmc_dev_close(io_dev_info_t *dev_info);
-static io_type_t device_type_mmc(void);
-
-static signed long long seek_offset;
-static size_t (*_read_blocks)(int lba, uintptr_t buf, size_t size);
-
-static const io_dev_connector_t mmc_dev_connector = {
- .dev_open = mmc_dev_open
-};
-
-static const io_dev_funcs_t mmc_dev_funcs = {
- .type = device_type_mmc,
- .open = mmc_block_open,
- .seek = mmc_block_seek,
- .size = NULL,
- .read = mmc_block_read,
- .write = NULL,
- .close = mmc_block_close,
- .dev_init = mmc_dev_init,
- .dev_close = mmc_dev_close,
-};
-
-static const io_dev_info_t mmc_dev_info = {
- .funcs = &mmc_dev_funcs,
- .info = 0,
-};
-
-/* Identify the device type as mmc device */
-static io_type_t device_type_mmc(void)
-{
- return IO_TYPE_MMC;
-}
-
-/* Open a connection to the mmc device */
-static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info)
-{
- struct io_mmc_dev_spec *device_spec =
- (struct io_mmc_dev_spec *)init_params;
-
- assert(dev_info != NULL);
- *dev_info = (io_dev_info_t *)&mmc_dev_info;
-
- _read_blocks = !device_spec->use_boot_part ?
- mmc_read_blocks : mmc_boot_part_read_blocks;
-
- return 0;
-}
-
-static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
-{
- return 0;
-}
-
-/* Close a connection to the mmc device */
-static int mmc_dev_close(io_dev_info_t *dev_info)
-{
- return 0;
-}
-
-/* Open a file on the mmc device */
-static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
- io_entity_t *entity)
-{
- seek_offset = 0;
- return 0;
-}
-
-/* Seek to a particular file offset on the mmc device */
-static int mmc_block_seek(io_entity_t *entity, int mode,
- signed long long offset)
-{
- seek_offset = offset;
- return 0;
-}
-
-/* Read data from a file on the mmc device */
-static int mmc_block_read(io_entity_t *entity, uintptr_t buffer,
- size_t length, size_t *length_read)
-{
- uint8_t retries;
-
- for (retries = 0U; retries < 3U; retries++) {
- *length_read = _read_blocks(seek_offset / MMC_BLOCK_SIZE,
- buffer, length);
-
- if (*length_read == length) {
- return 0;
- }
- WARN("%s: length_read = %lu (!= %lu), retry %u\n", __func__,
- (unsigned long)*length_read, (unsigned long)length,
- retries + 1U);
- }
-
- return -EIO;
-}
-
-/* Close a file on the mmc device */
-static int mmc_block_close(io_entity_t *entity)
-{
- return 0;
-}
-
-/* Register the mmc driver with the IO abstraction */
-int register_io_dev_mmc(const io_dev_connector_t **dev_con)
-{
- int result;
-
- assert(dev_con != NULL);
-
- result = io_register_device(&mmc_dev_info);
- if (result == 0) {
- *dev_con = &mmc_dev_connector;
- }
-
- return result;
-}
diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c
deleted file mode 100644
index 3e377cd483..0000000000
--- a/drivers/st/io/io_stm32image.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <platform_def.h>
-
-#include <common/debug.h>
-#include <drivers/io/io_driver.h>
-#include <drivers/io/io_storage.h>
-#include <drivers/st/io_stm32image.h>
-#include <lib/utils.h>
-#include <plat/common/platform.h>
-
-static uintptr_t backend_dev_handle;
-static uintptr_t backend_image_spec;
-static uint32_t *stm32_img;
-static uint8_t first_lba_buffer[MAX_LBA_SIZE] __aligned(4);
-static struct stm32image_part_info *current_part;
-
-/* STM32 Image driver functions */
-static int stm32image_dev_open(const uintptr_t init_params,
- io_dev_info_t **dev_info);
-static int stm32image_partition_open(io_dev_info_t *dev_info,
- const uintptr_t spec, io_entity_t *entity);
-static int stm32image_partition_size(io_entity_t *entity, size_t *length);
-static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
- size_t length, size_t *length_read);
-static int stm32image_partition_close(io_entity_t *entity);
-static int stm32image_dev_init(io_dev_info_t *dev_info,
- const uintptr_t init_params);
-static int stm32image_dev_close(io_dev_info_t *dev_info);
-
-/* Identify the device type as a virtual driver */
-static io_type_t device_type_stm32image(void)
-{
- return IO_TYPE_STM32IMAGE;
-}
-
-static const io_dev_connector_t stm32image_dev_connector = {
- .dev_open = stm32image_dev_open
-};
-
-static const io_dev_funcs_t stm32image_dev_funcs = {
- .type = device_type_stm32image,
- .open = stm32image_partition_open,
- .size = stm32image_partition_size,
- .read = stm32image_partition_read,
- .close = stm32image_partition_close,
- .dev_init = stm32image_dev_init,
- .dev_close = stm32image_dev_close,
-};
-
-static io_dev_info_t stm32image_dev_info = {
- .funcs = &stm32image_dev_funcs,
- .info = (uintptr_t)0,
-};
-
-static struct stm32image_device_info stm32image_dev;
-
-static int get_part_idx_by_binary_type(uint32_t binary_type)
-{
- int i;
-
- for (i = 0; i < STM32_PART_NUM; i++) {
- if (stm32image_dev.part_info[i].binary_type == binary_type) {
- return i;
- }
- }
-
- return -EINVAL;
-}
-
-/* Open a connection to the STM32IMAGE device */
-static int stm32image_dev_open(const uintptr_t init_params,
- io_dev_info_t **dev_info)
-{
- int i;
- struct stm32image_device_info *device_info =
- (struct stm32image_device_info *)init_params;
-
- assert(dev_info != NULL);
- *dev_info = (io_dev_info_t *)&stm32image_dev_info;
-
- stm32image_dev.device_size = device_info->device_size;
- stm32image_dev.lba_size = device_info->lba_size;
-
- for (i = 0; i < STM32_PART_NUM; i++) {
- memcpy(stm32image_dev.part_info[i].name,
- device_info->part_info[i].name, MAX_PART_NAME_SIZE);
- stm32image_dev.part_info[i].binary_type =
- device_info->part_info[i].binary_type;
- stm32image_dev.part_info[i].part_offset =
- device_info->part_info[i].part_offset;
- stm32image_dev.part_info[i].bkp_offset =
- device_info->part_info[i].bkp_offset;
- }
-
- return 0;
-}
-
-/* Do some basic package checks */
-static int stm32image_dev_init(io_dev_info_t *dev_info,
- const uintptr_t init_params)
-{
- int result;
-
- if ((backend_dev_handle != 0U) || (backend_image_spec != 0U)) {
- ERROR("STM32 Image io supports only one session\n");
- return -ENOMEM;
- }
-
- /* Obtain a reference to the image by querying the platform layer */
- result = plat_get_image_source(STM32_IMAGE_ID, &backend_dev_handle,
- &backend_image_spec);
- if (result != 0) {
- ERROR("STM32 image error (%i)\n", result);
- return -EINVAL;
- }
-
- return result;
-}
-
-/* Close a connection to the STM32 Image device */
-static int stm32image_dev_close(io_dev_info_t *dev_info)
-{
- backend_dev_handle = 0U;
- backend_image_spec = 0U;
- stm32_img = NULL;
-
- return 0;
-}
-
-/* Open a partition */
-static int stm32image_partition_open(io_dev_info_t *dev_info,
- const uintptr_t spec, io_entity_t *entity)
-{
- const struct stm32image_part_info *partition_spec;
- int idx;
-
- assert(entity != NULL);
-
- partition_spec = (struct stm32image_part_info *)spec;
- assert(partition_spec != NULL);
-
- idx = get_part_idx_by_binary_type(partition_spec->binary_type);
- if ((idx < 0) || (idx > STM32_PART_NUM)) {
- ERROR("Wrong partition index (%d)\n", idx);
- return -EINVAL;
- }
-
- current_part = &stm32image_dev.part_info[idx];
- stm32_img = (uint32_t *)&current_part->part_offset;
-
- return 0;
-}
-
-/* Return the size of a partition */
-static int stm32image_partition_size(io_entity_t *entity, size_t *length)
-{
- int result;
- uintptr_t backend_handle;
- size_t bytes_read;
- boot_api_image_header_t *header =
- (boot_api_image_header_t *)first_lba_buffer;
-
- assert(entity != NULL);
- assert(length != NULL);
-
- /* Attempt to access the image */
- result = io_open(backend_dev_handle, backend_image_spec,
- &backend_handle);
-
- if (result < 0) {
- ERROR("%s: io_open (%i)\n", __func__, result);
- return result;
- }
-
- /* Reset magic header value */
- header->magic = 0;
-
- while (header->magic == 0U) {
- result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img);
- if (result != 0) {
- ERROR("%s: io_seek (%i)\n", __func__, result);
- break;
- }
-
- result = io_read(backend_handle, (uintptr_t)header,
- MAX_LBA_SIZE, (size_t *)&bytes_read);
- if (result != 0) {
- if (current_part->bkp_offset == 0U) {
- ERROR("%s: io_read (%i)\n", __func__, result);
- }
- header->magic = 0;
- }
-
- if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
- (header->binary_type != current_part->binary_type) ||
- (header->image_length >= stm32image_dev.device_size)) {
- VERBOSE("%s: partition %s not found at %x\n",
- __func__, current_part->name, *stm32_img);
-
- if (current_part->bkp_offset == 0U) {
- result = -ENOMEM;
- break;
- }
-
- /* Header not correct, check next offset for backup */
- *stm32_img += current_part->bkp_offset;
- if (*stm32_img > stm32image_dev.device_size) {
- /* No backup found, end of device reached */
- WARN("%s : partition %s not found\n",
- __func__, current_part->name);
- result = -ENOMEM;
- break;
- }
- header->magic = 0;
- }
- }
-
- io_close(backend_handle);
-
- if (result != 0) {
- return result;
- }
-
- if (header->image_length < stm32image_dev.lba_size) {
- *length = stm32image_dev.lba_size;
- } else {
- *length = header->image_length;
- }
-
- INFO("STM32 Image size : %lu\n", (unsigned long)*length);
-
- return 0;
-}
-
-/* Read data from a partition */
-static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
- size_t length, size_t *length_read)
-{
- int result;
- uint8_t *local_buffer;
- boot_api_image_header_t *header =
- (boot_api_image_header_t *)first_lba_buffer;
-
- assert(entity != NULL);
- assert(buffer != 0U);
- assert(length_read != NULL);
-
- local_buffer = (uint8_t *)buffer;
- *length_read = 0U;
-
- while (*length_read == 0U) {
- int offset;
- int local_length;
- uintptr_t backend_handle;
-
- if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
- /* Check for backup as image is corrupted */
- if (current_part->bkp_offset == 0U) {
- result = -ENOMEM;
- break;
- }
-
- *stm32_img += current_part->bkp_offset;
- if (*stm32_img >= stm32image_dev.device_size) {
- /* End of device reached */
- result = -ENOMEM;
- break;
- }
-
- local_buffer = (uint8_t *)buffer;
-
- result = stm32image_partition_size(entity, &length);
- if (result != 0) {
- break;
- }
- }
-
- /* Part of image already loaded with the header */
- memcpy(local_buffer, (uint8_t *)first_lba_buffer +
- sizeof(boot_api_image_header_t),
- MAX_LBA_SIZE - sizeof(boot_api_image_header_t));
- local_buffer += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
- offset = MAX_LBA_SIZE;
-
- /* New image length to be read */
- local_length = round_up(length -
- ((MAX_LBA_SIZE) -
- sizeof(boot_api_image_header_t)),
- stm32image_dev.lba_size);
-
- if ((header->load_address != 0U) &&
- (header->load_address != buffer)) {
- ERROR("Wrong load address\n");
- panic();
- }
-
- result = io_open(backend_dev_handle, backend_image_spec,
- &backend_handle);
-
- if (result != 0) {
- ERROR("%s: io_open (%i)\n", __func__, result);
- break;
- }
-
- result = io_seek(backend_handle, IO_SEEK_SET,
- *stm32_img + offset);
-
- if (result != 0) {
- ERROR("%s: io_seek (%i)\n", __func__, result);
- *length_read = 0;
- io_close(backend_handle);
- break;
- }
-
- result = io_read(backend_handle, (uintptr_t)local_buffer,
- local_length, length_read);
-
- /* Adding part of size already read from header */
- *length_read += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
-
- if (result != 0) {
- ERROR("%s: io_read (%i)\n", __func__, result);
- *length_read = 0;
- header->magic = 0;
- continue;
- }
-
- result = stm32mp_check_header(header, buffer);
- if (result != 0) {
- ERROR("Header check failed\n");
- *length_read = 0;
- header->magic = 0;
- }
-
- result = stm32mp_auth_image(header, buffer);
- if (result != 0) {
- ERROR("Authentication Failed (%i)\n", result);
- return result;
- }
-
- io_close(backend_handle);
- }
-
- return result;
-}
-
-/* Close a partition */
-static int stm32image_partition_close(io_entity_t *entity)
-{
- current_part = NULL;
-
- return 0;
-}
-
-/* Register the stm32image driver with the IO abstraction */
-int register_io_dev_stm32image(const io_dev_connector_t **dev_con)
-{
- int result;
-
- assert(dev_con != NULL);
-
- result = io_register_device(&stm32image_dev_info);
- if (result == 0) {
- *dev_con = &stm32image_dev_connector;
- }
-
- return result;
-}
diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c
index c052b4dfbe..74451d70bc 100644
--- a/drivers/st/iwdg/stm32_iwdg.c
+++ b/drivers/st/iwdg/stm32_iwdg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,6 +15,7 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
#include <drivers/st/stm32_iwdg.h>
#include <drivers/st/stm32mp_clkfunc.h>
@@ -61,12 +62,12 @@ void stm32_iwdg_refresh(void)
/* 0x00000000 is not a valid address for IWDG peripherals */
if (iwdg->base != 0U) {
- stm32mp_clk_enable(iwdg->clock);
+ clk_enable(iwdg->clock);
mmio_write_32(iwdg->base + IWDG_KR_OFFSET,
IWDG_KR_RELOAD_KEY);
- stm32mp_clk_disable(iwdg->clock);
+ clk_disable(iwdg->clock);
}
}
}
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
index cff3a344f7..66988d71de 100644
--- a/drivers/st/mmc/stm32_sdmmc2.c
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2018-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,13 +8,10 @@
#include <errno.h>
#include <string.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
#include <drivers/mmc.h>
#include <drivers/st/stm32_gpio.h>
@@ -22,8 +19,11 @@
#include <drivers/st/stm32mp_reset.h>
#include <lib/mmio.h>
#include <lib/utils.h>
+#include <libfdt.h>
#include <plat/common/platform.h>
+#include <platform_def.h>
+
/* Registers offsets */
#define SDMMC_POWER 0x00U
#define SDMMC_CLKCR 0x04U
@@ -50,6 +50,7 @@
/* SDMMC power control register */
#define SDMMC_POWER_PWRCTRL GENMASK(1, 0)
+#define SDMMC_POWER_PWRCTRL_PWR_CYCLE BIT(1)
#define SDMMC_POWER_DIRPOL BIT(4)
/* SDMMC clock control register */
@@ -117,7 +118,28 @@
#define TIMEOUT_US_10_MS 10000U
#define TIMEOUT_US_1_S 1000000U
+/* Power cycle delays in ms */
+#define VCC_POWER_OFF_DELAY 2
+#define VCC_POWER_ON_DELAY 2
+#define POWER_CYCLE_DELAY 2
+#define POWER_OFF_DELAY 2
+#define POWER_ON_DELAY 1
+
+#ifndef DT_SDMMC2_COMPAT
#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
+#endif
+
+#if STM32MP13 || STM32MP15
+#define SDMMC_FIFO_SIZE 64U
+#else
+#define SDMMC_FIFO_SIZE 1024U
+#endif
+
+#define STM32MP_MMC_INIT_FREQ U(400000) /*400 KHz*/
+#define STM32MP_SD_NORMAL_SPEED_MAX_FREQ U(25000000) /*25 MHz*/
+#define STM32MP_SD_HIGH_SPEED_MAX_FREQ U(50000000) /*50 MHz*/
+#define STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ U(26000000) /*26 MHz*/
+#define STM32MP_EMMC_HIGH_SPEED_MAX_FREQ U(52000000) /*52 MHz*/
static void stm32_sdmmc2_init(void);
static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd);
@@ -138,6 +160,8 @@ static const struct mmc_ops stm32_sdmmc2_ops = {
static struct stm32_sdmmc2_params sdmmc2_params;
+static bool next_cmd_is_acmd;
+
#pragma weak plat_sdmmc2_use_dma
bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory)
{
@@ -149,11 +173,37 @@ static void stm32_sdmmc2_init(void)
uint32_t clock_div;
uint32_t freq = STM32MP_MMC_INIT_FREQ;
uintptr_t base = sdmmc2_params.reg_base;
+ int ret;
if (sdmmc2_params.max_freq != 0U) {
freq = MIN(sdmmc2_params.max_freq, freq);
}
+ if (sdmmc2_params.vmmc_regu != NULL) {
+ ret = regulator_disable(sdmmc2_params.vmmc_regu);
+ if (ret < 0) {
+ panic();
+ }
+ }
+
+ mdelay(VCC_POWER_OFF_DELAY);
+
+ mmio_write_32(base + SDMMC_POWER,
+ SDMMC_POWER_PWRCTRL_PWR_CYCLE | sdmmc2_params.dirpol);
+ mdelay(POWER_CYCLE_DELAY);
+
+ if (sdmmc2_params.vmmc_regu != NULL) {
+ ret = regulator_enable(sdmmc2_params.vmmc_regu);
+ if (ret < 0) {
+ panic();
+ }
+ }
+
+ mdelay(VCC_POWER_ON_DELAY);
+
+ mmio_write_32(base + SDMMC_POWER, sdmmc2_params.dirpol);
+ mdelay(POWER_OFF_DELAY);
+
clock_div = div_round_up(sdmmc2_params.clk_rate, freq * 2U);
mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
@@ -163,7 +213,7 @@ static void stm32_sdmmc2_init(void)
mmio_write_32(base + SDMMC_POWER,
SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol);
- mdelay(1);
+ mdelay(POWER_ON_DELAY);
}
static int stm32_sdmmc2_stop_transfer(void)
@@ -221,6 +271,20 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
case MMC_CMD(1):
arg_reg |= OCR_POWERUP;
break;
+ case MMC_CMD(6):
+ if ((sdmmc2_params.device_info->mmc_dev_type == MMC_IS_SD_HC) &&
+ (!next_cmd_is_acmd)) {
+ cmd_reg |= SDMMC_CMDR_CMDTRANS;
+ if (sdmmc2_params.use_dma) {
+ flags_data |= SDMMC_STAR_DCRCFAIL |
+ SDMMC_STAR_DTIMEOUT |
+ SDMMC_STAR_DATAEND |
+ SDMMC_STAR_RXOVERR |
+ SDMMC_STAR_IDMATE |
+ SDMMC_STAR_DBCKEND;
+ }
+ }
+ break;
case MMC_CMD(8):
if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
cmd_reg |= SDMMC_CMDR_CMDTRANS;
@@ -258,6 +322,8 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
break;
}
+ next_cmd_is_acmd = (cmd->cmd_idx == MMC_CMD(55));
+
mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
/*
@@ -265,8 +331,7 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
* Skip CMD55 as the next command could be data related, and
* the register could have been set in prepare function.
*/
- if (((cmd_reg & SDMMC_CMDR_CMDTRANS) == 0U) &&
- (cmd->cmd_idx != MMC_CMD(55))) {
+ if (((cmd_reg & SDMMC_CMDR_CMDTRANS) == 0U) && !next_cmd_is_acmd) {
mmio_write_32(base + SDMMC_DCTRLR, 0U);
}
@@ -285,7 +350,7 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
while ((status & flags_cmd) == 0U) {
if (timeout_elapsed(timeout)) {
err = -ETIMEDOUT;
- ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n",
+ ERROR("%s: timeout 10ms (cmd = %u,status = %x)\n",
__func__, cmd->cmd_idx, status);
goto err_exit;
}
@@ -305,12 +370,12 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
(cmd->cmd_idx == MMC_CMD(13)) ||
((cmd->cmd_idx == MMC_CMD(8)) &&
(cmd->resp_type == MMC_RESPONSE_R7)))) {
- ERROR("%s: CTIMEOUT (cmd = %d,status = %x)\n",
+ ERROR("%s: CTIMEOUT (cmd = %u,status = %x)\n",
__func__, cmd->cmd_idx, status);
}
} else {
err = -EIO;
- ERROR("%s: CRCFAIL (cmd = %d,status = %x)\n",
+ ERROR("%s: CRCFAIL (cmd = %u,status = %x)\n",
__func__, cmd->cmd_idx, status);
}
@@ -351,7 +416,7 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
while ((status & flags_data) == 0U) {
if (timeout_elapsed(timeout)) {
- ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n",
+ ERROR("%s: timeout 10ms (cmd = %u,status = %x)\n",
__func__, cmd->cmd_idx, status);
err = -ETIMEDOUT;
goto err_exit;
@@ -363,7 +428,7 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
if ((status & (SDMMC_STAR_DTIMEOUT | SDMMC_STAR_DCRCFAIL |
SDMMC_STAR_TXUNDERR | SDMMC_STAR_RXOVERR |
SDMMC_STAR_IDMATE)) != 0U) {
- ERROR("%s: Error flag (cmd = %d,status = %x)\n", __func__,
+ ERROR("%s: Error flag (cmd = %u,status = %x)\n", __func__,
cmd->cmd_idx, status);
err = -EIO;
}
@@ -473,12 +538,12 @@ static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
uint32_t data_ctrl = SDMMC_DCTRLR_DTDIR;
uint32_t arg_size;
- assert(size != 0U);
+ assert((size != 0U) && (size <= UINT32_MAX));
if (size > MMC_BLOCK_SIZE) {
arg_size = MMC_BLOCK_SIZE;
} else {
- arg_size = size;
+ arg_size = (uint32_t)size;
}
sdmmc2_params.use_dma = plat_sdmmc2_use_dma(base, buf);
@@ -591,7 +656,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
return -ETIMEDOUT;
}
- if (size < (8U * sizeof(uint32_t))) {
+ if (size < (SDMMC_FIFO_SIZE / 2U)) {
if ((mmio_read_32(base + SDMMC_DCNTR) > 0U) &&
((status & SDMMC_STAR_RXFIFOE) == 0U)) {
*buffer = mmio_read_32(fifo_reg);
@@ -601,7 +666,8 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
uint32_t count;
/* Read data from SDMMC Rx FIFO */
- for (count = 0; count < 8U; count++) {
+ for (count = 0; count < (SDMMC_FIFO_SIZE / 2U);
+ count += sizeof(uint32_t)) {
*buffer = mmio_read_32(fifo_reg);
buffer++;
}
@@ -628,6 +694,7 @@ static int stm32_sdmmc2_dt_get_config(void)
int sdmmc_node;
void *fdt = NULL;
const fdt32_t *cuint;
+ struct dt_node_info dt_info;
if (fdt_get_address(&fdt) == 0) {
return -FDT_ERR_NOTFOUND;
@@ -637,27 +704,14 @@ static int stm32_sdmmc2_dt_get_config(void)
return -FDT_ERR_NOTFOUND;
}
- sdmmc_node = fdt_node_offset_by_compatible(fdt, -1, DT_SDMMC2_COMPAT);
-
- while (sdmmc_node != -FDT_ERR_NOTFOUND) {
- cuint = fdt_getprop(fdt, sdmmc_node, "reg", NULL);
- if (cuint == NULL) {
- continue;
- }
-
- if (fdt32_to_cpu(*cuint) == sdmmc2_params.reg_base) {
- break;
- }
-
- sdmmc_node = fdt_node_offset_by_compatible(fdt, sdmmc_node,
- DT_SDMMC2_COMPAT);
- }
-
+ sdmmc_node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT,
+ sdmmc2_params.reg_base);
if (sdmmc_node == -FDT_ERR_NOTFOUND) {
return -FDT_ERR_NOTFOUND;
}
- if (fdt_get_status(sdmmc_node) == DT_DISABLED) {
+ dt_fill_device_info(&dt_info, sdmmc_node);
+ if (dt_info.status == DT_DISABLED) {
return -FDT_ERR_NOTFOUND;
}
@@ -665,21 +719,8 @@ static int stm32_sdmmc2_dt_get_config(void)
return -FDT_ERR_BADVALUE;
}
- cuint = fdt_getprop(fdt, sdmmc_node, "clocks", NULL);
- if (cuint == NULL) {
- return -FDT_ERR_NOTFOUND;
- }
-
- cuint++;
- sdmmc2_params.clock_id = fdt32_to_cpu(*cuint);
-
- cuint = fdt_getprop(fdt, sdmmc_node, "resets", NULL);
- if (cuint == NULL) {
- return -FDT_ERR_NOTFOUND;
- }
-
- cuint++;
- sdmmc2_params.reset_id = fdt32_to_cpu(*cuint);
+ sdmmc2_params.clock_id = dt_info.clock;
+ sdmmc2_params.reset_id = dt_info.reset;
if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) {
sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0;
@@ -714,6 +755,8 @@ static int stm32_sdmmc2_dt_get_config(void)
sdmmc2_params.max_freq = fdt32_to_cpu(*cuint);
}
+ sdmmc2_params.vmmc_regu = regulator_get_by_supply_name(fdt, sdmmc_node, "vmmc");
+
return 0;
}
@@ -724,8 +767,6 @@ unsigned long long stm32_sdmmc2_mmc_get_device_size(void)
int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
{
- int rc;
-
assert((params != NULL) &&
((params->reg_base & MMC_BLOCK_MASK) == 0U) &&
((params->bus_width == MMC_BUS_WIDTH_1) ||
@@ -734,25 +775,31 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params));
+ sdmmc2_params.vmmc_regu = NULL;
+
if (stm32_sdmmc2_dt_get_config() != 0) {
ERROR("%s: DT error\n", __func__);
return -ENOMEM;
}
- stm32mp_clk_enable(sdmmc2_params.clock_id);
+ clk_enable(sdmmc2_params.clock_id);
- rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
- if (rc != 0) {
- panic();
- }
- udelay(2);
- rc = stm32mp_reset_deassert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
- if (rc != 0) {
- panic();
+ if ((int)sdmmc2_params.reset_id >= 0) {
+ int rc;
+
+ rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
+ if (rc != 0) {
+ panic();
+ }
+ udelay(2);
+ rc = stm32mp_reset_deassert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
+ if (rc != 0) {
+ panic();
+ }
+ mdelay(1);
}
- mdelay(1);
- sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id);
+ sdmmc2_params.clk_rate = clk_get_rate(sdmmc2_params.clock_id);
sdmmc2_params.device_info->ocr_voltage = OCR_3_2_3_3 | OCR_3_3_3_4;
return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate,
diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c
index b2bb482f9d..1e1628770b 100644
--- a/drivers/st/pmic/stm32mp_pmic.c
+++ b/drivers/st/pmic/stm32mp_pmic.c
@@ -1,57 +1,67 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
#include <errno.h>
-#include <libfdt.h>
-
-#include <platform_def.h>
-
#include <common/debug.h>
#include <drivers/delay_timer.h>
+#include <drivers/st/regulator.h>
#include <drivers/st/stm32_i2c.h>
#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stpmic1.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
+#include <libfdt.h>
-#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2))
-#define STPMIC1_LDO12356_OUTPUT_SHIFT 2
-#define STPMIC1_LDO3_MODE (uint8_t)(BIT(7))
-#define STPMIC1_LDO3_DDR_SEL 31U
-#define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT)
-
-#define STPMIC1_BUCK_OUTPUT_SHIFT 2
-#define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT)
+#include <platform_def.h>
-#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1
+#define PMIC_NODE_NOT_FOUND 1
+#define NB_REG 14U
static struct i2c_handle_s i2c_handle;
static uint32_t pmic_i2c_addr;
+static int register_pmic(void);
+
static int dt_get_pmic_node(void *fdt)
{
- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
+ static int node = -FDT_ERR_BADOFFSET;
+
+ if (node == -FDT_ERR_BADOFFSET) {
+ node = fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
+ }
+
+ return node;
}
int dt_pmic_status(void)
{
+ static int status = -FDT_ERR_BADVALUE;
int node;
void *fdt;
+ if (status != -FDT_ERR_BADVALUE) {
+ return status;
+ }
+
if (fdt_get_address(&fdt) == 0) {
return -ENOENT;
}
node = dt_get_pmic_node(fdt);
if (node <= 0) {
- return -FDT_ERR_NOTFOUND;
+ status = -FDT_ERR_NOTFOUND;
+
+ return status;
}
- return fdt_get_status(node);
+ status = (int)fdt_get_status(node);
+
+ return status;
}
static bool dt_pmic_is_secure(void)
@@ -65,122 +75,49 @@ static bool dt_pmic_is_secure(void)
/*
* Get PMIC and its I2C bus configuration from the device tree.
- * Return 0 on success, negative on error, 1 if no PMIC node is found.
+ * Return 0 on success, negative on error, 1 if no PMIC node is defined.
*/
static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
struct stm32_i2c_init_s *init)
{
- int pmic_node, i2c_node;
- void *fdt;
- const fdt32_t *cuint;
-
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
- }
-
- pmic_node = dt_get_pmic_node(fdt);
- if (pmic_node < 0) {
- return 1;
- }
-
- cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
- if (cuint == NULL) {
- return -FDT_ERR_NOTFOUND;
- }
-
- pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
- if (pmic_i2c_addr > UINT16_MAX) {
- return -EINVAL;
- }
-
- i2c_node = fdt_parent_offset(fdt, pmic_node);
- if (i2c_node < 0) {
- return -FDT_ERR_NOTFOUND;
- }
-
- dt_fill_device_info(i2c_info, i2c_node);
- if (i2c_info->base == 0U) {
- return -FDT_ERR_NOTFOUND;
- }
-
- return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
-}
-
-int dt_pmic_configure_boot_on_regulators(void)
-{
- int pmic_node, regulators_node, regulator_node;
+ static int i2c_node = -FDT_ERR_NOTFOUND;
void *fdt;
if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
- }
-
- pmic_node = dt_get_pmic_node(fdt);
- if (pmic_node < 0) {
return -FDT_ERR_NOTFOUND;
}
- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
-
- fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
+ if (i2c_node == -FDT_ERR_NOTFOUND) {
+ int pmic_node;
const fdt32_t *cuint;
- const char *node_name = fdt_get_name(fdt, regulator_node, NULL);
- uint16_t voltage;
- int status;
-
-#if defined(IMAGE_BL2)
- if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on",
- NULL) == NULL) &&
- (fdt_getprop(fdt, regulator_node, "regulator-always-on",
- NULL) == NULL)) {
-#else
- if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
- NULL) == NULL) {
-#endif
- continue;
- }
-
- if (fdt_getprop(fdt, regulator_node, "regulator-pull-down",
- NULL) != NULL) {
- status = stpmic1_regulator_pull_down_set(node_name);
- if (status != 0) {
- return status;
- }
- }
-
- if (fdt_getprop(fdt, regulator_node, "st,mask-reset",
- NULL) != NULL) {
-
- status = stpmic1_regulator_mask_reset_set(node_name);
- if (status != 0) {
- return status;
- }
+ pmic_node = dt_get_pmic_node(fdt);
+ if (pmic_node < 0) {
+ return PMIC_NODE_NOT_FOUND;
}
- cuint = fdt_getprop(fdt, regulator_node,
- "regulator-min-microvolt", NULL);
+ cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
if (cuint == NULL) {
- continue;
+ return -FDT_ERR_NOTFOUND;
}
- /* DT uses microvolts, whereas driver awaits millivolts */
- voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
-
- status = stpmic1_regulator_voltage_set(node_name, voltage);
- if (status != 0) {
- return status;
+ pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
+ if (pmic_i2c_addr > UINT16_MAX) {
+ return -FDT_ERR_BADVALUE;
}
- if (stpmic1_is_regulator_enabled(node_name) == 0U) {
- status = stpmic1_regulator_enable(node_name);
- if (status != 0) {
- return status;
- }
+ i2c_node = fdt_parent_offset(fdt, pmic_node);
+ if (i2c_node < 0) {
+ return -FDT_ERR_NOTFOUND;
}
}
- return 0;
+ dt_fill_device_info(i2c_info, i2c_node);
+ if (i2c_info->base == 0U) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
}
bool initialize_pmic_i2c(void)
@@ -204,6 +141,7 @@ bool initialize_pmic_i2c(void)
i2c->i2c_base_addr = i2c_info.base;
i2c->dt_status = i2c_info.status;
i2c->clock = i2c_info.clock;
+ i2c->i2c_state = I2C_STATE_RESET;
i2c_init.own_address1 = pmic_i2c_addr;
i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT;
i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE;
@@ -247,8 +185,6 @@ static void register_pmic_shared_peripherals(void)
void initialize_pmic(void)
{
- unsigned long pmic_version;
-
if (!initialize_pmic_i2c()) {
VERBOSE("No PMIC\n");
return;
@@ -256,70 +192,84 @@ void initialize_pmic(void)
register_pmic_shared_peripherals();
+ if (register_pmic() < 0) {
+ panic();
+ }
+
+ if (stpmic1_powerctrl_on() < 0) {
+ panic();
+ }
+
+}
+
+#if DEBUG
+void print_pmic_info_and_debug(void)
+{
+ unsigned long pmic_version;
+
if (stpmic1_get_version(&pmic_version) != 0) {
ERROR("Failed to access PMIC\n");
panic();
}
INFO("PMIC version = 0x%02lx\n", pmic_version);
- stpmic1_dump_regulators();
-
-#if defined(IMAGE_BL2)
- if (dt_pmic_configure_boot_on_regulators() != 0) {
- panic();
- };
-#endif
}
+#endif
int pmic_ddr_power_init(enum ddr_type ddr_type)
{
- bool buck3_at_1v8 = false;
- uint8_t read_val;
int status;
+ uint16_t buck3_min_mv;
+ struct rdev *buck2, *buck3, *vref;
+ struct rdev *ldo3 __unused;
- switch (ddr_type) {
- case STM32MP_DDR3:
- /* Set LDO3 to sync mode */
- status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
- if (status != 0) {
- return status;
- }
+ buck2 = regulator_get_by_name("buck2");
+ if (buck2 == NULL) {
+ return -ENOENT;
+ }
- read_val &= ~STPMIC1_LDO3_MODE;
- read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
- read_val |= STPMIC1_LDO3_DDR_SEL <<
- STPMIC1_LDO12356_OUTPUT_SHIFT;
+#if STM32MP15
+ ldo3 = regulator_get_by_name("ldo3");
+ if (ldo3 == NULL) {
+ return -ENOENT;
+ }
+#endif
+
+ vref = regulator_get_by_name("vref_ddr");
+ if (vref == NULL) {
+ return -ENOENT;
+ }
- status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
+ switch (ddr_type) {
+ case STM32MP_DDR3:
+#if STM32MP15
+ status = regulator_set_flag(ldo3, REGUL_SINK_SOURCE);
if (status != 0) {
return status;
}
+#endif
- status = stpmic1_regulator_voltage_set("buck2", 1350);
+ status = regulator_set_min_voltage(buck2);
if (status != 0) {
return status;
}
- status = stpmic1_regulator_enable("buck2");
+ status = regulator_enable(buck2);
if (status != 0) {
return status;
}
- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
- status = stpmic1_regulator_enable("vref_ddr");
+ status = regulator_enable(vref);
if (status != 0) {
return status;
}
- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
-
- status = stpmic1_regulator_enable("ldo3");
+#if STM32MP15
+ status = regulator_enable(ldo3);
if (status != 0) {
return status;
}
-
- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+#endif
break;
case STM32MP_LPDDR2:
@@ -329,62 +279,247 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
* Set LDO3 to bypass mode if BUCK3 = 1.8V
* Set LDO3 to normal mode if BUCK3 != 1.8V
*/
- status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val);
- if (status != 0) {
- return status;
+ buck3 = regulator_get_by_name("buck3");
+ if (buck3 == NULL) {
+ return -ENOENT;
}
- if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) {
- buck3_at_1v8 = true;
+ regulator_get_range(buck3, &buck3_min_mv, NULL);
+
+#if STM32MP15
+ if (buck3_min_mv != 1800) {
+ status = regulator_set_min_voltage(ldo3);
+ if (status != 0) {
+ return status;
+ }
+ } else {
+ status = regulator_set_flag(ldo3, REGUL_ENABLE_BYPASS);
+ if (status != 0) {
+ return status;
+ }
}
+#endif
- status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
+ status = regulator_set_min_voltage(buck2);
if (status != 0) {
return status;
}
- read_val &= ~STPMIC1_LDO3_MODE;
- read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
- read_val |= STPMIC1_LDO3_1800000;
- if (buck3_at_1v8) {
- read_val |= STPMIC1_LDO3_MODE;
- }
-
- status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
+#if STM32MP15
+ status = regulator_enable(ldo3);
if (status != 0) {
return status;
}
+#endif
- status = stpmic1_regulator_voltage_set("buck2", 1200);
+ status = regulator_enable(buck2);
if (status != 0) {
return status;
}
- status = stpmic1_regulator_enable("ldo3");
+ status = regulator_enable(vref);
if (status != 0) {
return status;
}
+ break;
- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+ default:
+ break;
+ };
- status = stpmic1_regulator_enable("buck2");
- if (status != 0) {
- return status;
- }
+ return 0;
+}
- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+int pmic_voltages_init(void)
+{
+#if STM32MP13
+ struct rdev *buck1, *buck4;
+ int status;
- status = stpmic1_regulator_enable("vref_ddr");
- if (status != 0) {
- return status;
- }
+ buck1 = regulator_get_by_name("buck1");
+ if (buck1 == NULL) {
+ return -ENOENT;
+ }
- mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
- break;
+ buck4 = regulator_get_by_name("buck4");
+ if (buck4 == NULL) {
+ return -ENOENT;
+ }
+
+ status = regulator_set_min_voltage(buck1);
+ if (status != 0) {
+ return status;
+ }
+
+ status = regulator_set_min_voltage(buck4);
+ if (status != 0) {
+ return status;
+ }
+#endif
+
+ return 0;
+}
+
+enum {
+ STPMIC1_BUCK1 = 0,
+ STPMIC1_BUCK2,
+ STPMIC1_BUCK3,
+ STPMIC1_BUCK4,
+ STPMIC1_LDO1,
+ STPMIC1_LDO2,
+ STPMIC1_LDO3,
+ STPMIC1_LDO4,
+ STPMIC1_LDO5,
+ STPMIC1_LDO6,
+ STPMIC1_VREF_DDR,
+ STPMIC1_BOOST,
+ STPMIC1_VBUS_OTG,
+ STPMIC1_SW_OUT,
+};
+
+static int pmic_set_state(const struct regul_description *desc, bool enable)
+{
+ VERBOSE("%s: set state to %d\n", desc->node_name, enable);
+
+ if (enable == STATE_ENABLE) {
+ return stpmic1_regulator_enable(desc->node_name);
+ } else {
+ return stpmic1_regulator_disable(desc->node_name);
+ }
+}
+
+static int pmic_get_state(const struct regul_description *desc)
+{
+ VERBOSE("%s: get state\n", desc->node_name);
+
+ return stpmic1_is_regulator_enabled(desc->node_name);
+}
+
+static int pmic_get_voltage(const struct regul_description *desc)
+{
+ VERBOSE("%s: get volt\n", desc->node_name);
+
+ return stpmic1_regulator_voltage_get(desc->node_name);
+}
+
+static int pmic_set_voltage(const struct regul_description *desc, uint16_t mv)
+{
+ VERBOSE("%s: get volt\n", desc->node_name);
+
+ return stpmic1_regulator_voltage_set(desc->node_name, mv);
+}
+
+static int pmic_list_voltages(const struct regul_description *desc,
+ const uint16_t **levels, size_t *count)
+{
+ VERBOSE("%s: list volt\n", desc->node_name);
+
+ return stpmic1_regulator_levels_mv(desc->node_name, levels, count);
+}
+
+static int pmic_set_flag(const struct regul_description *desc, uint16_t flag)
+{
+ VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag);
+
+ switch (flag) {
+ case REGUL_OCP:
+ return stpmic1_regulator_icc_set(desc->node_name);
+
+ case REGUL_ACTIVE_DISCHARGE:
+ return stpmic1_active_discharge_mode_set(desc->node_name);
+
+ case REGUL_PULL_DOWN:
+ return stpmic1_regulator_pull_down_set(desc->node_name);
+
+ case REGUL_MASK_RESET:
+ return stpmic1_regulator_mask_reset_set(desc->node_name);
+
+ case REGUL_SINK_SOURCE:
+ return stpmic1_regulator_sink_mode_set(desc->node_name);
+
+ case REGUL_ENABLE_BYPASS:
+ return stpmic1_regulator_bypass_mode_set(desc->node_name);
default:
- break;
- };
+ return -EINVAL;
+ }
+}
+
+static const struct regul_ops pmic_ops = {
+ .set_state = pmic_set_state,
+ .get_state = pmic_get_state,
+ .set_voltage = pmic_set_voltage,
+ .get_voltage = pmic_get_voltage,
+ .list_voltages = pmic_list_voltages,
+ .set_flag = pmic_set_flag,
+};
+
+#define DEFINE_REGU(name) { \
+ .node_name = (name), \
+ .ops = &pmic_ops, \
+ .driver_data = NULL, \
+ .enable_ramp_delay = 1000, \
+}
+
+static const struct regul_description pmic_regs[NB_REG] = {
+ [STPMIC1_BUCK1] = DEFINE_REGU("buck1"),
+ [STPMIC1_BUCK2] = DEFINE_REGU("buck2"),
+ [STPMIC1_BUCK3] = DEFINE_REGU("buck3"),
+ [STPMIC1_BUCK4] = DEFINE_REGU("buck4"),
+ [STPMIC1_LDO1] = DEFINE_REGU("ldo1"),
+ [STPMIC1_LDO2] = DEFINE_REGU("ldo2"),
+ [STPMIC1_LDO3] = DEFINE_REGU("ldo3"),
+ [STPMIC1_LDO4] = DEFINE_REGU("ldo4"),
+ [STPMIC1_LDO5] = DEFINE_REGU("ldo5"),
+ [STPMIC1_LDO6] = DEFINE_REGU("ldo6"),
+ [STPMIC1_VREF_DDR] = DEFINE_REGU("vref_ddr"),
+ [STPMIC1_BOOST] = DEFINE_REGU("boost"),
+ [STPMIC1_VBUS_OTG] = DEFINE_REGU("pwr_sw1"),
+ [STPMIC1_SW_OUT] = DEFINE_REGU("pwr_sw2"),
+};
+
+static int register_pmic(void)
+{
+ void *fdt;
+ int pmic_node, regulators_node, subnode;
+
+ VERBOSE("Register pmic\n");
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ pmic_node = dt_get_pmic_node(fdt);
+ if (pmic_node < 0) {
+ return pmic_node;
+ }
+
+ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+ if (regulators_node < 0) {
+ return -ENOENT;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, regulators_node) {
+ const char *reg_name = fdt_get_name(fdt, subnode, NULL);
+ const struct regul_description *desc;
+ unsigned int i;
+ int ret;
+
+ for (i = 0U; i < NB_REG; i++) {
+ desc = &pmic_regs[i];
+ if (strcmp(desc->node_name, reg_name) == 0) {
+ break;
+ }
+ }
+ assert(i < NB_REG);
+
+ ret = regulator_register(desc, subnode);
+ if (ret != 0) {
+ WARN("%s:%d failed to register %s\n", __func__,
+ __LINE__, reg_name);
+ return ret;
+ }
+ }
return 0;
}
diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c
index 9999630545..37eb50bbce 100644
--- a/drivers/st/pmic/stpmic1.c
+++ b/drivers/st/pmic/stpmic1.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <errno.h>
#include <string.h>
#include <common/debug.h>
@@ -16,15 +17,23 @@ struct regul_struct {
const uint16_t *voltage_table;
uint8_t voltage_table_size;
uint8_t control_reg;
+ uint8_t enable_mask;
uint8_t low_power_reg;
uint8_t pull_down_reg;
uint8_t pull_down;
uint8_t mask_reset_reg;
uint8_t mask_reset;
+ uint8_t icc_reg;
+ uint8_t icc_mask;
};
static struct i2c_handle_s *pmic_i2c_handle;
static uint16_t pmic_i2c_addr;
+/*
+ * Special mode corresponds to LDO3 in sink source mode or in bypass mode.
+ * LDO3 doesn't switch back from special to normal mode.
+ */
+static bool ldo3_special_mode;
/* Voltage tables in mV */
static const uint16_t buck1_voltage_table[] = {
@@ -345,8 +354,11 @@ static const uint16_t ldo3_voltage_table[] = {
3300,
3300,
3300,
- 500,
- 0xFFFF, /* VREFDDR */
+};
+
+/* Special mode table is used for sink source OR bypass mode */
+static const uint16_t ldo3_special_mode_table[] = {
+ 0,
};
static const uint16_t ldo5_voltage_table[] = {
@@ -419,6 +431,10 @@ static const uint16_t vref_ddr_voltage_table[] = {
3300,
};
+static const uint16_t fixed_5v_voltage_table[] = {
+ 5000,
+};
+
/* Table of Regulators in PMIC SoC */
static const struct regul_struct regulators_table[] = {
{
@@ -426,108 +442,166 @@ static const struct regul_struct regulators_table[] = {
.voltage_table = buck1_voltage_table,
.voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
.control_reg = BUCK1_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = BUCK1_PWRCTRL_REG,
.pull_down_reg = BUCK_PULL_DOWN_REG,
.pull_down = BUCK1_PULL_DOWN_SHIFT,
.mask_reset_reg = MASK_RESET_BUCK_REG,
.mask_reset = BUCK1_MASK_RESET,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK1_ICC_SHIFT,
},
{
.dt_node_name = "buck2",
.voltage_table = buck2_voltage_table,
.voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
.control_reg = BUCK2_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = BUCK2_PWRCTRL_REG,
.pull_down_reg = BUCK_PULL_DOWN_REG,
.pull_down = BUCK2_PULL_DOWN_SHIFT,
.mask_reset_reg = MASK_RESET_BUCK_REG,
.mask_reset = BUCK2_MASK_RESET,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK2_ICC_SHIFT,
},
{
.dt_node_name = "buck3",
.voltage_table = buck3_voltage_table,
.voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
.control_reg = BUCK3_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = BUCK3_PWRCTRL_REG,
.pull_down_reg = BUCK_PULL_DOWN_REG,
.pull_down = BUCK3_PULL_DOWN_SHIFT,
.mask_reset_reg = MASK_RESET_BUCK_REG,
.mask_reset = BUCK3_MASK_RESET,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK3_ICC_SHIFT,
},
{
.dt_node_name = "buck4",
.voltage_table = buck4_voltage_table,
.voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
.control_reg = BUCK4_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = BUCK4_PWRCTRL_REG,
.pull_down_reg = BUCK_PULL_DOWN_REG,
.pull_down = BUCK4_PULL_DOWN_SHIFT,
.mask_reset_reg = MASK_RESET_BUCK_REG,
.mask_reset = BUCK4_MASK_RESET,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BUCK4_ICC_SHIFT,
},
{
.dt_node_name = "ldo1",
.voltage_table = ldo1_voltage_table,
.voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
.control_reg = LDO1_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = LDO1_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = LDO1_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO1_ICC_SHIFT,
},
{
.dt_node_name = "ldo2",
.voltage_table = ldo2_voltage_table,
.voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
.control_reg = LDO2_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = LDO2_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = LDO2_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO2_ICC_SHIFT,
},
{
.dt_node_name = "ldo3",
.voltage_table = ldo3_voltage_table,
.voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
.control_reg = LDO3_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = LDO3_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = LDO3_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO3_ICC_SHIFT,
},
{
.dt_node_name = "ldo4",
.voltage_table = ldo4_voltage_table,
.voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
.control_reg = LDO4_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = LDO4_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = LDO4_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO4_ICC_SHIFT,
},
{
.dt_node_name = "ldo5",
.voltage_table = ldo5_voltage_table,
.voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
.control_reg = LDO5_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = LDO5_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = LDO5_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO5_ICC_SHIFT,
},
{
.dt_node_name = "ldo6",
.voltage_table = ldo6_voltage_table,
.voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
.control_reg = LDO6_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = LDO6_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = LDO6_MASK_RESET,
+ .icc_reg = LDO_ICC_TURNOFF_REG,
+ .icc_mask = LDO6_ICC_SHIFT,
},
{
.dt_node_name = "vref_ddr",
.voltage_table = vref_ddr_voltage_table,
.voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
.control_reg = VREF_DDR_CONTROL_REG,
+ .enable_mask = LDO_BUCK_ENABLE_MASK,
.low_power_reg = VREF_DDR_PWRCTRL_REG,
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = VREF_DDR_MASK_RESET,
},
+ {
+ .dt_node_name = "boost",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .enable_mask = BOOST_ENABLED,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = BOOST_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "pwr_sw1",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .enable_mask = USBSW_OTG_SWITCH_ENABLED,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = PWR_SW1_ICC_SHIFT,
+ },
+ {
+ .dt_node_name = "pwr_sw2",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .enable_mask = SWIN_SWOUT_ENABLED,
+ .icc_reg = BUCK_ICC_TURNOFF_REG,
+ .icc_mask = PWR_SW2_ICC_SHIFT,
+ },
};
#define MAX_REGUL ARRAY_SIZE(regulators_table)
@@ -581,17 +655,19 @@ int stpmic1_regulator_enable(const char *name)
{
const struct regul_struct *regul = get_regulator_data(name);
- return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0));
+ return stpmic1_register_update(regul->control_reg, regul->enable_mask,
+ regul->enable_mask);
}
int stpmic1_regulator_disable(const char *name)
{
const struct regul_struct *regul = get_regulator_data(name);
- return stpmic1_register_update(regul->control_reg, 0, BIT(0));
+ return stpmic1_register_update(regul->control_reg, 0,
+ regul->enable_mask);
}
-uint8_t stpmic1_is_regulator_enabled(const char *name)
+bool stpmic1_is_regulator_enabled(const char *name)
{
uint8_t val;
const struct regul_struct *regul = get_regulator_data(name);
@@ -600,7 +676,7 @@ uint8_t stpmic1_is_regulator_enabled(const char *name)
panic();
}
- return (val & 0x1U);
+ return (val & regul->enable_mask) == regul->enable_mask;
}
int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
@@ -609,11 +685,21 @@ int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
const struct regul_struct *regul = get_regulator_data(name);
uint8_t mask;
+ if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
+ /*
+ * when the LDO3 is in special mode, we do not change voltage,
+ * because by setting voltage, the LDO would leaves sink-source
+ * mode. There is obviously no reason to leave sink-source mode
+ * at runtime.
+ */
+ return 0;
+ }
+
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
if (strncmp(name, "buck", 4) == 0) {
mask = BUCK_VOLTAGE_MASK;
} else if ((strncmp(name, "ldo", 3) == 0) &&
- (strncmp(name, "ldo4", 4) != 0)) {
+ (strncmp(name, "ldo4", 5) != 0)) {
mask = LDO_VOLTAGE_MASK;
} else {
return 0;
@@ -642,35 +728,121 @@ int stpmic1_regulator_mask_reset_set(const char *name)
{
const struct regul_struct *regul = get_regulator_data(name);
+ if (regul->mask_reset_reg == 0U) {
+ return -EPERM;
+ }
+
return stpmic1_register_update(regul->mask_reset_reg,
BIT(regul->mask_reset),
LDO_BUCK_RESET_MASK <<
regul->mask_reset);
}
+int stpmic1_regulator_icc_set(const char *name)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+
+ if (regul->mask_reset_reg == 0U) {
+ return -EPERM;
+ }
+
+ return stpmic1_register_update(regul->icc_reg,
+ BIT(regul->icc_mask),
+ BIT(regul->icc_mask));
+}
+
+int stpmic1_regulator_sink_mode_set(const char *name)
+{
+ if (strncmp(name, "ldo3", 5) != 0) {
+ return -EPERM;
+ }
+
+ ldo3_special_mode = true;
+
+ /* disable bypass mode, enable sink mode */
+ return stpmic1_register_update(LDO3_CONTROL_REG,
+ LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT,
+ LDO3_BYPASS | LDO_VOLTAGE_MASK);
+}
+
+int stpmic1_regulator_bypass_mode_set(const char *name)
+{
+ if (strncmp(name, "ldo3", 5) != 0) {
+ return -EPERM;
+ }
+
+ ldo3_special_mode = true;
+
+ /* enable bypass mode, disable sink mode */
+ return stpmic1_register_update(LDO3_CONTROL_REG,
+ LDO3_BYPASS,
+ LDO3_BYPASS | LDO_VOLTAGE_MASK);
+}
+
+int stpmic1_active_discharge_mode_set(const char *name)
+{
+ if (strncmp(name, "pwr_sw1", 8) == 0) {
+ return stpmic1_register_update(USB_CONTROL_REG,
+ VBUS_OTG_DISCHARGE,
+ VBUS_OTG_DISCHARGE);
+ }
+
+ if (strncmp(name, "pwr_sw2", 8) == 0) {
+ return stpmic1_register_update(USB_CONTROL_REG,
+ SW_OUT_DISCHARGE,
+ SW_OUT_DISCHARGE);
+ }
+
+ return -EPERM;
+}
+
+int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
+ size_t *levels_count)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+
+ if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
+ *levels_count = ARRAY_SIZE(ldo3_special_mode_table);
+ *levels = ldo3_special_mode_table;
+ } else {
+ *levels_count = regul->voltage_table_size;
+ *levels = regul->voltage_table;
+ }
+
+ return 0;
+}
+
int stpmic1_regulator_voltage_get(const char *name)
{
const struct regul_struct *regul = get_regulator_data(name);
uint8_t value;
uint8_t mask;
+ int status;
+
+ if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
+ return 0;
+ }
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
if (strncmp(name, "buck", 4) == 0) {
mask = BUCK_VOLTAGE_MASK;
} else if ((strncmp(name, "ldo", 3) == 0) &&
- (strncmp(name, "ldo4", 4) != 0)) {
+ (strncmp(name, "ldo4", 5) != 0)) {
mask = LDO_VOLTAGE_MASK;
} else {
return 0;
}
- if (stpmic1_register_read(regul->control_reg, &value))
- return -1;
+ status = stpmic1_register_read(regul->control_reg, &value);
+ if (status < 0) {
+ return status;
+ }
value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
- if (value > regul->voltage_table_size)
- return -1;
+ if (value > regul->voltage_table_size) {
+ return -ERANGE;
+ }
return (int)regul->voltage_table[value];
}
@@ -706,7 +878,7 @@ int stpmic1_register_write(uint8_t register_id, uint8_t value)
}
if (readval != value) {
- return -1;
+ return -EIO;
}
}
#endif
@@ -751,12 +923,12 @@ void stpmic1_dump_regulators(void)
int stpmic1_get_version(unsigned long *version)
{
- int rc;
uint8_t read_val;
+ int status;
- rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
- if (rc) {
- return -1;
+ status = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
+ if (status < 0) {
+ return status;
}
*version = (unsigned long)read_val;
diff --git a/drivers/st/regulator/regulator_core.c b/drivers/st/regulator/regulator_core.c
new file mode 100644
index 0000000000..2a5d0f7aea
--- /dev/null
+++ b/drivers/st/regulator/regulator_core.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/regulator.h>
+#include <libfdt.h>
+
+#define MAX_PROPERTY_LEN 64
+
+CASSERT(PLAT_NB_RDEVS >= 1U, plat_nb_rdevs_must_be_higher);
+
+static struct rdev rdev_array[PLAT_NB_RDEVS];
+
+#define for_each_rdev(rdev) \
+ for ((rdev) = rdev_array; (rdev) <= &rdev_array[PLAT_NB_RDEVS - 1U]; (rdev)++)
+
+#define for_each_registered_rdev(rdev) \
+ for ((rdev) = rdev_array; \
+ ((rdev) <= &rdev_array[PLAT_NB_RDEVS - 1U]) && ((rdev)->desc != NULL); (rdev)++)
+
+static void lock_driver(const struct rdev *rdev)
+{
+ if (rdev->desc->ops->lock != NULL) {
+ rdev->desc->ops->lock(rdev->desc);
+ }
+}
+
+static void unlock_driver(const struct rdev *rdev)
+{
+ if (rdev->desc->ops->unlock != NULL) {
+ rdev->desc->ops->unlock(rdev->desc);
+ }
+}
+
+static struct rdev *regulator_get_by_phandle(int32_t phandle)
+{
+ struct rdev *rdev;
+
+ for_each_registered_rdev(rdev) {
+ if (rdev->phandle == phandle) {
+ return rdev;
+ }
+ }
+
+ WARN("%s: phandle %d not found\n", __func__, phandle);
+ return NULL;
+}
+
+/*
+ * Get a regulator from its node name
+ *
+ * @fdt - pointer to device tree memory
+ * @node_name - name of the node "ldo1"
+ * Return pointer to rdev if succeed, NULL else.
+ */
+struct rdev *regulator_get_by_name(const char *node_name)
+{
+ struct rdev *rdev;
+
+ assert(node_name != NULL);
+ VERBOSE("get %s\n", node_name);
+
+ for_each_registered_rdev(rdev) {
+ if (strcmp(rdev->desc->node_name, node_name) == 0) {
+ return rdev;
+ }
+ }
+
+ WARN("%s: %s not found\n", __func__, node_name);
+ return NULL;
+}
+
+static int32_t get_supply_phandle(const void *fdt, int node, const char *name)
+{
+ const fdt32_t *cuint;
+ int len __unused;
+ int supply_phandle = -FDT_ERR_NOTFOUND;
+ char prop_name[MAX_PROPERTY_LEN];
+
+ len = snprintf(prop_name, MAX_PROPERTY_LEN - 1, "%s-supply", name);
+ assert((len >= 0) && (len < (MAX_PROPERTY_LEN - 1)));
+
+ cuint = fdt_getprop(fdt, node, prop_name, NULL);
+ if (cuint != NULL) {
+ supply_phandle = fdt32_to_cpu(*cuint);
+ VERBOSE("%s: supplied by %d\n", name, supply_phandle);
+ }
+
+ return supply_phandle;
+}
+
+/*
+ * Get a regulator from a supply name
+ *
+ * @fdt - pointer to device tree memory
+ * @node - offset of the node that contains the supply description
+ * @name - name of the supply "vdd" for "vdd-supply'
+ * Return pointer to rdev if succeed, NULL else.
+ */
+struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name)
+{
+ const int p = get_supply_phandle(fdt, node, name);
+
+ if (p < 0) {
+ return NULL;
+ }
+
+ return regulator_get_by_phandle(p);
+}
+
+static int __regulator_set_state(struct rdev *rdev, bool state)
+{
+ if (rdev->desc->ops->set_state == NULL) {
+ return -ENODEV;
+ }
+
+ return rdev->desc->ops->set_state(rdev->desc, state);
+}
+
+/*
+ * Enable regulator
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_enable(struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ ret = __regulator_set_state(rdev, STATE_ENABLE);
+
+ udelay(rdev->enable_ramp_delay);
+
+ return ret;
+}
+
+/*
+ * Disable regulator
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_disable(struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ if ((rdev->flags & REGUL_ALWAYS_ON) != 0U) {
+ return 0;
+ }
+
+ ret = __regulator_set_state(rdev, STATE_DISABLE);
+
+ udelay(rdev->enable_ramp_delay);
+
+ return ret;
+}
+
+/*
+ * Regulator enabled query
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if disabled, 1 if enabled, <0 else.
+ */
+int regulator_is_enabled(const struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ VERBOSE("%s: is en\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->get_state == NULL) {
+ return -ENODEV;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->get_state(rdev->desc);
+ if (ret < 0) {
+ ERROR("regul %s get state failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ }
+
+ unlock_driver(rdev);
+
+ return ret;
+}
+
+/*
+ * Set regulator voltage
+ *
+ * @rdev - pointer to rdev struct
+ * @mvolt - Target voltage level in millivolt
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_set_voltage(struct rdev *rdev, uint16_t mvolt)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ VERBOSE("%s: set mvolt\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->set_voltage == NULL) {
+ return -ENODEV;
+ }
+
+ if ((mvolt < rdev->min_mv) || (mvolt > rdev->max_mv)) {
+ return -EPERM;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->set_voltage(rdev->desc, mvolt);
+ if (ret < 0) {
+ ERROR("regul %s set volt failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ }
+
+ unlock_driver(rdev);
+
+ return ret;
+}
+
+/*
+ * Set regulator min voltage
+ *
+ * @rdev - pointer to rdev struct
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_set_min_voltage(struct rdev *rdev)
+{
+ return regulator_set_voltage(rdev, rdev->min_mv);
+}
+
+/*
+ * Get regulator voltage
+ *
+ * @rdev - pointer to rdev struct
+ * Return milli volts if succeed, <0 else.
+ */
+int regulator_get_voltage(const struct rdev *rdev)
+{
+ int ret;
+
+ assert(rdev != NULL);
+
+ VERBOSE("%s: get volt\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->get_voltage == NULL) {
+ return rdev->min_mv;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->get_voltage(rdev->desc);
+ if (ret < 0) {
+ ERROR("regul %s get voltage failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ }
+
+ unlock_driver(rdev);
+
+ return ret;
+}
+
+/*
+ * List regulator voltages
+ *
+ * @rdev - pointer to rdev struct
+ * @levels - out: array of supported millitvolt levels from min to max value
+ * @count - out: number of possible millivolt values
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count)
+{
+ int ret;
+ size_t n;
+
+ assert(rdev != NULL);
+ assert(levels != NULL);
+ assert(count != NULL);
+
+ VERBOSE("%s: list volt\n", rdev->desc->node_name);
+
+ if (rdev->desc->ops->list_voltages == NULL) {
+ return -ENODEV;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->list_voltages(rdev->desc, levels, count);
+
+ unlock_driver(rdev);
+
+ if (ret < 0) {
+ ERROR("regul %s list_voltages failed: err: %d\n",
+ rdev->desc->node_name, ret);
+ return ret;
+ }
+
+ /*
+ * Reduce the possible values depending on min and max from device-tree
+ */
+ n = *count;
+ while ((n > 1U) && ((*levels)[n - 1U] > rdev->max_mv)) {
+ n--;
+ }
+
+ /* Verify that max val is a valid value */
+ if (rdev->max_mv != (*levels)[n - 1]) {
+ ERROR("regul %s: max value %u is invalid\n",
+ rdev->desc->node_name, rdev->max_mv);
+ return -EINVAL;
+ }
+
+ while ((n > 1U) && ((*levels[0U]) < rdev->min_mv)) {
+ (*levels)++;
+ n--;
+ }
+
+ /* Verify that min is not too high */
+ if (n == 0U) {
+ ERROR("regul %s set min voltage is too high\n",
+ rdev->desc->node_name);
+ return -EINVAL;
+ }
+
+ /* Verify that min val is a valid vlue */
+ if (rdev->min_mv != (*levels)[0U]) {
+ ERROR("regul %s: min value %u is invalid\n",
+ rdev->desc->node_name, rdev->min_mv);
+ return -EINVAL;
+ }
+
+ *count = n;
+
+ VERBOSE("rdev->min_mv=%u rdev->max_mv=%u\n", rdev->min_mv, rdev->max_mv);
+
+ return 0;
+}
+
+/*
+ * Get regulator voltages range
+ *
+ * @rdev - pointer to rdev struct
+ * @min_mv - out: min possible millivolt value
+ * @max_mv - out: max possible millivolt value
+ * Return 0 if succeed, non 0 else.
+ */
+void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv)
+{
+ assert(rdev != NULL);
+
+ if (min_mv != NULL) {
+ *min_mv = rdev->min_mv;
+ }
+ if (max_mv != NULL) {
+ *max_mv = rdev->max_mv;
+ }
+}
+
+/*
+ * Set regulator flag
+ *
+ * @rdev - pointer to rdev struct
+ * @flag - flag value to set (eg: REGUL_OCP)
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_set_flag(struct rdev *rdev, uint16_t flag)
+{
+ int ret;
+
+ /* check that only one bit is set on flag */
+ if (__builtin_popcount(flag) != 1) {
+ return -EINVAL;
+ }
+
+ /* REGUL_ALWAYS_ON and REGUL_BOOT_ON are internal properties of the core */
+ if ((flag == REGUL_ALWAYS_ON) || (flag == REGUL_BOOT_ON)) {
+ rdev->flags |= flag;
+ return 0;
+ }
+
+ if (rdev->desc->ops->set_flag == NULL) {
+ ERROR("%s can not set any flag\n", rdev->desc->node_name);
+ return -ENODEV;
+ }
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->set_flag(rdev->desc, flag);
+
+ unlock_driver(rdev);
+
+ if (ret != 0) {
+ ERROR("%s: could not set flag %d ret=%d\n",
+ rdev->desc->node_name, flag, ret);
+ return ret;
+ }
+
+ rdev->flags |= flag;
+
+ return 0;
+}
+
+static int parse_properties(const void *fdt, struct rdev *rdev, int node)
+{
+ int ret;
+
+ if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL) {
+ VERBOSE("%s: set regulator-always-on\n", rdev->desc->node_name);
+ ret = regulator_set_flag(rdev, REGUL_ALWAYS_ON);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Parse the device-tree for a regulator
+ *
+ * Read min/max voltage from dt and check its validity
+ * Read the properties, and call the driver to set flags
+ * Read power supply phandle
+ * Read and store low power mode states
+ *
+ * @rdev - pointer to rdev struct
+ * @node - device-tree node offset of the regulator
+ * Return 0 if disabled, 1 if enabled, <0 else.
+ */
+static int parse_dt(struct rdev *rdev, int node)
+{
+ void *fdt;
+ const fdt32_t *cuint;
+ const uint16_t *levels;
+ size_t size;
+ int ret;
+
+ VERBOSE("%s: parse dt\n", rdev->desc->node_name);
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ rdev->phandle = fdt_get_phandle(fdt, node);
+
+ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
+ if (cuint != NULL) {
+ uint16_t min_mv;
+
+ min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+ VERBOSE("%s: min_mv=%d\n", rdev->desc->node_name, (int)min_mv);
+ if (min_mv <= rdev->max_mv) {
+ rdev->min_mv = min_mv;
+ } else {
+ ERROR("%s: min_mv=%d is too high\n",
+ rdev->desc->node_name, (int)min_mv);
+ return -EINVAL;
+ }
+ }
+
+ cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
+ if (cuint != NULL) {
+ uint16_t max_mv;
+
+ max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+ VERBOSE("%s: max_mv=%d\n", rdev->desc->node_name, (int)max_mv);
+ if (max_mv >= rdev->min_mv) {
+ rdev->max_mv = max_mv;
+ } else {
+ ERROR("%s: max_mv=%d is too low\n",
+ rdev->desc->node_name, (int)max_mv);
+ return -EINVAL;
+ }
+ }
+
+ /* validate that min and max values can be used */
+ ret = regulator_list_voltages(rdev, &levels, &size);
+ if ((ret != 0) && (ret != -ENODEV)) {
+ return ret;
+ }
+
+ ret = parse_properties(fdt, rdev, node);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Register a regulator driver in regulator framework.
+ * Initialize voltage range from driver description
+ *
+ * @desc - pointer to the regulator description
+ * @node - device-tree node offset of the regulator
+ * Return 0 if succeed, non 0 else.
+ */
+int regulator_register(const struct regul_description *desc, int node)
+{
+ struct rdev *rdev;
+
+ assert(desc != NULL);
+
+ VERBOSE("register %s\n", desc->node_name);
+
+ for_each_rdev(rdev) {
+ if (rdev->desc == NULL) {
+ break;
+ }
+ }
+
+ if (rdev > &rdev_array[PLAT_NB_RDEVS - 1U]) {
+ WARN("Not enough place for regulators, PLAT_NB_RDEVS should be increased.\n");
+ return -ENOMEM;
+ }
+
+ rdev->desc = desc;
+ rdev->enable_ramp_delay = rdev->desc->enable_ramp_delay;
+
+ if (rdev->desc->ops->list_voltages != NULL) {
+ int ret;
+ const uint16_t *levels;
+ size_t count;
+
+ lock_driver(rdev);
+
+ ret = rdev->desc->ops->list_voltages(rdev->desc, &levels, &count);
+
+ unlock_driver(rdev);
+
+ if (ret < 0) {
+ ERROR("regul %s set state failed: err:%d\n",
+ rdev->desc->node_name, ret);
+ return ret;
+ }
+
+ rdev->min_mv = levels[0];
+ rdev->max_mv = levels[count - 1U];
+ } else {
+ rdev->max_mv = UINT16_MAX;
+ }
+
+ return parse_dt(rdev, node);
+}
diff --git a/drivers/st/regulator/regulator_fixed.c b/drivers/st/regulator/regulator_fixed.c
new file mode 100644
index 0000000000..6c9d3b17e1
--- /dev/null
+++ b/drivers/st/regulator/regulator_fixed.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2021-2023, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/st/regulator.h>
+#include <drivers/st/regulator_fixed.h>
+#include <libfdt.h>
+
+#ifndef PLAT_NB_FIXED_REGUS
+#error "Missing PLAT_NB_FIXED_REGUS"
+#endif
+
+#define FIXED_NAME_LEN 32
+
+struct fixed_data {
+ char name[FIXED_NAME_LEN];
+ uint16_t volt;
+ struct regul_description desc;
+};
+
+static struct fixed_data data[PLAT_NB_FIXED_REGUS];
+
+static int fixed_set_state(const struct regul_description *desc, bool state)
+{
+ return 0;
+}
+
+static int fixed_get_state(const struct regul_description *desc)
+{
+ return 1;
+}
+
+static struct regul_ops fixed_ops = {
+ .set_state = fixed_set_state,
+ .get_state = fixed_get_state,
+};
+
+int fixed_regulator_register(void)
+{
+ uint32_t count = 0;
+ void *fdt;
+ int node;
+
+ VERBOSE("fixed reg init!\n");
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fdt_for_each_compatible_node(fdt, node, "regulator-fixed") {
+ int len __unused;
+ int ret;
+ struct fixed_data *d = &data[count];
+ const char *reg_name;
+
+ reg_name = fdt_get_name(fdt, node, NULL);
+
+ VERBOSE("register fixed reg %s!\n", reg_name);
+
+ len = snprintf(d->name, FIXED_NAME_LEN - 1, "%s", reg_name);
+ assert((len > 0) && (len < (FIXED_NAME_LEN - 1)));
+
+ d->desc.node_name = d->name;
+ d->desc.driver_data = d;
+ d->desc.ops = &fixed_ops;
+
+ ret = regulator_register(&d->desc, node);
+ if (ret != 0) {
+ WARN("%s:%d failed to register %s\n", __func__,
+ __LINE__, reg_name);
+ return ret;
+ }
+
+ count++;
+ assert(count <= PLAT_NB_FIXED_REGUS);
+
+ }
+
+ return 0;
+}
diff --git a/drivers/st/spi/stm32_qspi.c b/drivers/st/spi/stm32_qspi.c
index d67f8313f3..73aa9ac60d 100644
--- a/drivers/st/spi/stm32_qspi.c
+++ b/drivers/st/spi/stm32_qspi.c
@@ -1,15 +1,14 @@
/*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
-#include <libfdt.h>
-
-#include <platform_def.h>
+#include <inttypes.h>
#include <common/debug.h>
#include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
#include <drivers/delay_timer.h>
#include <drivers/spi_mem.h>
#include <drivers/st/stm32_gpio.h>
@@ -17,6 +16,9 @@
#include <drivers/st/stm32mp_reset.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
/* Timeout for device interface reset */
#define TIMEOUT_US_1_MS 1000U
@@ -137,10 +139,6 @@ static int stm32_qspi_wait_cmd(const struct spi_mem_op *op)
int ret = 0;
uint64_t timeout;
- if (op->data.nbytes == 0U) {
- return stm32_qspi_wait_for_not_busy();
- }
-
timeout = timeout_init_us(QSPI_CMD_TIMEOUT_US);
while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TCF) == 0U) {
if (timeout_elapsed(timeout)) {
@@ -161,6 +159,10 @@ static int stm32_qspi_wait_cmd(const struct spi_mem_op *op)
/* Clear flags */
mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF | QSPI_FCR_CTEF);
+ if (ret == 0) {
+ ret = stm32_qspi_wait_for_not_busy();
+ }
+
return ret;
}
@@ -244,16 +246,11 @@ static int stm32_qspi_exec_op(const struct spi_mem_op *op)
uint8_t mode = QSPI_CCR_IND_WRITE;
int ret;
- VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addr:%llx len:%x\n",
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addr:%" PRIx64 " len:%x\n",
__func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
op->dummy.buswidth, op->data.buswidth,
op->addr.val, op->data.nbytes);
- ret = stm32_qspi_wait_for_not_busy();
- if (ret != 0) {
- return ret;
- }
-
addr_max = op->addr.val + op->data.nbytes + 1U;
if ((op->data.dir == SPI_MEM_DATA_IN) && (op->data.nbytes != 0U)) {
@@ -363,7 +360,7 @@ static void stm32_qspi_release_bus(void)
static int stm32_qspi_set_speed(unsigned int hz)
{
- unsigned long qspi_clk = stm32mp_clk_get_rate(stm32_qspi.clock_id);
+ unsigned long qspi_clk = clk_get_rate(stm32_qspi.clock_id);
uint32_t prescaler = UINT8_MAX;
uint32_t csht;
int ret;
@@ -493,7 +490,7 @@ int stm32_qspi_init(void)
stm32_qspi.clock_id = (unsigned long)info.clock;
stm32_qspi.reset_id = (unsigned int)info.reset;
- stm32mp_clk_enable(stm32_qspi.clock_id);
+ clk_enable(stm32_qspi.clock_id);
ret = stm32mp_reset_assert(stm32_qspi.reset_id, TIMEOUT_US_1_MS);
if (ret != 0) {
diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S
index 686b18b969..e063941d23 100644
--- a/drivers/st/uart/aarch32/stm32_console.S
+++ b/drivers/st/uart/aarch32/stm32_console.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -45,7 +45,18 @@ func console_stm32_core_init
/* Check the input base address */
cmp r0, #0
beq core_init_fail
-#if defined(IMAGE_BL2)
+#if !defined(IMAGE_BL2)
+#if STM32MP_RECONFIGURE_CONSOLE
+ /* UART clock rate is set to 0 in BL32, skip init in that case */
+ cmp r1, #0
+ beq 1f
+#else /* STM32MP_RECONFIGURE_CONSOLE */
+ /* Skip UART initialization if it is already enabled */
+ ldr r3, [r0, #USART_CR1]
+ ands r3, r3, #USART_CR1_UE
+ bne 1f
+#endif /* STM32MP_RECONFIGURE_CONSOLE */
+#endif /* IMAGE_BL2 */
/* Check baud rate and uart clock for sanity */
cmp r1, #0
beq core_init_fail
@@ -62,9 +73,24 @@ func console_stm32_core_init
bic r3, r3, #USART_CR2_STOP
str r3, [r0, #USART_CR2]
/* Divisor = (Uart clock + (baudrate / 2)) / baudrate */
- lsl r3, r2, #1
+ lsr r3, r2, #1
add r3, r1, r3
udiv r3, r3, r2
+ cmp r3, #16
+ bhi 2f
+ /* Oversampling 8 */
+ /* Divisor = (2 * Uart clock + (baudrate / 2)) / baudrate */
+ lsr r3, r2, #1
+ add r3, r3, r1, lsl #1
+ udiv r3, r3, r2
+ and r1, r3, #USART_BRR_DIV_FRACTION
+ lsr r1, r1, #1
+ bic r3, r3, #USART_BRR_DIV_FRACTION
+ orr r3, r3, r1
+ ldr r1, [r0, #USART_CR1]
+ orr r1, r1, #USART_CR1_OVER8
+ str r1, [r0, #USART_CR1]
+2:
str r3, [r0, #USART_BRR]
/* Enable UART */
ldr r3, [r0, #USART_CR1]
@@ -78,7 +104,7 @@ teack_loop:
ldr r3, [r0, #USART_ISR]
tst r3, #USART_ISR_TEACK
beq teack_loop
-#endif /* IMAGE_BL2 */
+1:
mov r0, #1
bx lr
core_init_fail:
@@ -208,11 +234,16 @@ func console_stm32_core_flush
cmp r0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
+ /* Skip flush if UART is not enabled */
+ ldr r1, [r0, #USART_CR1]
+ tst r1, #USART_CR1_UE
+ beq 1f
/* Check Transmit Data Register Empty */
txe_loop_3:
ldr r1, [r0, #USART_ISR]
tst r1, #USART_ISR_TXE
beq txe_loop_3
+1:
bx lr
endfunc console_stm32_core_flush
diff --git a/drivers/st/uart/aarch64/stm32_console.S b/drivers/st/uart/aarch64/stm32_console.S
new file mode 100644
index 0000000000..312b35d48a
--- /dev/null
+++ b/drivers/st/uart/aarch64/stm32_console.S
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2023, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/st/stm32_console.h>
+#include <drivers/st/stm32_uart_regs.h>
+
+#define USART_TIMEOUT 0x1000
+
+ /*
+ * "core" functions are low-level implementations that don't require
+ * writeable memory and are thus safe to call in BL1 crash context.
+ */
+ .globl console_stm32_core_init
+ .globl console_stm32_core_putc
+ .globl console_stm32_core_getc
+ .globl console_stm32_core_flush
+
+ .globl console_stm32_putc
+ .globl console_stm32_flush
+
+
+
+ /* -----------------------------------------------------------------
+ * int console_core_init(uintptr_t base_addr,
+ * unsigned int uart_clk,
+ * unsigned int baud_rate)
+ *
+ * Function to initialize the console without a C Runtime to print
+ * debug information. This function will be accessed by console_init
+ * and crash reporting.
+ *
+ * In: x0 - console base address
+ * w1 - Uart clock in Hz
+ * w2 - Baud rate
+ * Out: return 1 on success else 0 on error
+ * Clobber list : x1, x2, x3, x4
+ * -----------------------------------------------
+ */
+func console_stm32_core_init
+ /* Check the input base address */
+ cbz x0, core_init_fail
+#if !defined(IMAGE_BL2)
+#if STM32MP_RECONFIGURE_CONSOLE
+ /* UART clock rate is set to 0 in BL32, skip init in that case */
+ cbz x1, 1f
+#else /* STM32MP_RECONFIGURE_CONSOLE */
+ /* Skip UART initialization if it is already enabled */
+ ldr w3, [x0, #USART_CR1]
+ tst w3, #USART_CR1_UE
+ b.ne 1f
+#endif /* STM32MP_RECONFIGURE_CONSOLE */
+#endif /* IMAGE_BL2 */
+ /* Check baud rate and uart clock for sanity */
+ cbz w1, core_init_fail
+ cbz w2, core_init_fail
+ /* Disable UART */
+ ldr w3, [x0, #USART_CR1]
+ mov w4, #USART_CR1_UE
+ bic w3, w3, w4
+ str w3, [x0, #USART_CR1]
+ /* Configure UART */
+ mov w4, #(USART_CR1_TE)
+ orr w4, w4, #(USART_CR1_FIFOEN)
+ orr w3, w3, w4
+ str w3, [x0, #USART_CR1]
+ ldr w3, [x0, #USART_CR2]
+ mov w4, #USART_CR2_STOP
+ bic w3, w3, w4
+ str w3, [x0, #USART_CR2]
+ /* Divisor = (Uart clock + (baudrate / 2)) / baudrate */
+ lsr w3, w2, #1
+ add w3, w1, w3
+ udiv w3, w3, w2
+ cmp w3, #16
+ b.hi 2f
+ /* Oversampling 8 */
+ /* Divisor = (2 * Uart clock + (baudrate / 2)) / baudrate */
+ lsr w3, w2, #1
+ add w3, w3, w1, lsl #1
+ udiv w3, w3, w2
+ and w1, w3, #USART_BRR_DIV_FRACTION
+ lsr w1, w1, #1
+ bic w3, w3, #USART_BRR_DIV_FRACTION
+ orr w3, w3, w1
+ ldr w1, [x0, #USART_CR1]
+ orr w1, w1, #USART_CR1_OVER8
+ str w1, [x0, #USART_CR1]
+2:
+ str w3, [x0, #USART_BRR]
+ /* Enable UART */
+ ldr w3, [x0, #USART_CR1]
+ mov w4, #USART_CR1_UE
+ orr w3, w3, w4
+ str w3, [x0, #USART_CR1]
+ /* Check TEACK bit */
+ mov w2, #USART_TIMEOUT
+teack_loop:
+ subs w2, w2, #1
+ beq core_init_fail
+ ldr w3, [x0, #USART_ISR]
+ tst w3, #USART_ISR_TEACK
+ beq teack_loop
+1:
+ mov w0, #1
+ ret
+core_init_fail:
+ mov w0, wzr
+ ret
+endfunc console_stm32_core_init
+
+ .globl console_stm32_register
+
+ /* -------------------------------------------------------
+ * int console_stm32_register(uintptr_t baseaddr,
+ * uint32_t clock, uint32_t baud,
+ * console_t *console);
+ * Function to initialize and register a new STM32
+ * console. Storage passed in for the console struct
+ * *must* be persistent (i.e. not from the stack).
+ * In: x0 - UART register base address
+ * w1 - UART clock in Hz
+ * w2 - Baud rate
+ * x3 - pointer to empty console_t struct
+ * Out: return 1 on success, 0 on error
+ * Clobber list : x0, x1, x2, x6, x7, x14
+ * -------------------------------------------------------
+ */
+func console_stm32_register
+ mov x7, x30
+ mov x6, x3
+ cbz x6, register_fail
+ str x0, [x6, #CONSOLE_T_BASE]
+
+ bl console_stm32_core_init
+ cbz x0, register_fail
+
+ mov x0, x6
+ mov x30, x7
+ finish_console_register stm32 putc=1, getc=0, flush=1
+
+register_fail:
+ ret x7
+endfunc console_stm32_register
+
+ /* --------------------------------------------------------
+ * int console_stm32_core_putc(int c, uintptr_t base_addr)
+ * Function to output a character over the console. It
+ * returns the character printed on success or -1 on error.
+ * In : w0 - character to be printed
+ * x1 - console base address
+ * Out : return -1 on error else return character.
+ * Clobber list : x2
+ * --------------------------------------------------------
+ */
+func console_stm32_core_putc
+#if ENABLE_ASSERTIONS
+ cmp x1, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+ /* Check Transmit Data Register Empty */
+txe_loop:
+ ldr w2, [x1, #USART_ISR]
+ tst w2, #USART_ISR_TXE
+ beq txe_loop
+ str w0, [x1, #USART_TDR]
+ /* Check transmit complete flag */
+tc_loop:
+ ldr w2, [x1, #USART_ISR]
+ tst w2, #USART_ISR_TC
+ beq tc_loop
+ ret
+endfunc console_stm32_core_putc
+
+ /* --------------------------------------------------------
+ * int console_stm32_putc(int c, console_t *console)
+ * Function to output a character over the console. It
+ * returns the character printed on success or -1 on error.
+ * In : w0 - character to be printed
+ * x1 - pointer to console_t structure
+ * Out : return -1 on error else return character.
+ * Clobber list : x2
+ * --------------------------------------------------------
+ */
+func console_stm32_putc
+#if ENABLE_ASSERTIONS
+ cmp x1, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ ldr x1, [x1, #CONSOLE_T_BASE]
+ b console_stm32_core_putc
+endfunc console_stm32_putc
+
+ /* ---------------------------------------------
+ * int console_stm32_core_getc(uintptr_t base_addr)
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or -1 if no character is available.
+ * In : x0 - console base address
+ * Out: w0 - character if available, else -1
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_stm32_core_getc
+ /* Not supported */
+ mov w0, #-1
+ ret
+endfunc console_stm32_core_getc
+
+ /* ---------------------------------------------
+ * int console_stm32_core_flush(uintptr_t base_addr)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - console base address
+ * Out : return -1 on error else return 0.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_stm32_core_flush
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ /* Check Transmit Data Register Empty */
+txe_loop_3:
+ ldr w1, [x0, #USART_ISR]
+ tst w1, #USART_ISR_TXE
+ beq txe_loop_3
+ mov w0, #0
+ ret
+endfunc console_stm32_core_flush
+
+ /* ---------------------------------------------
+ * int console_stm32_flush(console_t *console)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : x0 - pointer to console_t structure
+ * Out : return -1 on error else return 0.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func console_stm32_flush
+#if ENABLE_ASSERTIONS
+ cmp x0, #0
+ ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+ ldr x0, [x0, #CONSOLE_T_BASE]
+ b console_stm32_core_flush
+endfunc console_stm32_flush
diff --git a/drivers/st/uart/stm32_uart.c b/drivers/st/uart/stm32_uart.c
new file mode 100644
index 0000000000..63970c76d9
--- /dev/null
+++ b/drivers/st/uart/stm32_uart.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/clk.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+/* UART time-out value */
+#define STM32_UART_TIMEOUT_US 20000U
+
+/* Mask to clear ALL the configuration registers */
+
+#define STM32_UART_CR1_FIELDS \
+ (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \
+ USART_CR1_RE | USART_CR1_OVER8 | USART_CR1_FIFOEN)
+
+#define STM32_UART_CR2_FIELDS \
+ (USART_CR2_SLVEN | USART_CR2_DIS_NSS | USART_CR2_ADDM7 | \
+ USART_CR2_LBDL | USART_CR2_LBDIE | USART_CR2_LBCL | \
+ USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | \
+ USART_CR2_STOP | USART_CR2_LINEN | USART_CR2_SWAP | \
+ USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_DATAINV | \
+ USART_CR2_MSBFIRST | USART_CR2_ABREN | USART_CR2_ABRMODE | \
+ USART_CR2_RTOEN | USART_CR2_ADD)
+
+#define STM32_UART_CR3_FIELDS \
+ (USART_CR3_EIE | USART_CR3_IREN | USART_CR3_IRLP | \
+ USART_CR3_HDSEL | USART_CR3_NACK | USART_CR3_SCEN | \
+ USART_CR3_DMAR | USART_CR3_DMAT | USART_CR3_RTSE | \
+ USART_CR3_CTSE | USART_CR3_CTSIE | USART_CR3_ONEBIT | \
+ USART_CR3_OVRDIS | USART_CR3_DDRE | USART_CR3_DEM | \
+ USART_CR3_DEP | USART_CR3_SCARCNT | USART_CR3_WUS | \
+ USART_CR3_WUFIE | USART_CR3_TXFTIE | USART_CR3_TCBGTIE | \
+ USART_CR3_RXFTCFG | USART_CR3_RXFTIE | USART_CR3_TXFTCFG)
+
+#define STM32_UART_ISR_ERRORS \
+ (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE)
+
+static const uint16_t presc_table[STM32_UART_PRESCALER_NB] = {
+ 1U, 2U, 4U, 6U, 8U, 10U, 12U, 16U, 32U, 64U, 128U, 256U
+};
+
+/* @brief BRR division operation to set BRR register in 8-bit oversampling
+ * mode.
+ * @param clockfreq: UART clock.
+ * @param baud_rate: Baud rate set by the user.
+ * @param prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling8(unsigned long clockfreq,
+ uint32_t baud_rate,
+ uint32_t prescaler)
+{
+ uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+ return ((scaled_freq * 2) + (baud_rate / 2)) / baud_rate;
+
+}
+
+/* @brief BRR division operation to set BRR register in 16-bit oversampling
+ * mode.
+ * @param clockfreq: UART clock.
+ * @param baud_rate: Baud rate set by the user.
+ * @param prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling16(unsigned long clockfreq,
+ uint32_t baud_rate,
+ uint32_t prescaler)
+{
+ uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+ return (scaled_freq + (baud_rate / 2)) / baud_rate;
+
+}
+
+/*
+ * @brief Return the UART clock frequency.
+ * @param huart: UART handle.
+ * @retval Frequency value in Hz.
+ */
+static unsigned long uart_get_clock_freq(struct stm32_uart_handle_s *huart)
+{
+ return fdt_get_uart_clock_freq((uintptr_t)huart->base);
+}
+
+/*
+ * @brief Configure the UART peripheral.
+ * @param huart: UART handle.
+ * @retval UART status.
+ */
+static int uart_set_config(struct stm32_uart_handle_s *huart,
+ const struct stm32_uart_init_s *init)
+{
+ uint32_t tmpreg;
+ unsigned long clockfreq;
+ unsigned long int_div;
+ uint32_t brrtemp;
+ uint32_t over_sampling;
+
+ /*---------------------- USART BRR configuration --------------------*/
+ clockfreq = uart_get_clock_freq(huart);
+ if (clockfreq == 0UL) {
+ return -ENODEV;
+ }
+
+ int_div = clockfreq / init->baud_rate;
+ if (int_div < 16U) {
+ uint32_t usartdiv = uart_div_sampling8(clockfreq,
+ init->baud_rate,
+ init->prescaler);
+
+ brrtemp = (usartdiv & USART_BRR_DIV_MANTISSA) |
+ ((usartdiv & USART_BRR_DIV_FRACTION) >> 1);
+ over_sampling = USART_CR1_OVER8;
+ } else {
+ brrtemp = uart_div_sampling16(clockfreq,
+ init->baud_rate,
+ init->prescaler) &
+ (USART_BRR_DIV_FRACTION | USART_BRR_DIV_MANTISSA);
+ over_sampling = 0x0U;
+ }
+ mmio_write_32(huart->base + USART_BRR, brrtemp);
+
+ /*
+ * ---------------------- USART CR1 Configuration --------------------
+ * Clear M, PCE, PS, TE, RE and OVER8 bits and configure
+ * the UART word length, parity, mode and oversampling:
+ * - set the M bits according to init->word_length value,
+ * - set PCE and PS bits according to init->parity value,
+ * - set TE and RE bits according to init->mode value,
+ * - set OVER8 bit according baudrate and clock.
+ */
+ tmpreg = init->word_length |
+ init->parity |
+ init->mode |
+ over_sampling |
+ init->fifo_mode;
+ mmio_clrsetbits_32(huart->base + USART_CR1, STM32_UART_CR1_FIELDS, tmpreg);
+
+ /*
+ * --------------------- USART CR2 Configuration ---------------------
+ * Configure the UART Stop Bits: Set STOP[13:12] bits according
+ * to init->stop_bits value.
+ */
+ mmio_clrsetbits_32(huart->base + USART_CR2, STM32_UART_CR2_FIELDS,
+ init->stop_bits);
+
+ /*
+ * --------------------- USART CR3 Configuration ---------------------
+ * Configure:
+ * - UART HardWare Flow Control: set CTSE and RTSE bits according
+ * to init->hw_flow_control value,
+ * - one-bit sampling method versus three samples' majority rule
+ * according to init->one_bit_sampling (not applicable to
+ * LPUART),
+ * - set TXFTCFG bit according to init->tx_fifo_threshold value,
+ * - set RXFTCFG bit according to init->rx_fifo_threshold value.
+ */
+ tmpreg = init->hw_flow_control | init->one_bit_sampling;
+
+ if (init->fifo_mode == USART_CR1_FIFOEN) {
+ tmpreg |= init->tx_fifo_threshold |
+ init->rx_fifo_threshold;
+ }
+
+ mmio_clrsetbits_32(huart->base + USART_CR3, STM32_UART_CR3_FIELDS, tmpreg);
+
+ /*
+ * --------------------- USART PRESC Configuration -------------------
+ * Configure UART Clock Prescaler : set PRESCALER according to
+ * init->prescaler value.
+ */
+ assert(init->prescaler < STM32_UART_PRESCALER_NB);
+ mmio_clrsetbits_32(huart->base + USART_PRESC, USART_PRESC_PRESCALER,
+ init->prescaler);
+
+ return 0;
+}
+
+/*
+ * @brief Handle UART communication timeout.
+ * @param huart: UART handle.
+ * @param flag: Specifies the UART flag to check.
+ * @retval UART status.
+ */
+static int stm32_uart_wait_flag(struct stm32_uart_handle_s *huart, uint32_t flag)
+{
+ uint64_t timeout_ref = timeout_init_us(STM32_UART_TIMEOUT_US);
+
+ while ((mmio_read_32(huart->base + USART_ISR) & flag) == 0U) {
+ if (timeout_elapsed(timeout_ref)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Check the UART idle State.
+ * @param huart: UART handle.
+ * @retval UART status.
+ */
+static int stm32_uart_check_idle(struct stm32_uart_handle_s *huart)
+{
+ int ret;
+
+ /* Check if the transmitter is enabled */
+ if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_TE) == USART_CR1_TE) {
+ ret = stm32_uart_wait_flag(huart, USART_ISR_TEACK);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /* Check if the receiver is enabled */
+ if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_RE) == USART_CR1_RE) {
+ ret = stm32_uart_wait_flag(huart, USART_ISR_REACK);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Compute RDR register mask depending on word length.
+ * @param huart: UART handle.
+ * @retval Mask value.
+ */
+static unsigned int stm32_uart_rdr_mask(const struct stm32_uart_init_s *init)
+{
+ unsigned int mask = 0U;
+
+ switch (init->word_length) {
+ case STM32_UART_WORDLENGTH_9B:
+ mask = GENMASK(8, 0);
+ break;
+ case STM32_UART_WORDLENGTH_8B:
+ mask = GENMASK(7, 0);
+ break;
+ case STM32_UART_WORDLENGTH_7B:
+ mask = GENMASK(6, 0);
+ break;
+ default:
+ break; /* not reached */
+ }
+
+ if (init->parity != STM32_UART_PARITY_NONE) {
+ mask >>= 1;
+ }
+
+ return mask;
+}
+
+/*
+ * @brief Check interrupt and status errors.
+ * @retval True if error detected, false otherwise.
+ */
+static bool stm32_uart_error_detected(struct stm32_uart_handle_s *huart)
+{
+ return (mmio_read_32(huart->base + USART_ISR) & STM32_UART_ISR_ERRORS) != 0U;
+}
+
+/*
+ * @brief Clear status errors.
+ */
+static void stm32_uart_error_clear(struct stm32_uart_handle_s *huart)
+{
+ mmio_write_32(huart->base + USART_ICR, STM32_UART_ISR_ERRORS);
+}
+
+/*
+ * @brief Stop the UART.
+ * @param base: UART base address.
+ */
+void stm32_uart_stop(uintptr_t base)
+{
+ mmio_clrbits_32(base + USART_CR1, USART_CR1_UE);
+}
+
+/*
+ * @brief Initialize UART.
+ * @param huart: UART handle.
+ * @param base_addr: base address of UART.
+ * @param init: UART initialization parameter.
+ * @retval UART status.
+ */
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+ uintptr_t base_addr,
+ const struct stm32_uart_init_s *init)
+{
+ int ret;
+ int uart_node;
+ int clk;
+ void *fdt = NULL;
+
+ if (huart == NULL || init == NULL || base_addr == 0U) {
+ return -EINVAL;
+ }
+
+ huart->base = base_addr;
+
+ /* Search UART instance in DT */
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (fdt == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ uart_node = dt_match_instance_by_compatible(DT_UART_COMPAT, base_addr);
+ if (uart_node == -FDT_ERR_NOTFOUND) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Pinctrl initialization */
+ if (dt_set_pinctrl_config(uart_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Clock initialization */
+ clk = fdt_get_clock_id(uart_node);
+ if (clk < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+ clk_enable(clk);
+
+ /* Disable the peripheral */
+ stm32_uart_stop(huart->base);
+
+ /* Computation of UART mask to apply to RDR register */
+ huart->rdr_mask = stm32_uart_rdr_mask(init);
+
+ /* Init the peripheral */
+ ret = uart_set_config(huart, init);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Enable the peripheral */
+ mmio_setbits_32(huart->base + USART_CR1, USART_CR1_UE);
+
+ /* TEACK and/or REACK to check */
+ return stm32_uart_check_idle(huart);
+}
+
+/*
+ * @brief Transmit one data in no blocking mode.
+ * @param huart: UART handle.
+ * @param c: data to sent.
+ * @retval UART status.
+ */
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c)
+{
+ int ret;
+
+ if (huart == NULL) {
+ return -EINVAL;
+ }
+
+ ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_write_32(huart->base + USART_TDR, c);
+ if (stm32_uart_error_detected(huart)) {
+ stm32_uart_error_clear(huart);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*
+ * @brief Flush TX Transmit fifo
+ * @param huart: UART handle.
+ * @retval UART status.
+ */
+int stm32_uart_flush(struct stm32_uart_handle_s *huart)
+{
+ int ret;
+
+ if (huart == NULL) {
+ return -EINVAL;
+ }
+
+ ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return stm32_uart_wait_flag(huart, USART_ISR_TC);
+}
+
+/*
+ * @brief Receive a data in no blocking mode.
+ * @retval value if >0 or UART status.
+ */
+int stm32_uart_getc(struct stm32_uart_handle_s *huart)
+{
+ uint32_t data;
+
+ if (huart == NULL) {
+ return -EINVAL;
+ }
+
+ /* Check if data is available */
+ if ((mmio_read_32(huart->base + USART_ISR) & USART_ISR_RXNE) == 0U) {
+ return -EAGAIN;
+ }
+
+ data = mmio_read_32(huart->base + USART_RDR) & huart->rdr_mask;
+
+ if (stm32_uart_error_detected(huart)) {
+ stm32_uart_error_clear(huart);
+ return -EFAULT;
+ }
+
+ return (int)data;
+}
diff --git a/drivers/st/usb/stm32mp1_usb.c b/drivers/st/usb/stm32mp1_usb.c
new file mode 100644
index 0000000000..78890f5eb2
--- /dev/null
+++ b/drivers/st/usb/stm32mp1_usb.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp1_usb.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#define USB_OTG_MODE_DEVICE 0U
+#define USB_OTG_MODE_HOST 1U
+#define USB_OTG_MODE_DRD 2U
+
+#define EP_TYPE_CTRL 0U
+#define EP_TYPE_ISOC 1U
+#define EP_TYPE_BULK 2U
+#define EP_TYPE_INTR 3U
+
+#define USBD_FIFO_FLUSH_TIMEOUT_US 1000U
+#define EP0_FIFO_SIZE 64U
+
+/* OTG registers offsets */
+#define OTG_GOTGINT 0x004U
+#define OTG_GAHBCFG 0x008U
+#define OTG_GUSBCFG 0x00CU
+#define OTG_GRSTCTL 0x010U
+#define OTG_GINTSTS 0x014U
+#define OTG_GINTMSK 0x018U
+#define OTG_GRXSTSP 0x020U
+#define OTG_GLPMCFG 0x054U
+#define OTG_DCFG 0x800U
+#define OTG_DCTL 0x804U
+#define OTG_DSTS 0x808U
+#define OTG_DIEPMSK 0x810U
+#define OTG_DOEPMSK 0x814U
+#define OTG_DAINT 0x818U
+#define OTG_DAINTMSK 0x81CU
+#define OTG_DIEPEMPMSK 0x834U
+
+/* Definitions for OTG_DIEPx registers */
+#define OTG_DIEP_BASE 0x900U
+#define OTG_DIEP_SIZE 0x20U
+#define OTG_DIEPCTL 0x00U
+#define OTG_DIEPINT 0x08U
+#define OTG_DIEPTSIZ 0x10U
+#define OTG_DIEPDMA 0x14U
+#define OTG_DTXFSTS 0x18U
+#define OTG_DIEP_MAX_NB 9U
+
+/* Definitions for OTG_DOEPx registers */
+#define OTG_DOEP_BASE 0xB00U
+#define OTG_DOEP_SIZE 0x20U
+#define OTG_DOEPCTL 0x00U
+#define OTG_DOEPINT 0x08U
+#define OTG_DOEPTSIZ 0x10U
+#define OTG_DOEPDMA 0x14U
+#define OTG_D0EP_MAX_NB 9U
+
+/* Definitions for OTG_DAINT registers */
+#define OTG_DAINT_OUT_MASK GENMASK(31, 16)
+#define OTG_DAINT_OUT_SHIFT 16U
+#define OTG_DAINT_IN_MASK GENMASK(15, 0)
+#define OTG_DAINT_IN_SHIFT 0U
+
+#define OTG_DAINT_EP0_IN BIT(16)
+#define OTG_DAINT_EP0_OUT BIT(0)
+
+/* Definitions for FIFOs */
+#define OTG_FIFO_BASE 0x1000U
+#define OTG_FIFO_SIZE 0x1000U
+
+/* Bit definitions for OTG_GOTGINT register */
+#define OTG_GOTGINT_SEDET BIT(2)
+
+/* Bit definitions for OTG_GAHBCFG register */
+#define OTG_GAHBCFG_GINT BIT(0)
+
+/* Bit definitions for OTG_GUSBCFG register */
+#define OTG_GUSBCFG_TRDT GENMASK(13, 10)
+#define OTG_GUSBCFG_TRDT_SHIFT 10U
+
+#define USBD_HS_TRDT_VALUE 9U
+
+/* Bit definitions for OTG_GRSTCTL register */
+#define OTG_GRSTCTL_RXFFLSH BIT(4)
+#define OTG_GRSTCTL_TXFFLSH BIT(5)
+#define OTG_GRSTCTL_TXFNUM_SHIFT 6U
+
+/* Bit definitions for OTG_GINTSTS register */
+#define OTG_GINTSTS_CMOD BIT(0)
+#define OTG_GINTSTS_MMIS BIT(1)
+#define OTG_GINTSTS_OTGINT BIT(2)
+#define OTG_GINTSTS_SOF BIT(3)
+#define OTG_GINTSTS_RXFLVL BIT(4)
+#define OTG_GINTSTS_USBSUSP BIT(11)
+#define OTG_GINTSTS_USBRST BIT(12)
+#define OTG_GINTSTS_ENUMDNE BIT(13)
+#define OTG_GINTSTS_IEPINT BIT(18)
+#define OTG_GINTSTS_OEPINT BIT(19)
+#define OTG_GINTSTS_IISOIXFR BIT(20)
+#define OTG_GINTSTS_IPXFR_INCOMPISOOUT BIT(21)
+#define OTG_GINTSTS_LPMINT BIT(27)
+#define OTG_GINTSTS_SRQINT BIT(30)
+#define OTG_GINTSTS_WKUPINT BIT(31)
+
+/* Bit definitions for OTG_GRXSTSP register */
+#define OTG_GRXSTSP_EPNUM GENMASK(3, 0)
+#define OTG_GRXSTSP_BCNT GENMASK(14, 4)
+#define OTG_GRXSTSP_BCNT_SHIFT 4U
+#define OTG_GRXSTSP_PKTSTS GENMASK(20, 17)
+#define OTG_GRXSTSP_PKTSTS_SHIFT 17U
+
+#define STS_GOUT_NAK 1U
+#define STS_DATA_UPDT 2U
+#define STS_XFER_COMP 3U
+#define STS_SETUP_COMP 4U
+#define STS_SETUP_UPDT 6U
+
+/* Bit definitions for OTG_GLPMCFG register */
+#define OTG_GLPMCFG_BESL GENMASK(5, 2)
+
+/* Bit definitions for OTG_DCFG register */
+#define OTG_DCFG_DAD GENMASK(10, 4)
+#define OTG_DCFG_DAD_SHIFT 4U
+
+/* Bit definitions for OTG_DCTL register */
+#define OTG_DCTL_RWUSIG BIT(0)
+#define OTG_DCTL_SDIS BIT(1)
+#define OTG_DCTL_CGINAK BIT(8)
+
+/* Bit definitions for OTG_DSTS register */
+#define OTG_DSTS_SUSPSTS BIT(0)
+#define OTG_DSTS_ENUMSPD_MASK GENMASK(2, 1)
+#define OTG_DSTS_FNSOF0 BIT(8)
+
+#define OTG_DSTS_ENUMSPD(val) ((val) << 1)
+#define OTG_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(0U)
+#define OTG_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(1U)
+#define OTG_DSTS_ENUMSPD_LS_PHY_6MHZ OTG_DSTS_ENUMSPD(2U)
+#define OTG_DSTS_ENUMSPD_FS_PHY_48MHZ OTG_DSTS_ENUMSPD(3U)
+
+/* Bit definitions for OTG_DIEPMSK register */
+#define OTG_DIEPMSK_XFRCM BIT(0)
+#define OTG_DIEPMSK_EPDM BIT(1)
+#define OTG_DIEPMSK_TOM BIT(3)
+
+/* Bit definitions for OTG_DOEPMSK register */
+#define OTG_DOEPMSK_XFRCM BIT(0)
+#define OTG_DOEPMSK_EPDM BIT(1)
+#define OTG_DOEPMSK_STUPM BIT(3)
+
+/* Bit definitions for OTG_DIEPCTLx registers */
+#define OTG_DIEPCTL_MPSIZ GENMASK(10, 0)
+#define OTG_DIEPCTL_STALL BIT(21)
+#define OTG_DIEPCTL_CNAK BIT(26)
+#define OTG_DIEPCTL_SD0PID_SEVNFRM BIT(28)
+#define OTG_DIEPCTL_SODDFRM BIT(29)
+#define OTG_DIEPCTL_EPDIS BIT(30)
+#define OTG_DIEPCTL_EPENA BIT(31)
+
+/* Bit definitions for OTG_DIEPINTx registers */
+#define OTG_DIEPINT_XFRC BIT(0)
+#define OTG_DIEPINT_EPDISD BIT(1)
+#define OTG_DIEPINT_TOC BIT(3)
+#define OTG_DIEPINT_ITTXFE BIT(4)
+#define OTG_DIEPINT_INEPNE BIT(6)
+#define OTG_DIEPINT_TXFE BIT(7)
+#define OTG_DIEPINT_TXFE_SHIFT 7U
+
+#define OTG_DIEPINT_MASK (BIT(13) | BIT(11) | GENMASK(9, 0))
+
+/* Bit definitions for OTG_DIEPTSIZx registers */
+#define OTG_DIEPTSIZ_XFRSIZ GENMASK(18, 0)
+#define OTG_DIEPTSIZ_PKTCNT GENMASK(28, 19)
+#define OTG_DIEPTSIZ_PKTCNT_SHIFT 19U
+#define OTG_DIEPTSIZ_MCNT_MASK GENMASK(30, 29)
+#define OTG_DIEPTSIZ_MCNT_DATA0 BIT(29)
+
+#define OTG_DIEPTSIZ_PKTCNT_1 BIT(19)
+
+/* Bit definitions for OTG_DTXFSTSx registers */
+#define OTG_DTXFSTS_INEPTFSAV GENMASK(15, 0)
+
+/* Bit definitions for OTG_DOEPCTLx registers */
+#define OTG_DOEPCTL_STALL BIT(21)
+#define OTG_DOEPCTL_CNAK BIT(26)
+#define OTG_DOEPCTL_SD0PID_SEVNFRM BIT(28) /* other than endpoint 0 */
+#define OTG_DOEPCTL_SD1PID_SODDFRM BIT(29) /* other than endpoint 0 */
+#define OTG_DOEPCTL_EPDIS BIT(30)
+#define OTG_DOEPCTL_EPENA BIT(31)
+
+/* Bit definitions for OTG_DOEPTSIZx registers */
+#define OTG_DOEPTSIZ_XFRSIZ GENMASK(18, 0)
+#define OTG_DOEPTSIZ_PKTCNT GENMASK(28, 19)
+#define OTG_DOEPTSIZ_RXDPID_STUPCNT GENMASK(30, 29)
+
+/* Bit definitions for OTG_DOEPINTx registers */
+#define OTG_DOEPINT_XFRC BIT(0)
+#define OTG_DOEPINT_STUP BIT(3)
+#define OTG_DOEPINT_OTEPDIS BIT(4)
+
+#define OTG_DOEPINT_MASK (GENMASK(15, 12) | GENMASK(9, 8) | GENMASK(6, 0))
+
+#define EP_NB 15U
+#define EP_ALL 0x10U
+
+/*
+ * Flush TX FIFO.
+ * handle: PCD handle.
+ * num: FIFO number.
+ * This parameter can be a value from 1 to 15 or EP_ALL.
+ * EP_ALL= 0x10 means Flush all TX FIFOs
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_flush_tx_fifo(void *handle, uint32_t num)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US);
+
+ mmio_write_32(usb_base_addr + OTG_GRSTCTL,
+ OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << OTG_GRSTCTL_TXFNUM_SHIFT));
+
+ while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) &
+ OTG_GRSTCTL_TXFFLSH) == OTG_GRSTCTL_TXFFLSH) {
+ if (timeout_elapsed(timeout)) {
+ return USBD_TIMEOUT;
+ }
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Flush RX FIFO.
+ * handle: PCD handle.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_flush_rx_fifo(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US);
+
+ mmio_write_32(usb_base_addr + OTG_GRSTCTL, OTG_GRSTCTL_RXFFLSH);
+
+ while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) &
+ OTG_GRSTCTL_RXFFLSH) == OTG_GRSTCTL_RXFFLSH) {
+ if (timeout_elapsed(timeout)) {
+ return USBD_TIMEOUT;
+ }
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Return the global USB interrupt status.
+ * handle: PCD handle.
+ * return: Interrupt register value.
+ */
+static uint32_t usb_dwc2_read_int(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return mmio_read_32(usb_base_addr + OTG_GINTSTS) &
+ mmio_read_32(usb_base_addr + OTG_GINTMSK);
+}
+
+/*
+ * Return the USB device OUT endpoints interrupt.
+ * handle: PCD handle.
+ * return: Device OUT endpoint interrupts.
+ */
+static uint32_t usb_dwc2_all_out_ep_int(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return ((mmio_read_32(usb_base_addr + OTG_DAINT) &
+ mmio_read_32(usb_base_addr + OTG_DAINTMSK)) &
+ OTG_DAINT_OUT_MASK) >> OTG_DAINT_OUT_SHIFT;
+}
+
+/*
+ * Return the USB device IN endpoints interrupt.
+ * handle: PCD handle.
+ * return: Device IN endpoint interrupts.
+ */
+static uint32_t usb_dwc2_all_in_ep_int(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return ((mmio_read_32(usb_base_addr + OTG_DAINT) &
+ mmio_read_32(usb_base_addr + OTG_DAINTMSK)) &
+ OTG_DAINT_IN_MASK) >> OTG_DAINT_IN_SHIFT;
+}
+
+/*
+ * Return Device OUT EP interrupt register.
+ * handle: PCD handle.
+ * epnum: Endpoint number.
+ * This parameter can be a value from 0 to 15.
+ * return: Device OUT EP Interrupt register.
+ */
+static uint32_t usb_dwc2_out_ep_int(void *handle, uint8_t epnum)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return mmio_read_32(usb_base_addr + OTG_DOEP_BASE +
+ (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT) &
+ mmio_read_32(usb_base_addr + OTG_DOEPMSK);
+}
+
+/*
+ * Return Device IN EP interrupt register.
+ * handle: PCD handle.
+ * epnum: Endpoint number.
+ * This parameter can be a value from 0 to 15.
+ * return: Device IN EP Interrupt register.
+ */
+static uint32_t usb_dwc2_in_ep_int(void *handle, uint8_t epnum)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t msk;
+ uint32_t emp;
+
+ msk = mmio_read_32(usb_base_addr + OTG_DIEPMSK);
+ emp = mmio_read_32(usb_base_addr + OTG_DIEPEMPMSK);
+ msk |= ((emp >> epnum) << OTG_DIEPINT_TXFE_SHIFT) & OTG_DIEPINT_TXFE;
+
+ return mmio_read_32(usb_base_addr + OTG_DIEP_BASE +
+ (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT) & msk;
+}
+
+/*
+ * Return USB core mode.
+ * handle: PCD handle.
+ * return: Core mode.
+ * This parameter can be 0 (host) or 1 (device).
+ */
+static uint32_t usb_dwc2_get_mode(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ return mmio_read_32(usb_base_addr + OTG_GINTSTS) & OTG_GINTSTS_CMOD;
+}
+
+/*
+ * Activate EP0 for detup transactions.
+ * handle: PCD handle.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_activate_setup(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE;
+
+ /* Set the MPS of the IN EP based on the enumeration speed */
+ mmio_clrbits_32(reg_offset + OTG_DIEPCTL, OTG_DIEPCTL_MPSIZ);
+
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_ENUMSPD_MASK) ==
+ OTG_DSTS_ENUMSPD_LS_PHY_6MHZ) {
+ mmio_setbits_32(reg_offset + OTG_DIEPCTL, 3U);
+ }
+
+ mmio_setbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_CGINAK);
+
+ return USBD_OK;
+}
+
+/*
+ * Prepare the EP0 to start the first control setup.
+ * handle: Selected device.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep0_out_start(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE + OTG_DIEPTSIZ;
+ uint32_t reg_value = 0U;
+
+ /* PKTCNT = 1 and XFRSIZ = 24 bytes for endpoint 0 */
+ reg_value |= OTG_DIEPTSIZ_PKTCNT_1;
+ reg_value |= (EP0_FIFO_SIZE & OTG_DIEPTSIZ_XFRSIZ);
+ reg_value |= OTG_DOEPTSIZ_RXDPID_STUPCNT;
+
+ mmio_write_32(reg_offset, reg_value);
+
+ return USBD_OK;
+}
+
+/*
+ * Write a packet into the TX FIFO associated with the EP/channel.
+ * handle: Selected device.
+ * src: Pointer to source buffer.
+ * ch_ep_num: Endpoint or host channel number.
+ * len: Number of bytes to write.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_write_packet(void *handle, uint8_t *src,
+ uint8_t ch_ep_num, uint16_t len)
+{
+ uint32_t reg_offset;
+ uint32_t count32b = (len + 3U) / 4U;
+ uint32_t i;
+
+ reg_offset = (uintptr_t)handle + OTG_FIFO_BASE +
+ (ch_ep_num * OTG_FIFO_SIZE);
+
+ for (i = 0U; i < count32b; i++) {
+ uint32_t src_copy = 0U;
+ uint32_t j;
+
+ /* Data written to FIFO need to be 4 bytes aligned */
+ for (j = 0U; j < 4U; j++) {
+ src_copy += (*(src + j)) << (8U * j);
+ }
+
+ mmio_write_32(reg_offset, src_copy);
+ src += 4U;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Read a packet from the RX FIFO associated with the EP/channel.
+ * handle: Selected device.
+ * dst: Destination pointer.
+ * len: Number of bytes to read.
+ * return: Pointer to destination buffer.
+ */
+static void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len)
+{
+ uint32_t reg_offset;
+ uint32_t count32b = (len + 3U) / 4U;
+ uint32_t i;
+
+ VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest);
+
+ reg_offset = (uintptr_t)handle + OTG_FIFO_BASE;
+
+ for (i = 0U; i < count32b; i++) {
+ *(uint32_t *)dest = mmio_read_32(reg_offset);
+ dest += 4U;
+ dsb();
+ }
+
+ return (void *)dest;
+}
+
+/*
+ * Setup and start a transfer over an EP.
+ * handle: Selected device
+ * ep: Pointer to endpoint structure.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep_start_xfer(void *handle, struct usbd_ep *ep)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ uint32_t reg_value;
+ uint32_t clear_value;
+
+ if (ep->is_in) {
+ reg_offset = usb_base_addr + OTG_DIEP_BASE + (ep->num * OTG_DIEP_SIZE);
+ clear_value = OTG_DIEPTSIZ_PKTCNT | OTG_DIEPTSIZ_XFRSIZ;
+ if (ep->xfer_len == 0U) {
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1;
+ } else {
+ /*
+ * Program the transfer size and packet count
+ * as follows:
+ * xfersize = N * maxpacket + short_packet
+ * pktcnt = N + (short_packet exist ? 1 : 0)
+ */
+ reg_value = (OTG_DIEPTSIZ_PKTCNT &
+ (((ep->xfer_len + ep->maxpacket - 1U) /
+ ep->maxpacket) << OTG_DIEPTSIZ_PKTCNT_SHIFT))
+ | ep->xfer_len;
+
+ if (ep->type == EP_TYPE_ISOC) {
+ clear_value |= OTG_DIEPTSIZ_MCNT_MASK;
+ reg_value |= OTG_DIEPTSIZ_MCNT_DATA0;
+ }
+ }
+
+ mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, clear_value, reg_value);
+
+ if ((ep->type != EP_TYPE_ISOC) && (ep->xfer_len > 0U)) {
+ /* Enable the TX FIFO empty interrupt for this EP */
+ mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(ep->num));
+ }
+
+ /* EP enable, IN data in FIFO */
+ reg_value = OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA;
+
+ if (ep->type == EP_TYPE_ISOC) {
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) {
+ reg_value |= OTG_DIEPCTL_SODDFRM;
+ } else {
+ reg_value |= OTG_DIEPCTL_SD0PID_SEVNFRM;
+ }
+ }
+
+ mmio_setbits_32(reg_offset + OTG_DIEPCTL, reg_value);
+
+ if (ep->type == EP_TYPE_ISOC) {
+ usb_dwc2_write_packet(handle, ep->xfer_buff, ep->num, ep->xfer_len);
+ }
+ } else {
+ reg_offset = usb_base_addr + OTG_DOEP_BASE + (ep->num * OTG_DOEP_SIZE);
+ /*
+ * Program the transfer size and packet count as follows:
+ * pktcnt = N
+ * xfersize = N * maxpacket
+ */
+ if (ep->xfer_len == 0U) {
+ reg_value = ep->maxpacket | OTG_DIEPTSIZ_PKTCNT_1;
+ } else {
+ uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket;
+
+ reg_value = (pktcnt << OTG_DIEPTSIZ_PKTCNT_SHIFT) |
+ (ep->maxpacket * pktcnt);
+ }
+
+ mmio_clrsetbits_32(reg_offset + OTG_DOEPTSIZ,
+ OTG_DOEPTSIZ_XFRSIZ & OTG_DOEPTSIZ_PKTCNT,
+ reg_value);
+
+ /* EP enable */
+ reg_value = OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA;
+
+ if (ep->type == EP_TYPE_ISOC) {
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) {
+ reg_value |= OTG_DOEPCTL_SD1PID_SODDFRM;
+ } else {
+ reg_value |= OTG_DOEPCTL_SD0PID_SEVNFRM;
+ }
+ }
+
+ mmio_setbits_32(reg_offset + OTG_DOEPCTL, reg_value);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Setup and start a transfer over the EP0.
+ * handle: Selected device.
+ * ep: Pointer to endpoint structure.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep0_start_xfer(void *handle, struct usbd_ep *ep)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ uint32_t reg_value;
+
+ if (ep->is_in) {
+ reg_offset = usb_base_addr + OTG_DIEP_BASE +
+ (ep->num * OTG_DIEP_SIZE);
+
+ if (ep->xfer_len == 0U) {
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1;
+ } else {
+ /*
+ * Program the transfer size and packet count
+ * as follows:
+ * xfersize = N * maxpacket + short_packet
+ * pktcnt = N + (short_packet exist ? 1 : 0)
+ */
+
+ if (ep->xfer_len > ep->maxpacket) {
+ ep->xfer_len = ep->maxpacket;
+ }
+
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->xfer_len;
+ }
+
+ mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ,
+ OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT,
+ reg_value);
+
+ /* Enable the TX FIFO empty interrupt for this EP */
+ if (ep->xfer_len > 0U) {
+ mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK,
+ BIT(ep->num));
+ }
+
+ /* EP enable, IN data in FIFO */
+ mmio_setbits_32(reg_offset + OTG_DIEPCTL,
+ OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA);
+ } else {
+ reg_offset = usb_base_addr + OTG_DOEP_BASE +
+ (ep->num * OTG_DOEP_SIZE);
+
+ /*
+ * Program the transfer size and packet count as follows:
+ * pktcnt = N
+ * xfersize = N * maxpacket
+ */
+ if (ep->xfer_len > 0U) {
+ ep->xfer_len = ep->maxpacket;
+ }
+
+ reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->maxpacket;
+
+ mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ,
+ OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT,
+ reg_value);
+
+ /* EP enable */
+ mmio_setbits_32(reg_offset + OTG_DOEPCTL,
+ OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Set a stall condition over an EP.
+ * handle: Selected device.
+ * ep: Pointer to endpoint structure.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_ep_set_stall(void *handle, struct usbd_ep *ep)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ uint32_t reg_value;
+
+ if (ep->is_in) {
+ reg_offset = usb_base_addr + OTG_DIEP_BASE +
+ (ep->num * OTG_DIEP_SIZE);
+ reg_value = mmio_read_32(reg_offset + OTG_DIEPCTL);
+
+ if ((reg_value & OTG_DIEPCTL_EPENA) == 0U) {
+ reg_value &= ~OTG_DIEPCTL_EPDIS;
+ }
+
+ reg_value |= OTG_DIEPCTL_STALL;
+
+ mmio_write_32(reg_offset + OTG_DIEPCTL, reg_value);
+ } else {
+ reg_offset = usb_base_addr + OTG_DOEP_BASE +
+ (ep->num * OTG_DOEP_SIZE);
+ reg_value = mmio_read_32(reg_offset + OTG_DOEPCTL);
+
+ if ((reg_value & OTG_DOEPCTL_EPENA) == 0U) {
+ reg_value &= ~OTG_DOEPCTL_EPDIS;
+ }
+
+ reg_value |= OTG_DOEPCTL_STALL;
+
+ mmio_write_32(reg_offset + OTG_DOEPCTL, reg_value);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Stop the USB device mode.
+ * handle: Selected device.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_stop_device(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t i;
+
+ /* Disable Int */
+ mmio_clrbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT);
+
+ /* Clear pending interrupts */
+ for (i = 0U; i < EP_NB; i++) {
+ mmio_write_32(usb_base_addr + OTG_DIEP_BASE + (i * OTG_DIEP_SIZE) + OTG_DIEPINT,
+ OTG_DIEPINT_MASK);
+ mmio_write_32(usb_base_addr + OTG_DOEP_BASE + (i * OTG_DOEP_SIZE) + OTG_DOEPINT,
+ OTG_DOEPINT_MASK);
+ }
+
+ mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK);
+
+ /* Clear interrupt masks */
+ mmio_write_32(usb_base_addr + OTG_DIEPMSK, 0U);
+ mmio_write_32(usb_base_addr + OTG_DOEPMSK, 0U);
+ mmio_write_32(usb_base_addr + OTG_DAINTMSK, 0U);
+
+ /* Flush the FIFO */
+ usb_dwc2_flush_rx_fifo(handle);
+ usb_dwc2_flush_tx_fifo(handle, EP_ALL);
+
+ /* Disconnect the USB device by disabling the pull-up/pull-down */
+ mmio_setbits_32((uintptr_t)handle + OTG_DCTL, OTG_DCTL_SDIS);
+
+ return USBD_OK;
+}
+
+/*
+ * Stop the USB device mode.
+ * handle: Selected device.
+ * address: New device address to be assigned.
+ * This parameter can be a value from 0 to 255.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_set_address(void *handle, uint8_t address)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ mmio_clrsetbits_32(usb_base_addr + OTG_DCFG,
+ OTG_DCFG_DAD,
+ address << OTG_DCFG_DAD_SHIFT);
+
+ return USBD_OK;
+}
+
+/*
+ * Check FIFO for the next packet to be loaded.
+ * handle: Selected device.
+ * epnum : Endpoint number.
+ * xfer_len: Block length.
+ * xfer_count: Number of blocks.
+ * maxpacket: Max packet length.
+ * xfer_buff: Buffer pointer.
+ * return: USB status.
+ */
+static enum usb_status usb_dwc2_write_empty_tx_fifo(void *handle,
+ uint32_t epnum,
+ uint32_t xfer_len,
+ uint32_t *xfer_count,
+ uint32_t maxpacket,
+ uint8_t **xfer_buff)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t reg_offset;
+ int32_t len;
+ uint32_t len32b;
+ enum usb_status ret;
+
+ len = xfer_len - *xfer_count;
+
+ if ((len > 0) && ((uint32_t)len > maxpacket)) {
+ len = maxpacket;
+ }
+
+ len32b = (len + 3U) / 4U;
+
+ reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE);
+
+ while (((mmio_read_32(reg_offset + OTG_DTXFSTS) &
+ OTG_DTXFSTS_INEPTFSAV) > len32b) &&
+ (*xfer_count < xfer_len) && (xfer_len != 0U)) {
+ /* Write the FIFO */
+ len = xfer_len - *xfer_count;
+
+ if ((len > 0) && ((uint32_t)len > maxpacket)) {
+ len = maxpacket;
+ }
+
+ len32b = (len + 3U) / 4U;
+
+ ret = usb_dwc2_write_packet(handle, *xfer_buff, epnum, len);
+ if (ret != USBD_OK) {
+ return ret;
+ }
+
+ *xfer_buff += len;
+ *xfer_count += len;
+ }
+
+ if (len <= 0) {
+ mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum));
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * Handle PCD interrupt request.
+ * handle: PCD handle.
+ * param: Pointer to information updated by the IT handling.
+ * return: Action to do after IT handling.
+ */
+static enum usb_action usb_dwc2_it_handler(void *handle, uint32_t *param)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+ uint32_t ep_intr;
+ uint32_t epint;
+ uint32_t epnum;
+ uint32_t temp;
+ enum usb_status __unused ret;
+
+ if (usb_dwc2_get_mode(handle) != USB_OTG_MODE_DEVICE) {
+ return USB_NOTHING;
+ }
+
+ /* Avoid spurious interrupt */
+ if (usb_dwc2_read_int(handle) == 0U) {
+ return USB_NOTHING;
+ }
+
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_MMIS) != 0U) {
+ /* Incorrect mode, acknowledge the interrupt */
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_MMIS);
+ }
+
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OEPINT) != 0U) {
+ uint32_t reg_offset;
+
+ /* Read in the device interrupt bits */
+ ep_intr = usb_dwc2_all_out_ep_int(handle);
+ epnum = 0U;
+ while ((ep_intr & BIT(0)) != BIT(0)) {
+ epnum++;
+ ep_intr >>= 1;
+ }
+
+ reg_offset = usb_base_addr + OTG_DOEP_BASE + (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT;
+
+ epint = usb_dwc2_out_ep_int(handle, epnum);
+
+ if ((epint & OTG_DOEPINT_XFRC) == OTG_DOEPINT_XFRC) {
+ mmio_write_32(reg_offset, OTG_DOEPINT_XFRC);
+ *param = epnum;
+
+ return USB_DATA_OUT;
+ }
+
+ if ((epint & OTG_DOEPINT_STUP) == OTG_DOEPINT_STUP) {
+ /* Inform that a setup packet is available */
+ mmio_write_32(reg_offset, OTG_DOEPINT_STUP);
+
+ return USB_SETUP;
+ }
+
+ if ((epint & OTG_DOEPINT_OTEPDIS) == OTG_DOEPINT_OTEPDIS) {
+ mmio_write_32(reg_offset, OTG_DOEPINT_OTEPDIS);
+ }
+ }
+
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IEPINT) != 0U) {
+ uint32_t reg_offset;
+
+ /* Read in the device interrupt bits */
+ ep_intr = usb_dwc2_all_in_ep_int(handle);
+ epnum = 0U;
+ while ((ep_intr & BIT(0)) != BIT(0)) {
+ epnum++;
+ ep_intr >>= 1;
+ }
+
+ reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT;
+
+ epint = usb_dwc2_in_ep_int(handle, epnum);
+
+ if ((epint & OTG_DIEPINT_XFRC) == OTG_DIEPINT_XFRC) {
+ mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum));
+ mmio_write_32(reg_offset, OTG_DIEPINT_XFRC);
+ *param = epnum;
+
+ return USB_DATA_IN;
+ }
+
+ if ((epint & OTG_DIEPINT_TOC) == OTG_DIEPINT_TOC) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_TOC);
+ }
+
+ if ((epint & OTG_DIEPINT_ITTXFE) == OTG_DIEPINT_ITTXFE) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_ITTXFE);
+ }
+
+ if ((epint & OTG_DIEPINT_INEPNE) == OTG_DIEPINT_INEPNE) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_INEPNE);
+ }
+
+ if ((epint & OTG_DIEPINT_EPDISD) == OTG_DIEPINT_EPDISD) {
+ mmio_write_32(reg_offset, OTG_DIEPINT_EPDISD);
+ }
+
+ if ((epint & OTG_DIEPINT_TXFE) == OTG_DIEPINT_TXFE) {
+ *param = epnum;
+
+ return USB_WRITE_EMPTY;
+ }
+ }
+
+ /* Handle resume interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_WKUPINT) != 0U) {
+ INFO("handle USB : Resume\n");
+
+ /* Clear the remote wake-up signaling */
+ mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG);
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_WKUPINT);
+
+ return USB_RESUME;
+ }
+
+ /* Handle suspend interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBSUSP) != 0U) {
+ INFO("handle USB : Suspend int\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBSUSP);
+
+ if ((mmio_read_32(usb_base_addr + OTG_DSTS) &
+ OTG_DSTS_SUSPSTS) == OTG_DSTS_SUSPSTS) {
+ return USB_SUSPEND;
+ }
+ }
+
+ /* Handle LPM interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_LPMINT) != 0U) {
+ INFO("handle USB : LPM int enter in suspend\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_LPMINT);
+ *param = (mmio_read_32(usb_base_addr + OTG_GLPMCFG) &
+ OTG_GLPMCFG_BESL) >> 2;
+
+ return USB_LPM;
+ }
+
+ /* Handle reset interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBRST) != 0U) {
+ INFO("handle USB : Reset\n");
+
+ mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG);
+
+ usb_dwc2_flush_tx_fifo(handle, 0U);
+
+ mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK);
+ mmio_setbits_32(usb_base_addr + OTG_DAINTMSK, OTG_DAINT_EP0_IN | OTG_DAINT_EP0_OUT);
+
+ mmio_setbits_32(usb_base_addr + OTG_DOEPMSK, OTG_DOEPMSK_STUPM |
+ OTG_DOEPMSK_XFRCM |
+ OTG_DOEPMSK_EPDM);
+ mmio_setbits_32(usb_base_addr + OTG_DIEPMSK, OTG_DIEPMSK_TOM |
+ OTG_DIEPMSK_XFRCM |
+ OTG_DIEPMSK_EPDM);
+
+ /* Set default address to 0 */
+ mmio_clrbits_32(usb_base_addr + OTG_DCFG, OTG_DCFG_DAD);
+
+ /* Setup EP0 to receive SETUP packets */
+ ret = usb_dwc2_ep0_out_start(handle);
+ assert(ret == USBD_OK);
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBRST);
+
+ return USB_RESET;
+ }
+
+ /* Handle enumeration done interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_ENUMDNE) != 0U) {
+ ret = usb_dwc2_activate_setup(handle);
+ assert(ret == USBD_OK);
+
+ mmio_clrbits_32(usb_base_addr + OTG_GUSBCFG, OTG_GUSBCFG_TRDT);
+
+ mmio_setbits_32(usb_base_addr + OTG_GUSBCFG,
+ (USBD_HS_TRDT_VALUE << OTG_GUSBCFG_TRDT_SHIFT) & OTG_GUSBCFG_TRDT);
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_ENUMDNE);
+
+ return USB_ENUM_DONE;
+ }
+
+ /* Handle RXQLevel interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_RXFLVL) != 0U) {
+ mmio_clrbits_32(usb_base_addr + OTG_GINTMSK,
+ OTG_GINTSTS_RXFLVL);
+
+ temp = mmio_read_32(usb_base_addr + OTG_GRXSTSP);
+
+ *param = temp & OTG_GRXSTSP_EPNUM;
+ *param |= (temp & OTG_GRXSTSP_BCNT) << (USBD_OUT_COUNT_SHIFT -
+ OTG_GRXSTSP_BCNT_SHIFT);
+
+ if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == STS_DATA_UPDT) {
+ if ((temp & OTG_GRXSTSP_BCNT) != 0U) {
+ mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
+
+ return USB_READ_DATA_PACKET;
+ }
+ } else if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) ==
+ STS_SETUP_UPDT) {
+ mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
+
+ return USB_READ_SETUP_PACKET;
+ }
+
+ mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL);
+ }
+
+ /* Handle SOF interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SOF) != 0U) {
+ INFO("handle USB : SOF\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SOF);
+
+ return USB_SOF;
+ }
+
+ /* Handle incomplete ISO IN interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IISOIXFR) != 0U) {
+ INFO("handle USB : ISO IN\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS,
+ OTG_GINTSTS_IISOIXFR);
+ }
+
+ /* Handle incomplete ISO OUT interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IPXFR_INCOMPISOOUT) !=
+ 0U) {
+ INFO("handle USB : ISO OUT\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS,
+ OTG_GINTSTS_IPXFR_INCOMPISOOUT);
+ }
+
+ /* Handle connection event interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SRQINT) != 0U) {
+ INFO("handle USB : Connect\n");
+
+ mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SRQINT);
+ }
+
+ /* Handle disconnection event interrupt */
+ if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OTGINT) != 0U) {
+ INFO("handle USB : Disconnect\n");
+
+ temp = mmio_read_32(usb_base_addr + OTG_GOTGINT);
+
+ if ((temp & OTG_GOTGINT_SEDET) == OTG_GOTGINT_SEDET) {
+ return USB_DISCONNECT;
+ }
+ }
+
+ return USB_NOTHING;
+}
+
+/*
+ * Start the usb device mode
+ * usb_core_handle: USB core driver handle.
+ * return USB status.
+ */
+static enum usb_status usb_dwc2_start_device(void *handle)
+{
+ uintptr_t usb_base_addr = (uintptr_t)handle;
+
+ mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_SDIS);
+ mmio_setbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT);
+
+ return USBD_OK;
+}
+
+static const struct usb_driver usb_dwc2driver = {
+ .ep0_out_start = usb_dwc2_ep0_out_start,
+ .ep_start_xfer = usb_dwc2_ep_start_xfer,
+ .ep0_start_xfer = usb_dwc2_ep0_start_xfer,
+ .write_packet = usb_dwc2_write_packet,
+ .read_packet = usb_dwc2_read_packet,
+ .ep_set_stall = usb_dwc2_ep_set_stall,
+ .start_device = usb_dwc2_start_device,
+ .stop_device = usb_dwc2_stop_device,
+ .set_address = usb_dwc2_set_address,
+ .write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo,
+ .it_handler = usb_dwc2_it_handler
+};
+
+/*
+ * Initialize USB DWC2 driver.
+ * usb_core_handle: USB core driver handle.
+ * pcd_handle: PCD handle.
+ * base_register: USB global register base address.
+ */
+void stm32mp1_usb_init_driver(struct usb_handle *usb_core_handle,
+ struct pcd_handle *pcd_handle,
+ void *base_register)
+{
+ register_usb_driver(usb_core_handle, pcd_handle, &usb_dwc2driver,
+ base_register);
+}
diff --git a/drivers/ti/uart/aarch32/16550_console.S b/drivers/ti/uart/aarch32/16550_console.S
index 0429f87024..898a68d8cb 100644
--- a/drivers/ti/uart/aarch32/16550_console.S
+++ b/drivers/ti/uart/aarch32/16550_console.S
@@ -124,7 +124,7 @@ func console_16550_register
register_16550:
mov r0, r4
pop {r4, lr}
- finish_console_register 16550 putc=1, getc=1, flush=1
+ finish_console_register 16550 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
pop {r4, pc}
diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S
index cb2151253c..2b1b5a9d76 100644
--- a/drivers/ti/uart/aarch64/16550_console.S
+++ b/drivers/ti/uart/aarch64/16550_console.S
@@ -118,7 +118,7 @@ func console_16550_register
register_16550:
mov x0, x6
mov x30, x7
- finish_console_register 16550 putc=1, getc=1, flush=1
+ finish_console_register 16550 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
register_fail:
ret x7
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 6dbf372361..33ceb26381 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -30,57 +30,196 @@
static ufs_params_t ufs_params;
static int nutrs; /* Number of UTP Transfer Request Slots */
+/*
+ * ufs_uic_error_handler - UIC error interrupts handler
+ * @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
+ *
+ * Returns
+ * 0 - ignore error
+ * -EIO - fatal error, needs re-init
+ * -EAGAIN - non-fatal error, retries are sufficient
+ */
+static int ufs_uic_error_handler(bool ignore_linereset)
+{
+ uint32_t data;
+ int result = 0;
+
+ data = mmio_read_32(ufs_params.reg_base + UECPA);
+ if (data & UFS_UIC_PA_ERROR_MASK) {
+ if (data & PA_LAYER_GEN_ERR) {
+ if (!ignore_linereset) {
+ return -EIO;
+ }
+ } else {
+ result = -EAGAIN;
+ }
+ }
+
+ data = mmio_read_32(ufs_params.reg_base + UECDL);
+ if (data & UFS_UIC_DL_ERROR_MASK) {
+ if (data & PA_INIT_ERR) {
+ return -EIO;
+ }
+ result = -EAGAIN;
+ }
+
+ /* NL/TL/DME error requires retries */
+ data = mmio_read_32(ufs_params.reg_base + UECN);
+ if (data & UFS_UIC_NL_ERROR_MASK) {
+ result = -EAGAIN;
+ }
+
+ data = mmio_read_32(ufs_params.reg_base + UECT);
+ if (data & UFS_UIC_TL_ERROR_MASK) {
+ result = -EAGAIN;
+ }
+
+ data = mmio_read_32(ufs_params.reg_base + UECDME);
+ if (data & UFS_UIC_DME_ERROR_MASK) {
+ result = -EAGAIN;
+ }
+
+ return result;
+}
+
+/*
+ * ufs_error_handler - error interrupts handler
+ * @status: interrupt status
+ * @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
+ *
+ * Returns
+ * 0 - ignore error
+ * -EIO - fatal error, needs re-init
+ * -EAGAIN - non-fatal error, retries are sufficient
+ */
+static int ufs_error_handler(uint32_t status, bool ignore_linereset)
+{
+ int result;
+
+ if (status & UFS_INT_UE) {
+ result = ufs_uic_error_handler(ignore_linereset);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ /* Return I/O error on fatal error, it is upto the caller to re-init UFS */
+ if (status & UFS_INT_FATAL) {
+ return -EIO;
+ }
+
+ /* retry for non-fatal errors */
+ return -EAGAIN;
+}
+
+/*
+ * ufs_wait_for_int_status - wait for expected interrupt status
+ * @expected: expected interrupt status bit
+ * @timeout_ms: timeout in milliseconds to poll for
+ * @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
+ *
+ * Returns
+ * 0 - received expected interrupt and cleared it
+ * -EIO - fatal error, needs re-init
+ * -EAGAIN - non-fatal error, caller can retry
+ * -ETIMEDOUT - timed out waiting for interrupt status
+ */
+static int ufs_wait_for_int_status(const uint32_t expected_status,
+ unsigned int timeout_ms,
+ bool ignore_linereset)
+{
+ uint32_t interrupt_status, interrupts_enabled;
+ int result = 0;
+
+ interrupts_enabled = mmio_read_32(ufs_params.reg_base + IE);
+ do {
+ interrupt_status = mmio_read_32(ufs_params.reg_base + IS) & interrupts_enabled;
+ if (interrupt_status & UFS_INT_ERR) {
+ mmio_write_32(ufs_params.reg_base + IS, interrupt_status & UFS_INT_ERR);
+ result = ufs_error_handler(interrupt_status, ignore_linereset);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ if (interrupt_status & expected_status) {
+ break;
+ }
+ mdelay(1);
+ } while (timeout_ms-- > 0);
+
+ if (!(interrupt_status & expected_status)) {
+ return -ETIMEDOUT;
+ }
+
+ mmio_write_32(ufs_params.reg_base + IS, expected_status);
+
+ return result;
+}
+
+
int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
{
unsigned int data;
+ int result, retries;
- data = mmio_read_32(base + HCS);
- if ((data & HCS_UCRDY) == 0)
+ if (base == 0 || cmd == NULL)
+ return -EINVAL;
+
+ for (retries = 0; retries < 100; retries++) {
+ data = mmio_read_32(base + HCS);
+ if ((data & HCS_UCRDY) != 0) {
+ break;
+ }
+ mdelay(1);
+ }
+ if (retries >= 100) {
return -EBUSY;
+ }
+
mmio_write_32(base + IS, ~0);
mmio_write_32(base + UCMDARG1, cmd->arg1);
mmio_write_32(base + UCMDARG2, cmd->arg2);
mmio_write_32(base + UCMDARG3, cmd->arg3);
mmio_write_32(base + UICCMD, cmd->op);
- do {
- data = mmio_read_32(base + IS);
- } while ((data & UFS_INT_UCCS) == 0);
- mmio_write_32(base + IS, UFS_INT_UCCS);
+ result = ufs_wait_for_int_status(UFS_INT_UCCS, UIC_CMD_TIMEOUT_MS,
+ cmd->op == DME_SET);
+ if (result != 0) {
+ return result;
+ }
+
return mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
}
int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
{
uintptr_t base;
- unsigned int data;
- int retries;
+ int result, retries;
+ uic_cmd_t cmd;
+
+ assert(ufs_params.reg_base != 0);
- assert((ufs_params.reg_base != 0) && (val != NULL));
+ if (val == NULL)
+ return -EINVAL;
base = ufs_params.reg_base;
- for (retries = 0; retries < 100; retries++) {
- data = mmio_read_32(base + HCS);
- if ((data & HCS_UCRDY) != 0)
+ cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
+ cmd.arg2 = 0;
+ cmd.arg3 = 0;
+ cmd.op = DME_GET;
+
+ for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
+ result = ufshc_send_uic_cmd(base, &cmd);
+ if (result == 0)
break;
- mdelay(1);
+ /* -EIO requires UFS re-init */
+ if (result == -EIO) {
+ return result;
+ }
}
- if (retries >= 100)
- return -EBUSY;
-
- mmio_write_32(base + IS, ~0);
- mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
- mmio_write_32(base + UCMDARG2, 0);
- mmio_write_32(base + UCMDARG3, 0);
- mmio_write_32(base + UICCMD, DME_GET);
- do {
- data = mmio_read_32(base + IS);
- if (data & UFS_INT_UE)
- return -EINVAL;
- } while ((data & UFS_INT_UCCS) == 0);
- mmio_write_32(base + IS, UFS_INT_UCCS);
- data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
- assert(data == 0);
+ if (retries >= UFS_UIC_COMMAND_RETRIES)
+ return -EIO;
*val = mmio_read_32(base + UCMDARG3);
return 0;
@@ -89,105 +228,178 @@ int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
{
uintptr_t base;
- unsigned int data;
+ int result, retries;
+ uic_cmd_t cmd;
assert((ufs_params.reg_base != 0));
base = ufs_params.reg_base;
- data = mmio_read_32(base + HCS);
- if ((data & HCS_UCRDY) == 0)
- return -EBUSY;
- mmio_write_32(base + IS, ~0);
- mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
- mmio_write_32(base + UCMDARG2, 0);
- mmio_write_32(base + UCMDARG3, val);
- mmio_write_32(base + UICCMD, DME_SET);
- do {
- data = mmio_read_32(base + IS);
- if (data & UFS_INT_UE)
- return -EINVAL;
- } while ((data & UFS_INT_UCCS) == 0);
- mmio_write_32(base + IS, UFS_INT_UCCS);
- data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
- assert(data == 0);
+ cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
+ cmd.arg2 = 0;
+ cmd.arg3 = val;
+ cmd.op = DME_SET;
+
+ for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
+ result = ufshc_send_uic_cmd(base, &cmd);
+ if (result == 0)
+ break;
+ /* -EIO requires UFS re-init */
+ if (result == -EIO) {
+ return result;
+ }
+ }
+ if (retries >= UFS_UIC_COMMAND_RETRIES)
+ return -EIO;
+
return 0;
}
-static void ufshc_reset(uintptr_t base)
+static int ufshc_hce_enable(uintptr_t base)
{
unsigned int data;
+ int retries;
/* Enable Host Controller */
mmio_write_32(base + HCE, HCE_ENABLE);
+
/* Wait until basic initialization sequence completed */
+ for (retries = 0; retries < HCE_ENABLE_INNER_RETRIES; ++retries) {
+ data = mmio_read_32(base + HCE);
+ if (data & HCE_ENABLE) {
+ break;
+ }
+ udelay(HCE_ENABLE_TIMEOUT_US);
+ }
+ if (retries >= HCE_ENABLE_INNER_RETRIES) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int ufshc_hce_disable(uintptr_t base)
+{
+ unsigned int data;
+ int timeout;
+
+ /* Disable Host Controller */
+ mmio_write_32(base + HCE, HCE_DISABLE);
+ timeout = HCE_DISABLE_TIMEOUT_US;
do {
data = mmio_read_32(base + HCE);
- } while ((data & HCE_ENABLE) == 0);
+ if ((data & HCE_ENABLE) == HCE_DISABLE) {
+ break;
+ }
+ udelay(1);
+ } while (--timeout > 0);
+
+ if (timeout <= 0) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+
+static int ufshc_reset(uintptr_t base)
+{
+ unsigned int data;
+ int retries, result;
+
+ /* disable controller if enabled */
+ if (mmio_read_32(base + HCE) & HCE_ENABLE) {
+ result = ufshc_hce_disable(base);
+ if (result != 0) {
+ return -EIO;
+ }
+ }
+
+ for (retries = 0; retries < HCE_ENABLE_OUTER_RETRIES; ++retries) {
+ result = ufshc_hce_enable(base);
+ if (result == 0) {
+ break;
+ }
+ }
+ if (retries >= HCE_ENABLE_OUTER_RETRIES) {
+ return -EIO;
+ }
- /* Enable Interrupts */
- data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES |
- UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES;
+ /* Enable UIC Interrupts alone. We can ignore other interrupts until
+ * link is up as there might be spurious error interrupts during link-up
+ */
+ data = UFS_INT_UCCS | UFS_INT_UHES | UFS_INT_UHXS | UFS_INT_UPMS;
mmio_write_32(base + IE, data);
+
+ return 0;
}
-static int ufshc_link_startup(uintptr_t base)
+static int ufshc_dme_link_startup(uintptr_t base)
{
uic_cmd_t cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op = DME_LINKSTARTUP;
+ return ufshc_send_uic_cmd(base, &cmd);
+}
+
+static int ufshc_link_startup(uintptr_t base)
+{
int data, result;
int retries;
- for (retries = 10; retries > 0; retries--) {
- memset(&cmd, 0, sizeof(cmd));
- cmd.op = DME_LINKSTARTUP;
- result = ufshc_send_uic_cmd(base, &cmd);
- if (result != 0)
+ for (retries = DME_LINKSTARTUP_RETRIES; retries > 0; retries--) {
+ result = ufshc_dme_link_startup(base);
+ if (result != 0) {
+ /* Reset controller before trying again */
+ result = ufshc_reset(base);
+ if (result != 0) {
+ return result;
+ }
continue;
- while ((mmio_read_32(base + HCS) & HCS_DP) == 0)
- ;
+ }
+ assert(mmio_read_32(base + HCS) & HCS_DP);
data = mmio_read_32(base + IS);
if (data & UFS_INT_ULSS)
mmio_write_32(base + IS, UFS_INT_ULSS);
+
+ /* clear UE set due to line-reset */
+ if (data & UFS_INT_UE) {
+ mmio_write_32(base + IS, UFS_INT_UE);
+ }
+ /* clearing line-reset, UECPA is cleared on read */
+ mmio_read_32(base + UECPA);
return 0;
}
return -EIO;
}
-/* Check Door Bell register to get an empty slot */
-static int get_empty_slot(int *slot)
+/* Read Door Bell register to check if slot zero is available */
+static int is_slot_available(void)
{
- unsigned int data;
- int i;
-
- data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
- for (i = 0; i < nutrs; i++) {
- if ((data & 1) == 0)
- break;
- data = data >> 1;
- }
- if (i >= nutrs)
+ if (mmio_read_32(ufs_params.reg_base + UTRLDBR) & 0x1) {
return -EBUSY;
- *slot = i;
+ }
return 0;
}
static void get_utrd(utp_utrd_t *utrd)
{
uintptr_t base;
- int slot = 0, result;
+ int result;
utrd_header_t *hd;
assert(utrd != NULL);
- result = get_empty_slot(&slot);
+ result = is_slot_available();
assert(result == 0);
/* clear utrd */
memset((void *)utrd, 0, sizeof(utp_utrd_t));
- base = ufs_params.desc_base + (slot * UFS_DESC_SIZE);
+ base = ufs_params.desc_base;
/* clear the descriptor */
memset((void *)base, 0, UFS_DESC_SIZE);
utrd->header = base;
- utrd->task_tag = slot + 1;
+ utrd->task_tag = 1; /* We always use the first slot */
/* CDB address should be aligned with 128 bytes */
utrd->upiu = ALIGN_CDB(utrd->header + sizeof(utrd_header_t));
utrd->resp_upiu = ALIGN_8(utrd->upiu + sizeof(cmd_upiu_t));
@@ -215,13 +427,8 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
prdt_t *prdt;
unsigned int ulba;
unsigned int lba_cnt;
- int prdt_size;
-
-
- mmio_write_32(ufs_params.reg_base + UTRLBA,
- utrd->header & UINT32_MAX);
- mmio_write_32(ufs_params.reg_base + UTRLBAU,
- (utrd->upiu >> 32) & UINT32_MAX);
+ uintptr_t desc_limit;
+ uintptr_t prdt_end;
hd = (utrd_header_t *)utrd->header;
upiu = (cmd_upiu_t *)utrd->upiu;
@@ -275,17 +482,24 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
assert(0);
break;
}
- if (hd->dd == DD_IN)
+ if (hd->dd == DD_IN) {
flush_dcache_range(buf, length);
- else if (hd->dd == DD_OUT)
+ } else if (hd->dd == DD_OUT) {
inv_dcache_range(buf, length);
+ }
+
+ utrd->prdt_length = 0;
if (length) {
upiu->exp_data_trans_len = htobe32(length);
assert(lba_cnt <= UINT16_MAX);
prdt = (prdt_t *)utrd->prdt;
- prdt_size = 0;
+ desc_limit = ufs_params.desc_base + ufs_params.desc_size;
while (length > 0) {
+ if ((uintptr_t)prdt + sizeof(prdt_t) > desc_limit) {
+ ERROR("UFS: Exceeded descriptor limit. Image is too large\n");
+ panic();
+ }
prdt->dba = (unsigned int)(buf & UINT32_MAX);
prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);
/* prdt->dbc counts from 0 */
@@ -298,15 +512,14 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
}
buf += MAX_PRDT_SIZE;
prdt++;
- prdt_size += sizeof(prdt_t);
+ utrd->prdt_length++;
}
- utrd->size_prdt = ALIGN_8(prdt_size);
- hd->prdtl = utrd->size_prdt >> 2;
+ hd->prdtl = utrd->prdt_length;
hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2;
}
- flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
- flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+ prdt_end = utrd->prdt + utrd->prdt_length * sizeof(prdt_t);
+ flush_dcache_range(utrd->header, prdt_end - utrd->header);
return 0;
}
@@ -321,18 +534,13 @@ static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn,
hd = (utrd_header_t *)utrd->header;
query_upiu = (query_upiu_t *)utrd->upiu;
- mmio_write_32(ufs_params.reg_base + UTRLBA,
- utrd->header & UINT32_MAX);
- mmio_write_32(ufs_params.reg_base + UTRLBAU,
- (utrd->header >> 32) & UINT32_MAX);
-
-
hd->i = 1;
hd->ct = CT_UFS_STORAGE;
hd->ocs = OCS_MASK;
query_upiu->trans_type = QUERY_REQUEST_UPIU;
query_upiu->task_tag = utrd->task_tag;
+ query_upiu->data_segment_len = htobe16(length);
query_upiu->ts.desc.opcode = op;
query_upiu->ts.desc.idn = idn;
query_upiu->ts.desc.index = index;
@@ -358,13 +566,12 @@ static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn,
break;
case QUERY_WRITE_ATTR:
query_upiu->query_func = QUERY_FUNC_STD_WRITE;
- memcpy((void *)&query_upiu->ts.attr.value, (void *)buf, length);
+ query_upiu->ts.attr.value = htobe32(*((uint32_t *)buf));
break;
default:
assert(0);
break;
}
- flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
return 0;
}
@@ -374,11 +581,6 @@ static void ufs_prepare_nop_out(utp_utrd_t *utrd)
utrd_header_t *hd;
nop_out_upiu_t *nop_out;
- mmio_write_32(ufs_params.reg_base + UTRLBA,
- utrd->header & UINT32_MAX);
- mmio_write_32(ufs_params.reg_base + UTRLBAU,
- (utrd->header >> 32) & UINT32_MAX);
-
hd = (utrd_header_t *)utrd->header;
nop_out = (nop_out_upiu_t *)utrd->upiu;
@@ -388,7 +590,6 @@ static void ufs_prepare_nop_out(utp_utrd_t *utrd)
nop_out->trans_type = 0;
nop_out->task_tag = utrd->task_tag;
- flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
}
@@ -402,44 +603,77 @@ static void ufs_send_request(int task_tag)
mmio_write_32(ufs_params.reg_base + IS, ~0);
mmio_write_32(ufs_params.reg_base + UTRLRSR, 1);
- do {
- data = mmio_read_32(ufs_params.reg_base + UTRLRSR);
- } while (data == 0);
+ assert(mmio_read_32(ufs_params.reg_base + UTRLRSR) == 1);
data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) |
UTRIACR_IATOVAL(0xFF);
mmio_write_32(ufs_params.reg_base + UTRIACR, data);
/* send request */
- mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
+ mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1U << slot);
}
-static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
+static int ufs_check_resp(utp_utrd_t *utrd, int trans_type, unsigned int timeout_ms)
{
utrd_header_t *hd;
resp_upiu_t *resp;
+ sense_data_t *sense;
unsigned int data;
- int slot;
+ int slot, result;
hd = (utrd_header_t *)utrd->header;
resp = (resp_upiu_t *)utrd->resp_upiu;
- inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
- inv_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
- do {
- data = mmio_read_32(ufs_params.reg_base + IS);
- if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0)
- return -EIO;
- } while ((data & UFS_INT_UTRCS) == 0);
+
+ result = ufs_wait_for_int_status(UFS_INT_UTRCS, timeout_ms, false);
+ if (result != 0) {
+ return result;
+ }
+
slot = utrd->task_tag - 1;
data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
assert((data & (1 << slot)) == 0);
+ /*
+ * Invalidate the header after DMA read operation has
+ * completed to avoid cpu referring to the prefetched
+ * data brought in before DMA completion.
+ */
+ inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
assert(hd->ocs == OCS_SUCCESS);
assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
+
+ sense = &resp->sd.sense;
+ if (sense->resp_code == SENSE_DATA_VALID &&
+ sense->sense_key == SENSE_KEY_UNIT_ATTENTION && sense->asc == 0x29 &&
+ sense->ascq == 0) {
+ WARN("Unit Attention Condition\n");
+ return -EAGAIN;
+ }
+
(void)resp;
(void)slot;
+ (void)data;
return 0;
}
+static void ufs_send_cmd(utp_utrd_t *utrd, uint8_t cmd_op, uint8_t lun, int lba, uintptr_t buf,
+ size_t length)
+{
+ int result, i;
+
+ for (i = 0; i < UFS_CMD_RETRIES; ++i) {
+ get_utrd(utrd);
+ result = ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);
+ assert(result == 0);
+ ufs_send_request(utrd->task_tag);
+ result = ufs_check_resp(utrd, RESPONSE_UPIU, CMD_TIMEOUT_MS);
+ if (result == 0 || result == -EIO) {
+ break;
+ }
+ }
+ assert(result == 0);
+ (void)result;
+}
+
#ifdef UFS_RESP_DEBUG
static void dump_upiu(utp_utrd_t *utrd)
{
@@ -482,7 +716,7 @@ static void ufs_verify_init(void)
get_utrd(&utrd);
ufs_prepare_nop_out(&utrd);
ufs_send_request(utrd.task_tag);
- result = ufs_check_resp(&utrd, NOP_IN_UPIU);
+ result = ufs_check_resp(&utrd, NOP_IN_UPIU, NOP_OUT_TIMEOUT_MS);
assert(result == 0);
(void)result;
}
@@ -490,14 +724,7 @@ static void ufs_verify_init(void)
static void ufs_verify_ready(void)
{
utp_utrd_t utrd;
- int result;
-
- get_utrd(&utrd);
- ufs_prepare_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
- ufs_send_request(utrd.task_tag);
- result = ufs_check_resp(&utrd, RESPONSE_UPIU);
- assert(result == 0);
- (void)result;
+ ufs_send_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
}
static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
@@ -522,7 +749,7 @@ static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
get_utrd(&utrd);
ufs_prepare_query(&utrd, op, idn, index, sel, buf, size);
ufs_send_request(utrd.task_tag);
- result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU);
+ result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU, QUERY_REQ_TIMEOUT_MS);
assert(result == 0);
resp = (query_resp_upiu_t *)utrd.resp_upiu;
#ifdef UFS_RESP_DEBUG
@@ -534,12 +761,14 @@ static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
case QUERY_READ_FLAG:
*(uint32_t *)buf = (uint32_t)resp->ts.flag.value;
break;
- case QUERY_READ_ATTR:
case QUERY_READ_DESC:
memcpy((void *)buf,
(void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)),
size);
break;
+ case QUERY_READ_ATTR:
+ *(uint32_t *)buf = htobe32(resp->ts.attr.value);
+ break;
default:
/* Do nothing in default case */
break;
@@ -591,15 +820,14 @@ void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size)
ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
}
-static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
+static int ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
{
utp_utrd_t utrd;
resp_upiu_t *resp;
sense_data_t *sense;
unsigned char data[CACHE_WRITEBACK_GRANULE << 1];
uintptr_t buf;
- int result;
- int retry;
+ int retries = UFS_READ_CAPACITY_RETRIES;
assert((ufs_params.reg_base != 0) &&
(ufs_params.desc_base != 0) &&
@@ -610,59 +838,52 @@ static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
buf = (uintptr_t)data;
buf = (buf + CACHE_WRITEBACK_GRANULE - 1) &
~(CACHE_WRITEBACK_GRANULE - 1);
- memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE);
- flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
do {
- get_utrd(&utrd);
- ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
- buf, READ_CAPACITY_LENGTH);
- ufs_send_request(utrd.task_tag);
- result = ufs_check_resp(&utrd, RESPONSE_UPIU);
- assert(result == 0);
+ ufs_send_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
+ buf, READ_CAPACITY_LENGTH);
#ifdef UFS_RESP_DEBUG
dump_upiu(&utrd);
#endif
resp = (resp_upiu_t *)utrd.resp_upiu;
- retry = 0;
sense = &resp->sd.sense;
- if (sense->resp_code == SENSE_DATA_VALID) {
- if ((sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
- (sense->asc == 0x29) && (sense->ascq == 0)) {
- retry = 1;
- }
+ if (!((sense->resp_code == SENSE_DATA_VALID) &&
+ (sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
+ (sense->asc == 0x29) && (sense->ascq == 0))) {
+ inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
+ /* last logical block address */
+ *num = be32toh(*(unsigned int *)buf);
+ if (*num)
+ *num += 1;
+ /* logical block length in bytes */
+ *size = be32toh(*(unsigned int *)(buf + 4));
+
+ return 0;
}
- inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
- /* last logical block address */
- *num = be32toh(*(unsigned int *)buf);
- if (*num)
- *num += 1;
- /* logical block length in bytes */
- *size = be32toh(*(unsigned int *)(buf + 4));
- } while (retry);
- (void)result;
+
+ } while (retries-- > 0);
+
+ return -ETIMEDOUT;
}
size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
{
utp_utrd_t utrd;
resp_upiu_t *resp;
- int result;
assert((ufs_params.reg_base != 0) &&
(ufs_params.desc_base != 0) &&
(ufs_params.desc_size >= UFS_DESC_SIZE));
- memset((void *)buf, 0, size);
- get_utrd(&utrd);
- ufs_prepare_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
- ufs_send_request(utrd.task_tag);
- result = ufs_check_resp(&utrd, RESPONSE_UPIU);
- assert(result == 0);
+ ufs_send_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
#ifdef UFS_RESP_DEBUG
dump_upiu(&utrd);
#endif
+ /*
+ * Invalidate prefetched cache contents before cpu
+ * accesses the buf.
+ */
+ inv_dcache_range(buf, size);
resp = (resp_upiu_t *)utrd.resp_upiu;
- (void)result;
return size - resp->res_trans_cnt;
}
@@ -670,57 +891,82 @@ size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size)
{
utp_utrd_t utrd;
resp_upiu_t *resp;
- int result;
assert((ufs_params.reg_base != 0) &&
(ufs_params.desc_base != 0) &&
(ufs_params.desc_size >= UFS_DESC_SIZE));
- memset((void *)buf, 0, size);
- get_utrd(&utrd);
- ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
- ufs_send_request(utrd.task_tag);
- result = ufs_check_resp(&utrd, RESPONSE_UPIU);
- assert(result == 0);
+ ufs_send_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
#ifdef UFS_RESP_DEBUG
dump_upiu(&utrd);
#endif
resp = (resp_upiu_t *)utrd.resp_upiu;
- (void)result;
return size - resp->res_trans_cnt;
}
+static int ufs_set_fdevice_init(void)
+{
+ unsigned int result;
+ int timeout;
+
+ ufs_set_flag(FLAG_DEVICE_INIT);
+
+ timeout = FDEVICEINIT_TIMEOUT_MS;
+ do {
+ result = ufs_read_flag(FLAG_DEVICE_INIT);
+ if (!result) {
+ break;
+ }
+ mdelay(5);
+ timeout -= 5;
+ } while (timeout > 0);
+
+ if (result != 0U) {
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static void ufs_enum(void)
{
unsigned int blk_num, blk_size;
- int i;
+ int i, result;
- /* 0 means 1 slot */
- nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
- if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE))
- nutrs = ufs_params.desc_size / UFS_DESC_SIZE;
+ mmio_write_32(ufs_params.reg_base + UTRLBA,
+ ufs_params.desc_base & UINT32_MAX);
+ mmio_write_32(ufs_params.reg_base + UTRLBAU,
+ (ufs_params.desc_base >> 32) & UINT32_MAX);
ufs_verify_init();
ufs_verify_ready();
- ufs_set_flag(FLAG_DEVICE_INIT);
- mdelay(200);
+ result = ufs_set_fdevice_init();
+ assert(result == 0);
+
+ blk_num = 0;
+ blk_size = 0;
+
/* dump available LUNs */
for (i = 0; i < UFS_MAX_LUNS; i++) {
- ufs_read_capacity(i, &blk_num, &blk_size);
+ result = ufs_read_capacity(i, &blk_num, &blk_size);
+ if (result != 0) {
+ WARN("UFS LUN%d dump failed\n", i);
+ }
if (blk_num && blk_size) {
INFO("UFS LUN%d contains %d blocks with %d-byte size\n",
i, blk_num, blk_size);
}
}
+
+ (void)result;
}
static void ufs_get_device_info(struct ufs_dev_desc *card_data)
{
uint8_t desc_buf[DESC_DEVICE_MAX_SIZE];
- ufs_query(QUERY_READ_DESC, DESC_TYPE_DEVICE, 0, 0,
- (uintptr_t)desc_buf, DESC_DEVICE_MAX_SIZE);
+ ufs_read_desc(DESC_TYPE_DEVICE, 0, (uintptr_t)desc_buf, DESC_DEVICE_MAX_SIZE);
/*
* getting vendor (manufacturerID) and Bank Index in big endian
@@ -744,7 +990,19 @@ int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
memcpy(&ufs_params, params, sizeof(ufs_params_t));
+ /* 0 means 1 slot */
+ nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
+ if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE)) {
+ nutrs = ufs_params.desc_size / UFS_DESC_SIZE;
+ }
+
+
if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {
+ mmio_write_32(ufs_params.reg_base + UTRLBA,
+ ufs_params.desc_base & UINT32_MAX);
+ mmio_write_32(ufs_params.reg_base + UTRLBAU,
+ (ufs_params.desc_base >> 32) & UINT32_MAX);
+
result = ufshc_dme_get(0x1571, 0, &data);
assert(result == 0);
result = ufshc_dme_get(0x41, 0, &data);
@@ -772,11 +1030,17 @@ int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
assert((ops != NULL) && (ops->phy_init != NULL) &&
(ops->phy_set_pwr_mode != NULL));
- ufshc_reset(ufs_params.reg_base);
+ result = ufshc_reset(ufs_params.reg_base);
+ assert(result == 0);
ops->phy_init(&ufs_params);
result = ufshc_link_startup(ufs_params.reg_base);
assert(result == 0);
+ /* enable all interrupts */
+ data = UFS_INT_UCCS | UFS_INT_UHES | UFS_INT_UHXS | UFS_INT_UPMS;
+ data |= UFS_INT_UTRCS | UFS_INT_ERR;
+ mmio_write_32(ufs_params.reg_base + IE, data);
+
ufs_enum();
ufs_get_device_info(&card);
diff --git a/drivers/usb/usb_device.c b/drivers/usb/usb_device.c
new file mode 100644
index 0000000000..701f301208
--- /dev/null
+++ b/drivers/usb/usb_device.c
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/usb_device.h>
+
+/* Define for EP address */
+#define EP_DIR_MASK BIT(7)
+#define EP_DIR_IN BIT(7)
+#define EP_NUM_MASK GENMASK(3, 0)
+
+#define EP0_IN (0U | EP_DIR_IN)
+#define EP0_OUT 0U
+
+/* USB address between 1 through 127 = 0x7F mask */
+#define ADDRESS_MASK GENMASK(6, 0)
+
+/*
+ * Set a STALL condition over an endpoint
+ * pdev: USB handle
+ * ep_addr: endpoint address
+ * return : status
+ */
+static enum usb_status usb_core_set_stall(struct usb_handle *pdev, uint8_t ep_addr)
+{
+ struct usbd_ep *ep;
+ struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
+ uint8_t num;
+
+ num = ep_addr & EP_NUM_MASK;
+ if (num >= USBD_EP_NB) {
+ return USBD_FAIL;
+ }
+ if ((EP_DIR_MASK & ep_addr) == EP_DIR_IN) {
+ ep = &hpcd->in_ep[num];
+ ep->is_in = true;
+ } else {
+ ep = &hpcd->out_ep[num];
+ ep->is_in = false;
+ }
+ ep->num = num;
+
+ pdev->driver->ep_set_stall(hpcd->instance, ep);
+ if (num == 0U) {
+ pdev->driver->ep0_out_start(hpcd->instance);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_get_desc
+ * Handle Get Descriptor requests
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_get_desc(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ uint16_t len;
+ uint8_t *pbuf;
+ uint8_t desc_type = HIBYTE(req->value);
+ uint8_t desc_idx = LOBYTE(req->value);
+
+ switch (desc_type) {
+ case USB_DESC_TYPE_DEVICE:
+ pbuf = pdev->desc->get_device_desc(&len);
+ break;
+
+ case USB_DESC_TYPE_CONFIGURATION:
+ pbuf = pdev->desc->get_config_desc(&len);
+ break;
+
+ case USB_DESC_TYPE_STRING:
+ switch (desc_idx) {
+ case USBD_IDX_LANGID_STR:
+ pbuf = pdev->desc->get_lang_id_desc(&len);
+ break;
+
+ case USBD_IDX_MFC_STR:
+ pbuf = pdev->desc->get_manufacturer_desc(&len);
+ break;
+
+ case USBD_IDX_PRODUCT_STR:
+ pbuf = pdev->desc->get_product_desc(&len);
+ break;
+
+ case USBD_IDX_SERIAL_STR:
+ pbuf = pdev->desc->get_serial_desc(&len);
+ break;
+
+ case USBD_IDX_CONFIG_STR:
+ pbuf = pdev->desc->get_configuration_desc(&len);
+ break;
+
+ case USBD_IDX_INTERFACE_STR:
+ pbuf = pdev->desc->get_interface_desc(&len);
+ break;
+
+ /* For all USER string */
+ case USBD_IDX_USER0_STR:
+ default:
+ pbuf = pdev->desc->get_usr_desc(desc_idx - USBD_IDX_USER0_STR, &len);
+ break;
+ }
+ break;
+
+ case USB_DESC_TYPE_DEVICE_QUALIFIER:
+ pbuf = pdev->desc->get_device_qualifier_desc(&len);
+ break;
+
+ case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
+ if (pdev->desc->get_other_speed_config_desc == NULL) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ pbuf = pdev->desc->get_other_speed_config_desc(&len);
+ break;
+
+ default:
+ ERROR("Unknown request %i\n", desc_type);
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ if ((len != 0U) && (req->length != 0U)) {
+ len = MIN(len, req->length);
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, pbuf, len);
+ }
+}
+
+/*
+ * usb_core_set_config
+ * Handle Set device configuration request
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_set_config(struct usb_handle *pdev, struct usb_setup_req *req)
+{
+ static uint8_t cfgidx;
+
+ cfgidx = LOBYTE(req->value);
+
+ if (cfgidx > USBD_MAX_NUM_CONFIGURATION) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ switch (pdev->dev_state) {
+ case USBD_STATE_ADDRESSED:
+ if (cfgidx != 0U) {
+ pdev->dev_config = cfgidx;
+ pdev->dev_state = USBD_STATE_CONFIGURED;
+ if (!pdev->class) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ /* Set configuration and Start the Class */
+ if (pdev->class->init(pdev, cfgidx) != 0U) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ }
+ break;
+
+ case USBD_STATE_CONFIGURED:
+ if (cfgidx == 0U) {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ pdev->dev_config = cfgidx;
+ pdev->class->de_init(pdev, cfgidx);
+ } else if (cfgidx != pdev->dev_config) {
+ if (pdev->class == NULL) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ /* Clear old configuration */
+ pdev->class->de_init(pdev, pdev->dev_config);
+ /* Set new configuration */
+ pdev->dev_config = cfgidx;
+ /* Set configuration and start the USB class */
+ if (pdev->class->init(pdev, cfgidx) != 0U) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+ }
+ break;
+
+ default:
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ /* Send status */
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+}
+
+/*
+ * usb_core_get_status
+ * Handle Get Status request
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_get_status(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ if ((pdev->dev_state != USBD_STATE_ADDRESSED) &&
+ (pdev->dev_state != USBD_STATE_CONFIGURED)) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
+
+ if (pdev->dev_remote_wakeup != 0U) {
+ pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
+ }
+
+ /* Start the transfer */
+ usb_core_transmit_ep0(pdev, (uint8_t *)&pdev->dev_config_status, 2U);
+}
+
+/*
+ * usb_core_set_address
+ * Set device address
+ * pdev : device instance
+ * req : usb request
+ */
+static void usb_core_set_address(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ uint8_t dev_addr;
+
+ if ((req->index != 0U) || (req->length != 0U)) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ dev_addr = req->value & ADDRESS_MASK;
+ if (pdev->dev_state != USBD_STATE_DEFAULT) {
+ usb_core_ctl_error(pdev);
+ return;
+ }
+
+ pdev->dev_address = dev_addr;
+ pdev->driver->set_address(((struct pcd_handle *)(pdev->data))->instance, dev_addr);
+
+ /* Send status */
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+
+ if (dev_addr != 0U) {
+ pdev->dev_state = USBD_STATE_ADDRESSED;
+ } else {
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ }
+}
+
+/*
+ * usb_core_dev_req
+ * Handle standard usb device requests
+ * pdev : device instance
+ * req : usb request
+ * return : status
+ */
+static enum usb_status usb_core_dev_req(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ VERBOSE("receive request %i\n", req->b_request);
+ switch (req->b_request) {
+ case USB_REQ_GET_DESCRIPTOR:
+ usb_core_get_desc(pdev, req);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ usb_core_set_config(pdev, req);
+ break;
+
+ case USB_REQ_GET_STATUS:
+ usb_core_get_status(pdev, req);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ usb_core_set_address(pdev, req);
+ break;
+
+ case USB_REQ_GET_CONFIGURATION:
+ case USB_REQ_SET_FEATURE:
+ case USB_REQ_CLEAR_FEATURE:
+ default:
+ ERROR("NOT SUPPORTED %i\n", req->b_request);
+ usb_core_ctl_error(pdev);
+ break;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_itf_req
+ * Handle standard usb interface requests
+ * pdev : device instance
+ * req : usb request
+ * return : status
+ */
+static enum usb_status usb_core_itf_req(struct usb_handle *pdev,
+ struct usb_setup_req *req)
+{
+ if (pdev->dev_state != USBD_STATE_CONFIGURED) {
+ usb_core_ctl_error(pdev);
+ return USBD_OK;
+ }
+
+ if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) {
+ pdev->class->setup(pdev, req);
+
+ if (req->length == 0U) {
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+ }
+ } else {
+ usb_core_ctl_error(pdev);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_setup_stage
+ * Handle the setup stage
+ * pdev: device instance
+ * psetup : setup buffer
+ * return : status
+ */
+static enum usb_status usb_core_setup_stage(struct usb_handle *pdev,
+ uint8_t *psetup)
+{
+ struct usb_setup_req *req = &pdev->request;
+
+ /* Copy setup buffer into req structure */
+ req->bm_request = psetup[0];
+ req->b_request = psetup[1];
+ req->value = psetup[2] + (psetup[3] << 8);
+ req->index = psetup[4] + (psetup[5] << 8);
+ req->length = psetup[6] + (psetup[7] << 8);
+
+ pdev->ep0_state = USBD_EP0_SETUP;
+ pdev->ep0_data_len = pdev->request.length;
+
+ switch (pdev->request.bm_request & USB_REQ_RECIPIENT_MASK) {
+ case USB_REQ_RECIPIENT_DEVICE:
+ usb_core_dev_req(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ usb_core_itf_req(pdev, &pdev->request);
+ break;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ default:
+ ERROR("receive unsupported request %u",
+ pdev->request.bm_request & USB_REQ_RECIPIENT_MASK);
+ usb_core_set_stall(pdev, pdev->request.bm_request & USB_REQ_DIRECTION);
+ return USBD_FAIL;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_data_out
+ * Handle data OUT stage
+ * pdev: device instance
+ * epnum: endpoint index
+ * pdata: buffer to sent
+ * return : status
+ */
+static enum usb_status usb_core_data_out(struct usb_handle *pdev, uint8_t epnum,
+ uint8_t *pdata)
+{
+ struct usb_endpoint *pep;
+
+ if (epnum == 0U) {
+ pep = &pdev->ep_out[0];
+ if (pdev->ep0_state == USBD_EP0_DATA_OUT) {
+ if (pep->rem_length > pep->maxpacket) {
+ pep->rem_length -= pep->maxpacket;
+
+ usb_core_receive(pdev, 0U, pdata,
+ MIN(pep->rem_length,
+ pep->maxpacket));
+ } else {
+ if (pdev->class->ep0_rx_ready &&
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
+ pdev->class->ep0_rx_ready(pdev);
+ }
+
+ usb_core_transmit_ep0(pdev, NULL, 0U);
+ }
+ }
+ } else if (pdev->class->data_out != NULL &&
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
+ pdev->class->data_out(pdev, epnum);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_data_in
+ * Handle data in stage
+ * pdev: device instance
+ * epnum: endpoint index
+ * pdata: buffer to fill
+ * return : status
+ */
+static enum usb_status usb_core_data_in(struct usb_handle *pdev, uint8_t epnum,
+ uint8_t *pdata)
+{
+ if (epnum == 0U) {
+ struct usb_endpoint *pep = &pdev->ep_in[0];
+
+ if (pdev->ep0_state == USBD_EP0_DATA_IN) {
+ if (pep->rem_length > pep->maxpacket) {
+ pep->rem_length -= pep->maxpacket;
+
+ usb_core_transmit(pdev, 0U, pdata,
+ pep->rem_length);
+
+ /* Prepare EP for premature end of transfer */
+ usb_core_receive(pdev, 0U, NULL, 0U);
+ } else {
+ /* Last packet is MPS multiple, send ZLP packet */
+ if ((pep->total_length % pep->maxpacket == 0U) &&
+ (pep->total_length >= pep->maxpacket) &&
+ (pep->total_length < pdev->ep0_data_len)) {
+ usb_core_transmit(pdev, 0U, NULL, 0U);
+
+ pdev->ep0_data_len = 0U;
+
+ /* Prepare endpoint for premature end of transfer */
+ usb_core_receive(pdev, 0U, NULL, 0U);
+ } else {
+ if (pdev->class->ep0_tx_sent != NULL &&
+ (pdev->dev_state ==
+ USBD_STATE_CONFIGURED)) {
+ pdev->class->ep0_tx_sent(pdev);
+ }
+ /* Start the transfer */
+ usb_core_receive_ep0(pdev, NULL, 0U);
+ }
+ }
+ }
+ } else if ((pdev->class->data_in != NULL) &&
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
+ pdev->class->data_in(pdev, epnum);
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_suspend
+ * Handle suspend event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_suspend(struct usb_handle *pdev)
+{
+ INFO("USB Suspend mode\n");
+ pdev->dev_old_state = pdev->dev_state;
+ pdev->dev_state = USBD_STATE_SUSPENDED;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_resume
+ * Handle resume event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_resume(struct usb_handle *pdev)
+{
+ INFO("USB Resume\n");
+ pdev->dev_state = pdev->dev_old_state;
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_sof
+ * Handle SOF event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_sof(struct usb_handle *pdev)
+{
+ if (pdev->dev_state == USBD_STATE_CONFIGURED) {
+ if (pdev->class->sof != NULL) {
+ pdev->class->sof(pdev);
+ }
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_disconnect
+ * Handle device disconnection event
+ * pdev : device instance
+ * return : status
+ */
+static enum usb_status usb_core_disconnect(struct usb_handle *pdev)
+{
+ /* Free class resources */
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->class->de_init(pdev, pdev->dev_config);
+
+ return USBD_OK;
+}
+
+enum usb_status usb_core_handle_it(struct usb_handle *pdev)
+{
+ uint32_t param = 0U;
+ uint32_t len = 0U;
+ struct usbd_ep *ep;
+
+ switch (pdev->driver->it_handler(pdev->data->instance, &param)) {
+ case USB_DATA_OUT:
+ usb_core_data_out(pdev, param,
+ pdev->data->out_ep[param].xfer_buff);
+ break;
+
+ case USB_DATA_IN:
+ usb_core_data_in(pdev, param,
+ pdev->data->in_ep[param].xfer_buff);
+ break;
+
+ case USB_SETUP:
+ usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup);
+ break;
+
+ case USB_ENUM_DONE:
+ break;
+
+ case USB_READ_DATA_PACKET:
+ ep = &pdev->data->out_ep[param & USBD_OUT_EPNUM_MASK];
+ len = (param & USBD_OUT_COUNT_MASK) >> USBD_OUT_COUNT_SHIFT;
+ pdev->driver->read_packet(pdev->data->instance,
+ ep->xfer_buff, len);
+ ep->xfer_buff += len;
+ ep->xfer_count += len;
+ break;
+
+ case USB_READ_SETUP_PACKET:
+ ep = &pdev->data->out_ep[param & USBD_OUT_EPNUM_MASK];
+ len = (param & USBD_OUT_COUNT_MASK) >> 0x10;
+ pdev->driver->read_packet(pdev->data->instance,
+ (uint8_t *)pdev->data->setup, 8);
+ ep->xfer_count += len;
+ break;
+
+ case USB_RESET:
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ break;
+
+ case USB_RESUME:
+ if (pdev->data->lpm_state == LPM_L1) {
+ pdev->data->lpm_state = LPM_L0;
+ } else {
+ usb_core_resume(pdev);
+ }
+ break;
+
+ case USB_SUSPEND:
+ usb_core_suspend(pdev);
+ break;
+
+ case USB_LPM:
+ if (pdev->data->lpm_state == LPM_L0) {
+ pdev->data->lpm_state = LPM_L1;
+ } else {
+ usb_core_suspend(pdev);
+ }
+ break;
+
+ case USB_SOF:
+ usb_core_sof(pdev);
+ break;
+
+ case USB_DISCONNECT:
+ usb_core_disconnect(pdev);
+ break;
+
+ case USB_WRITE_EMPTY:
+ pdev->driver->write_empty_tx_fifo(pdev->data->instance, param,
+ pdev->data->in_ep[param].xfer_len,
+ (uint32_t *)&pdev->data->in_ep[param].xfer_count,
+ pdev->data->in_ep[param].maxpacket,
+ &pdev->data->in_ep[param].xfer_buff);
+ break;
+
+ case USB_NOTHING:
+ default:
+ break;
+ }
+
+ return USBD_OK;
+}
+
+static void usb_core_start_xfer(struct usb_handle *pdev,
+ void *handle,
+ struct usbd_ep *ep)
+{
+ if (ep->num == 0U) {
+ pdev->driver->ep0_start_xfer(handle, ep);
+ } else {
+ pdev->driver->ep_start_xfer(handle, ep);
+ }
+}
+
+/*
+ * usb_core_receive
+ * Receive an amount of data
+ * pdev: USB handle
+ * ep_addr: endpoint address
+ * buf: pointer to the reception buffer
+ * len: amount of data to be received
+ * return : status
+ */
+enum usb_status usb_core_receive(struct usb_handle *pdev, uint8_t ep_addr,
+ uint8_t *buf, uint32_t len)
+{
+ struct usbd_ep *ep;
+ struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
+ uint8_t num;
+
+ num = ep_addr & EP_NUM_MASK;
+ if (num >= USBD_EP_NB) {
+ return USBD_FAIL;
+ }
+ ep = &hpcd->out_ep[num];
+
+ /* Setup and start the Xfer */
+ ep->xfer_buff = buf;
+ ep->xfer_len = len;
+ ep->xfer_count = 0U;
+ ep->is_in = false;
+ ep->num = num;
+
+ usb_core_start_xfer(pdev, hpcd->instance, ep);
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_transmit
+ * Send an amount of data
+ * pdev: USB handle
+ * ep_addr: endpoint address
+ * buf: pointer to the transmission buffer
+ * len: amount of data to be sent
+ * return : status
+ */
+enum usb_status usb_core_transmit(struct usb_handle *pdev, uint8_t ep_addr,
+ uint8_t *buf, uint32_t len)
+{
+ struct usbd_ep *ep;
+ struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
+ uint8_t num;
+
+ num = ep_addr & EP_NUM_MASK;
+ if (num >= USBD_EP_NB) {
+ return USBD_FAIL;
+ }
+ ep = &hpcd->in_ep[num];
+
+ /* Setup and start the Xfer */
+ ep->xfer_buff = buf;
+ ep->xfer_len = len;
+ ep->xfer_count = 0U;
+ ep->is_in = true;
+ ep->num = num;
+
+ usb_core_start_xfer(pdev, hpcd->instance, ep);
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_receive_ep0
+ * Receive an amount of data on ep0
+ * pdev: USB handle
+ * buf: pointer to the reception buffer
+ * len: amount of data to be received
+ * return : status
+ */
+enum usb_status usb_core_receive_ep0(struct usb_handle *pdev, uint8_t *buf,
+ uint32_t len)
+{
+ /* Prepare the reception of the buffer over EP0 */
+ if (len != 0U) {
+ pdev->ep0_state = USBD_EP0_DATA_OUT;
+ } else {
+ pdev->ep0_state = USBD_EP0_STATUS_OUT;
+ }
+
+ pdev->ep_out[0].total_length = len;
+ pdev->ep_out[0].rem_length = len;
+
+ /* Start the transfer */
+ return usb_core_receive(pdev, 0U, buf, len);
+}
+
+/*
+ * usb_core_transmit_ep0
+ * Send an amount of data on ep0
+ * pdev: USB handle
+ * buf: pointer to the transmission buffer
+ * len: amount of data to be sent
+ * return : status
+ */
+enum usb_status usb_core_transmit_ep0(struct usb_handle *pdev, uint8_t *buf,
+ uint32_t len)
+{
+ /* Set EP0 State */
+ if (len != 0U) {
+ pdev->ep0_state = USBD_EP0_DATA_IN;
+ } else {
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
+ }
+
+ pdev->ep_in[0].total_length = len;
+ pdev->ep_in[0].rem_length = len;
+
+ /* Start the transfer */
+ return usb_core_transmit(pdev, 0U, buf, len);
+}
+
+/*
+ * usb_core_ctl_error
+ * Handle USB low level error
+ * pdev: device instance
+ * req: usb request
+ * return : None
+ */
+
+void usb_core_ctl_error(struct usb_handle *pdev)
+{
+ ERROR("%s : Send an ERROR\n", __func__);
+ usb_core_set_stall(pdev, EP0_IN);
+ usb_core_set_stall(pdev, EP0_OUT);
+}
+
+/*
+ * usb_core_start
+ * Start the USB device core.
+ * pdev: Device Handle
+ * return : USBD Status
+ */
+enum usb_status usb_core_start(struct usb_handle *pdev)
+{
+ /* Start the low level driver */
+ pdev->driver->start_device(pdev->data->instance);
+
+ return USBD_OK;
+}
+
+/*
+ * usb_core_stop
+ * Stop the USB device core.
+ * pdev: Device Handle
+ * return : USBD Status
+ */
+enum usb_status usb_core_stop(struct usb_handle *pdev)
+{
+ /* Free class resources */
+ pdev->class->de_init(pdev, pdev->dev_config);
+
+ /* Stop the low level driver */
+ pdev->driver->stop_device(pdev->data->instance);
+
+ return USBD_OK;
+}
+
+/*
+ * register_usb_driver
+ * Stop the USB device core.
+ * pdev: Device Handle
+ * pcd_handle: PCD handle
+ * driver: USB driver
+ * driver_handle: USB driver handle
+ * return : USBD Status
+ */
+enum usb_status register_usb_driver(struct usb_handle *pdev,
+ struct pcd_handle *pcd_handle,
+ const struct usb_driver *driver,
+ void *driver_handle)
+{
+ uint8_t i;
+
+ assert(pdev != NULL);
+ assert(pcd_handle != NULL);
+ assert(driver != NULL);
+ assert(driver_handle != NULL);
+
+ /* Free class resources */
+ pdev->driver = driver;
+ pdev->data = pcd_handle;
+ pdev->data->instance = driver_handle;
+ pdev->dev_state = USBD_STATE_DEFAULT;
+ pdev->ep0_state = USBD_EP0_IDLE;
+
+ /* Copy endpoint information */
+ for (i = 0U; i < USBD_EP_NB; i++) {
+ pdev->ep_in[i].maxpacket = pdev->data->in_ep[i].maxpacket;
+ pdev->ep_out[i].maxpacket = pdev->data->out_ep[i].maxpacket;
+ }
+
+ return USBD_OK;
+}
+
+/*
+ * register_platform
+ * Register the USB device core.
+ * pdev: Device Handle
+ * plat_call_back: callback
+ * return : USBD Status
+ */
+enum usb_status register_platform(struct usb_handle *pdev,
+ const struct usb_desc *plat_call_back)
+{
+ assert(pdev != NULL);
+ assert(plat_call_back != NULL);
+
+ /* Save platform info in class resources */
+ pdev->desc = plat_call_back;
+
+ return USBD_OK;
+}