diff options
Diffstat (limited to 'drivers')
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, ¶m_ptr, ¶m_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, ¶ms); - 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(¶ms, &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, ¶ms); - 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, ¶ms); - 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(¶ms, &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, ¶ms); - 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, ¶ms); 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, ¶ms); + 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)¤t_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(®s->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(®_lock); +} + +void stm32mp1_clk_rcc_regs_unlock(void) +{ + stm32mp1_clk_unlock(®_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 *)¤t_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, ¶m)) { + 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; +} |