diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c index c361270..2f4228f 100644 --- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c @@ -44,19 +44,10 @@ { unsigned int ver = zynqmp_get_silicon_ver(); - switch (ver) { - case ZYNQMP_CSU_VERSION_VELOCE: - return 48000; - case ZYNQMP_CSU_VERSION_EP108: - return 25000000; - case ZYNQMP_CSU_VERSION_QEMU: + if (ver == ZYNQMP_CSU_VERSION_QEMU) return 133000000; - default: - /* Do nothing in default case */ - break; - } - - return 100000000; + else + return 100000000; } #if LOG_LEVEL >= LOG_LEVEL_NOTICE @@ -298,12 +289,6 @@ char *label = "Unknown"; switch (ver) { - case ZYNQMP_CSU_VERSION_VELOCE: - label = "VELOCE"; - break; - case ZYNQMP_CSU_VERSION_EP108: - label = "EP108"; - break; case ZYNQMP_CSU_VERSION_QEMU: label = "QEMU"; break; @@ -346,17 +331,8 @@ { unsigned int ver = zynqmp_get_silicon_ver(); - switch (ver) { - case ZYNQMP_CSU_VERSION_VELOCE: - return 10000; - case ZYNQMP_CSU_VERSION_EP108: - return 4000000; - case ZYNQMP_CSU_VERSION_QEMU: + if (ver == ZYNQMP_CSU_VERSION_QEMU) return 50000000; - default: - /* Do nothing in default case */ - break; - } - - return mmio_read_32(IOU_SCNTRS_BASEFREQ); + else + return mmio_read_32(IOU_SCNTRS_BASEFREQ); } diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk index 3ac9db9..f806d46 100644 --- a/plat/xilinx/zynqmp/platform.mk +++ b/plat/xilinx/zynqmp/platform.mk @@ -17,6 +17,10 @@ WORKAROUND_CVE_2017_5715 := 0 +ARM_XLAT_TABLES_LIB_V1 := 1 +$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1)) +$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1)) + ifdef ZYNQMP_ATF_MEM_BASE $(eval $(call add_define,ZYNQMP_ATF_MEM_BASE)) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c index fefd9ea..b175b78 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c @@ -25,7 +25,6 @@ #define CLK_TOPOLOGY_NODE_OFFSET U(16) #define CLK_TOPOLOGY_PAYLOAD_LEN U(12) #define CLK_PARENTS_PAYLOAD_LEN U(12) -#define CLK_INIT_ENABLE_SHIFT U(1) #define CLK_TYPE_SHIFT U(2) #define CLK_CLKFLAGS_SHIFT U(8) #define CLK_TYPEFLAGS_SHIFT U(24) @@ -337,7 +336,8 @@ .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | - CLK_IS_BASIC, + CLK_IS_BASIC | + CLK_IS_CRITICAL, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, @@ -496,7 +496,7 @@ .type = TYPE_DIV1, .offset = 8, .width = 6, - .clkflags = CLK_IS_BASIC, + .clkflags = CLK_IS_BASIC | CLK_IS_CRITICAL, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, @@ -2022,12 +2022,11 @@ }, [CLK_WDT] = { .name = "wdt", - .control_reg = IOU_SLCR_WDT_CLK_SEL, + .control_reg = FPD_SLCR_WDT_CLK_SEL, .status_reg = 0, .parents = &((int32_t []) { CLK_TOPSW_LSBUS, EXT_CLK_SWDT0 | CLK_EXTERNAL_PARENT, - EXT_CLK_SWDT1 | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &wdt_nodes, @@ -2243,12 +2242,6 @@ /* Array of clock which are invalid for this variant */ static uint32_t pm_clk_invalid_list[] = {CLK_USB0, CLK_USB1, CLK_CSU_SPB}; -/* Array of clocks which needs to be enabled at init */ -static uint32_t pm_clk_init_enable_list[] = { - CLK_ACPU, - CLK_DDR_REF, -}; - /** * pm_clock_valid - Check if clock is valid or not * @clock_id Id of the clock to be queried @@ -2273,26 +2266,6 @@ } /** - * pm_clock_init_enable - Check if clock needs to be enabled at init - * @clock_id Id of the clock to be queried - * - * This function is used to check if given clock needs to be enabled - * at boot up or not. Some clocks needs to be enabled at init. - * - * Return: Returns 1 if clock needs to be enabled at boot up else 0. - */ -static unsigned int pm_clock_init_enable(unsigned int clock_id) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(pm_clk_init_enable_list); i++) - if (pm_clk_init_enable_list[i] == clock_id) - return 1; - - return 0; -} - -/** * pm_clock_type - Get clock's type * @clock_id Id of the clock to be queried * @@ -2509,9 +2482,6 @@ /* Clock valid bit */ *attr = pm_clock_valid(clock_id); - /* If clock needs to be enabled during init */ - *attr |= (pm_clock_init_enable(clock_id) << CLK_INIT_ENABLE_SHIFT); - /* Clock type (Output/External) */ *attr |= (pm_clock_type(clock_id) << CLK_TYPE_SHIFT); @@ -2657,10 +2627,11 @@ if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) return PM_RET_ERROR_NOTSUPPORTED; - if (ISPLL(clock_id)) - ret = pm_api_pll_bypass_and_reset(clock_id, - CLK_PLL_RESET_PULSE); - else + /* + * PLL type clock should not enable explicitly. + * It is done by FSBL on boot-up and by PMUFW whenever required. + */ + if (!ISPLL(clock_id)) ret = pm_api_clk_enable_disable(clock_id, 1); return ret; @@ -2686,10 +2657,11 @@ if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) return PM_RET_ERROR_NOTSUPPORTED; - if (ISPLL(clock_id)) - ret = pm_api_pll_bypass_and_reset(clock_id, - CLK_PLL_RESET_ASSERT); - else + /* + * PLL type clock should not be disabled explicitly. + * It is done by PMUFW if required. + */ + if (!ISPLL(clock_id)) ret = pm_api_clk_enable_disable(clock_id, 0); return ret; @@ -2837,8 +2809,13 @@ unsigned int divider) { unsigned int reg = clocks[clock_id].control_reg; + enum pm_ret_status ret; - return pm_mmio_write(reg, PLL_FBDIV_MASK, divider << PLL_FBDIV_SHIFT); + pm_api_pll_bypass_and_reset(clock_id, CLK_PLL_RESET_ASSERT); + ret = pm_mmio_write(reg, PLL_FBDIV_MASK, divider << PLL_FBDIV_SHIFT); + pm_api_pll_bypass_and_reset(clock_id, CLK_PLL_RESET_RELEASE); + + return ret; } /** @@ -2988,7 +2965,7 @@ /** * pm_api_clock_setparent - Set the clock parent for given id * @clock_id Id of the clock - * @parent_id parent id + * @parent_idx parent index * * This function is used by master to set parent for any clock. * @@ -3039,7 +3016,7 @@ /** * pm_api_clock_getparent - Get the clock parent for given id * @clock_id Id of the clock - * @parent_id parent id + * @parent_idx parent index * * This function is used by master to get parent index * for any clock. diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c index cdbb515..32c7357 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c @@ -453,6 +453,48 @@ } /** + * pm_ioctl_afi() - Ioctl function for writing afi values + * + * @index AFI register index + * @value Register value to be written + * + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_afi(unsigned int index, + unsigned int value) +{ + unsigned int mask; + unsigned int regarr[] = {0xFD360000, + 0xFD360014, + 0xFD370000, + 0xFD370014, + 0xFD380000, + 0xFD380014, + 0xFD390000, + 0xFD390014, + 0xFD3a0000, + 0xFD3a0014, + 0xFD3b0000, + 0xFD3b0014, + 0xFF9b0000, + 0xFF9b0014, + 0xFD615000, + 0xFF419000, + }; + + if (index >= ARRAY_SIZE(regarr)) + return PM_RET_ERROR_ARGS; + + if (index < AFIFM6_WRCTRL) + mask = FABRIC_WIDTH; + else + mask = 0xf00; + + return pm_mmio_write(regarr[index], mask, value); +} + +/** * pm_ioctl_read_pggs() - Ioctl function for reading persistent * global general storage (pggs) * @index PGGS register index @@ -472,6 +514,54 @@ } /** + * pm_ioctl_ulpi_reset() - Ioctl function for performing ULPI reset + * + * This function peerforms the ULPI reset sequence for resetting + * the ULPI transceiver. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_ulpi_reset(void) +{ + enum pm_ret_status ret; + + ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK, + ZYNQMP_ULPI_RESET_VAL_HIGH); + if (ret != PM_RET_SUCCESS) + return ret; + + /* Drive ULPI assert for atleast 1ms */ + mdelay(1); + + ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK, + ZYNQMP_ULPI_RESET_VAL_LOW); + if (ret != PM_RET_SUCCESS) + return ret; + + /* Drive ULPI de-assert for atleast 1ms */ + mdelay(1); + + ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK, + ZYNQMP_ULPI_RESET_VAL_HIGH); + + return ret; +} + +/** + * pm_ioctl_set_boot_health_status() - Ioctl for setting healthy boot status + * + * This function sets healthy bit value to indicate boot health status + * to firmware. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_set_boot_health_status(unsigned int value) +{ + return pm_mmio_write(PM_BOOT_HEALTH_STATUS_REG, + PM_BOOT_HEALTH_STATUS_MASK, value); +} + +/** * pm_api_ioctl() - PM IOCTL API for device control and configs * @node_id Node ID of the device * @ioctl_id ID of the requested IOCTL @@ -540,6 +630,15 @@ case IOCTL_READ_PGGS: ret = pm_ioctl_read_pggs(arg1, value); break; + case IOCTL_ULPI_RESET: + ret = pm_ioctl_ulpi_reset(); + break; + case IOCTL_SET_BOOT_HEALTH_STATUS: + ret = pm_ioctl_set_boot_health_status(arg1); + break; + case IOCTL_AFI: + ret = pm_ioctl_afi(arg1, arg2); + break; default: ret = PM_RET_ERROR_NOTSUPPORTED; break; diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h index 081259f..d68c5e3 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h @@ -32,6 +32,11 @@ IOCTL_READ_GGS, IOCTL_WRITE_PGGS, IOCTL_READ_PGGS, + /* IOCTL for ULPI reset */ + IOCTL_ULPI_RESET, + /* Set healthy bit value */ + IOCTL_SET_BOOT_HEALTH_STATUS, + IOCTL_AFI, }; //RPU operation mode diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index fe1029f..e85b2ce 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -602,6 +602,30 @@ } /** + * pm_aes_engine() - Aes data blob encryption/decryption + * This function provides access to the xilsecure library to + * encrypt/decrypt data blobs. + * + * address_low: lower 32-bit address of the AesParams structure + * + * address_high: higher 32-bit address of the AesParams structure + * + * value: Returned output value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_aes_engine(uint32_t address_high, + uint32_t address_low, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_SECURE_AES, address_high, address_low); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** * pm_pinctrl_request() - Request Pin from firmware * @pin Pin number to request * @@ -1183,3 +1207,33 @@ key_hi, key_lo); return pm_ipi_send_sync(primary_proc, payload, value, 2); } + +/** + * pm_fpga_read - Perform the fpga configuration readback + * + * @reg_numframes: Configuration register offset (or) Number of frames to read + * @address_low: lower 32-bit Linear memory space address + * @address_high: higher 32-bit Linear memory space address + * @readback_type: Type of fpga readback operation + * 0 -- Configuration Register readback + * 1 -- Configuration Data readback + * @value: Value to read + * + * This function provides access to the xilfpga library to read + * the PL configuration. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, + uint32_t address_low, + uint32_t address_high, + uint32_t readback_type, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_FPGA_READ, reg_numframes, address_low, + address_high, readback_type); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h index c304895..1c9255e 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h @@ -166,4 +166,14 @@ uint32_t key_lo, uint32_t key_hi, uint32_t *value); + +enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, + uint32_t address_low, + uint32_t address_high, + uint32_t readback_type, + uint32_t *value); +enum pm_ret_status pm_aes_engine(uint32_t address_high, + uint32_t address_low, + uint32_t *value); + #endif /* _PM_API_SYS_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h index 9a8026f..1fbf6ee 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_defs.h +++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h @@ -89,6 +89,9 @@ PM_CLOCK_SETPARENT, PM_CLOCK_GETPARENT, PM_SECURE_IMAGE, + /* FPGA PL Readback */ + PM_FPGA_READ, + PM_SECURE_AES, PM_API_MAX }; diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index dd9bbc8..7790c97 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -546,6 +546,23 @@ result[1]); } + case PM_FPGA_READ: + { + uint32_t value; + + ret = pm_fpga_read(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], + &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_SECURE_AES: + { + uint32_t value; + + ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + default: WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h index 22256eb..50a7331 100644 --- a/plat/xilinx/zynqmp/zynqmp_def.h +++ b/plat/xilinx/zynqmp/zynqmp_def.h @@ -48,6 +48,7 @@ #define CRL_APB_BOOT_MODE_USER (CRL_APB_BASE + 0x200) #define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218) #define CRL_APB_RST_LPD_TOP (CRL_APB_BASE + 0x23C) +#define CRL_APB_BOOT_PIN_CTRL (CRL_APB_BASE + U(0x250)) #define CRL_APB_CLK_BASE U(0xFF5E0020) #define CRL_APB_RPU_AMBA_RESET (U(1) << 2) @@ -56,7 +57,15 @@ #define CRL_APB_RESET_CTRL_SOFT_RESET (U(1) << 4) #define CRL_APB_BOOT_MODE_MASK (U(0xf) << 0) +#define CRL_APB_BOOT_PIN_MASK (U(0xf0f) << 0) +#define CRL_APB_BOOT_DRIVE_PIN_1_SHIFT U(9) +#define CRL_APB_BOOT_ENABLE_PIN_1_SHIFT U(1) +#define CRL_APB_BOOT_ENABLE_PIN_1 (U(0x1) << CRL_APB_BOOT_ENABLE_PIN_1_SHIFT) +#define CRL_APB_BOOT_DRIVE_PIN_1 (U(0x1) << CRL_APB_BOOT_DRIVE_PIN_1_SHIFT) #define ZYNQMP_BOOTMODE_JTAG U(0) +#define ZYNQMP_ULPI_RESET_VAL_HIGH (CRL_APB_BOOT_ENABLE_PIN_1 | \ + CRL_APB_BOOT_DRIVE_PIN_1) +#define ZYNQMP_ULPI_RESET_VAL_LOW CRL_APB_BOOT_ENABLE_PIN_1 /* system counter registers and bitfields */ #define IOU_SCNTRS_BASE 0xFF260000 @@ -148,8 +157,6 @@ #define ZYNQMP_SILICON_VER_MASK 0xF000 #define ZYNQMP_SILICON_VER_SHIFT 12 #define ZYNQMP_CSU_VERSION_SILICON 0 -#define ZYNQMP_CSU_VERSION_EP108 1 -#define ZYNQMP_CSU_VERSION_VELOCE 2 #define ZYNQMP_CSU_VERSION_QEMU 3 #define ZYNQMP_RTL_VER_MASK 0xFF0 @@ -192,6 +199,7 @@ #define ACTLR_EL3_L2ACTLR_BIT (1 << 6) #define ACTLR_EL3_CPUACTLR_BIT (1 << 0) +#define FPD_SLCR_BASEADDR U(0xFD610000) #define IOU_SLCR_BASEADDR U(0xFF180000) #define ZYNQMP_RPU_GLBL_CNTL U(0xFF9A0000) @@ -316,7 +324,7 @@ #define CRL_APB_TIMESTAMP_REF_CTRL (CRL_APB_CLK_BASE + 0x108) #define IOU_SLCR_GEM_CLK_CTRL (IOU_SLCR_BASEADDR + 0x308) #define IOU_SLCR_CAN_MIO_CTRL (IOU_SLCR_BASEADDR + 0x304) -#define IOU_SLCR_WDT_CLK_SEL (IOU_SLCR_BASEADDR + 0x300) +#define FPD_SLCR_WDT_CLK_SEL (FPD_SLCR_BASEADDR + 0x100) /* Global general storage register base address */ #define GGS_BASEADDR (0xFFD80030U) @@ -326,4 +334,12 @@ #define PGGS_BASEADDR (0xFFD80050U) #define PGGS_NUM_REGS U(4) +/* Warm restart boot health status register and mask */ +#define PM_BOOT_HEALTH_STATUS_REG (GGS_BASEADDR + U(0x10)) +#define PM_BOOT_HEALTH_STATUS_MASK U(0x01) + +/*AFI registers */ +#define AFIFM6_WRCTRL U(13) +#define FABRIC_WIDTH U(3) + #endif /* __ZYNQMP_DEF_H__ */