diff options
36 files changed, 1769 insertions, 192 deletions
diff --git a/docs/marvell/build.txt b/docs/marvell/build.txt index 8a669c10..0682b77d 100644 --- a/docs/marvell/build.txt +++ b/docs/marvell/build.txt @@ -78,9 +78,11 @@ Build Instructions Supported Options: - DDR3 1CS (0): DB-88F3720-DDR3-Modular (512MB); EspressoBIN (512MB) - DDR4 1CS (1): DB-88F3720-DDR4-Modular (512MB) - - DDR3 2CS (2): EspressoBIN (1GB) + - DDR3 2CS (2): EspressoBIN V3-V5 (1GB) - DDR4 2CS (3): DB-88F3720-DDR4-Modular (4GB) - DDR3 1CS (4): DB-88F3720-DDR3-Modular (1GB) + - DDR4 1CS (5): EspressoBin V7 (1GB) + - DDR4 2CS (6): EspressoBin V7 (2GB) - CUSTOMER (CUST): Customer board, DDR3 1CS 512MB - CLOCKSPRESET: For Armada37x0 only, the clock tree configuration preset including CPU and DDR frequency, diff --git a/docs/plat/imx8m.rst b/docs/plat/imx8m.rst new file mode 100644 index 00000000..ab33a8a5 --- /dev/null +++ b/docs/plat/imx8m.rst @@ -0,0 +1,42 @@ +Description +=========== + +The i.MX 8M family of applications processors based on Arm Corte-A53 and Cortex-M4 +cores provide high-performance computing, power efficiency, enhanced system +reliability and embedded security needed to drive the growth of fast-growing +edge node computing, streaming multimedia, and machine learning applications. + +Boot Sequence +============= + +Bootrom --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel + +How to build +============ + +Build Procedure +--------------- + +- Prepare AARCH64 toolchain. + +- Build spl and u-boot firstly, and get binary images: u-boot-spl.bin, + u-boot-nodtb.bin and dtb for the target board. + +- Build TF-A + + Build bl31: + + .. code:: shell + + CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31 + + Target_SoC should be "imx8mq" for i.MX8MQ SoC. + +Deploy TF-A Images +----------------- + +TF-A binary(bl31.bin), u-boot-spl.bin u-boot-nodtb.bin and dtb are combined +together to generate a binary file called flash.bin, the imx-mkimage tool is +used to generate flash.bin, and flash.bin needs to be flashed into SD card +with certain offset for BOOT ROM. the u-boot and imx-mkimage will be upstreamed +soon, this doc will be updated once they are ready, and the link will be posted. diff --git a/drivers/arm/tzc/tzc380.c b/drivers/arm/tzc/tzc380.c new file mode 100644 index 00000000..082161fe --- /dev/null +++ b/drivers/arm/tzc/tzc380.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <debug.h> +#include <mmio.h> +#include <stddef.h> +#include <tzc380.h> + +struct tzc380_instance { + uintptr_t base; + uint8_t addr_width; + uint8_t num_regions; +}; + +struct tzc380_instance tzc380; + +static unsigned int tzc380_read_build_config(uintptr_t base) +{ + return mmio_read_32(base + TZC380_CONFIGURATION_OFF); +} + +static void tzc380_write_action(uintptr_t base, tzc_action_t action) +{ + mmio_write_32(base + ACTION_OFF, action); +} + +static void tzc380_write_region_base_low(uintptr_t base, unsigned int region, + unsigned int val) +{ + mmio_write_32(base + REGION_SETUP_LOW_OFF(region), val); +} + +static void tzc380_write_region_base_high(uintptr_t base, unsigned int region, + unsigned int val) +{ + mmio_write_32(base + REGION_SETUP_HIGH_OFF(region), val); +} + +static void tzc380_write_region_attributes(uintptr_t base, unsigned int region, + unsigned int val) +{ + mmio_write_32(base + REGION_ATTRIBUTES_OFF(region), val); +} + +void tzc380_init(uintptr_t base) +{ + unsigned int tzc_build; + + assert(base != 0U); + tzc380.base = base; + + /* Save values we will use later. */ + tzc_build = tzc380_read_build_config(tzc380.base); + tzc380.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & + BUILD_CONFIG_AW_MASK) + 1; + tzc380.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & + BUILD_CONFIG_NR_MASK) + 1; +} + +static uint32_t addr_low(uintptr_t addr) +{ + return (uint32_t)addr; +} + +static uint32_t addr_high(uintptr_t addr __unused) +{ +#if (UINTPTR_MAX == UINT64_MAX) + return addr >> 32; +#else + return 0; +#endif +} + +/* + * `tzc380_configure_region` is used to program regions into the TrustZone + * controller. + */ +void tzc380_configure_region(uint8_t region, uintptr_t region_base, unsigned int attr) +{ + assert(tzc380.base != 0U); + + assert(region < tzc380.num_regions); + + tzc380_write_region_base_low(tzc380.base, region, addr_low(region_base)); + tzc380_write_region_base_high(tzc380.base, region, addr_high(region_base)); + tzc380_write_region_attributes(tzc380.base, region, attr); +} + +void tzc380_set_action(tzc_action_t action) +{ + assert(tzc380.base != 0U); + + /* + * - Currently no handler is provided to trap an error via interrupt + * or exception. + * - The interrupt action has not been tested. + */ + tzc380_write_action(tzc380.base, action); +} diff --git a/drivers/marvell/ap807_clocks_init.c b/drivers/marvell/ap807_clocks_init.c new file mode 100644 index 00000000..841e6aeb --- /dev/null +++ b/drivers/marvell/ap807_clocks_init.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + * https://spdx.org/licenses + */ + +#include <a8k_plat_def.h> +#include <aro.h> +#include <delay_timer.h> +#include <mmio.h> + +/* Notify bootloader on DRAM setup */ +#define AP807_CPU_ARO_CTRL(cluster) \ + (MVEBU_RFU_BASE + 0x82A8 + (0xA58 * (cluster))) + +/* 0 - ARO clock is enabled, 1 - ARO clock is disabled */ +#define AP807_CPU_ARO_CLK_EN_OFFSET 0 +#define AP807_CPU_ARO_CLK_EN_MASK (0x1 << AP807_CPU_ARO_CLK_EN_OFFSET) + +/* 0 - ARO is the clock source, 1 - PLL is the clock source */ +#define AP807_CPU_ARO_SEL_PLL_OFFSET 5 +#define AP807_CPU_ARO_SEL_PLL_MASK (0x1 << AP807_CPU_ARO_SEL_PLL_OFFSET) + +/* AP807 clusters count */ +#define AP807_CLUSTER_NUM 2 + +/* PLL frequency values */ +#define PLL_FREQ_1200 0x2AE5F002 /* 1200 */ +#define PLL_FREQ_2000 0x2FC9F002 /* 2000 */ +#define PLL_FREQ_2200 0x2AC57001 /* 2200 */ +#define PLL_FREQ_2400 0x2AE5F001 /* 2400 */ + +/* CPU PLL control registers */ +#define AP807_CPU_PLL_CTRL(cluster) \ + (MVEBU_RFU_BASE + 0x82E0 + (0x8 * (cluster))) + +#define AP807_CPU_PLL_PARAM(cluster) AP807_CPU_PLL_CTRL(cluster) +#define AP807_CPU_PLL_CFG(cluster) (AP807_CPU_PLL_CTRL(cluster) + 0x4) +#define AP807_CPU_PLL_CFG_BYPASS_MODE (0x1) +#define AP807_CPU_PLL_CFG_USE_REG_FILE (0x1 << 9) + +static void pll_set_freq(unsigned int freq_val) +{ + int i; + + for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) { + mmio_write_32(AP807_CPU_PLL_CFG(i), + AP807_CPU_PLL_CFG_USE_REG_FILE); + mmio_write_32(AP807_CPU_PLL_CFG(i), + AP807_CPU_PLL_CFG_USE_REG_FILE | + AP807_CPU_PLL_CFG_BYPASS_MODE); + mmio_write_32(AP807_CPU_PLL_PARAM(i), freq_val); + mmio_write_32(AP807_CPU_PLL_CFG(i), + AP807_CPU_PLL_CFG_USE_REG_FILE); + } +} + +/* Switch to ARO from PLL in ap807 */ +static void aro_to_pll(void) +{ + unsigned int reg; + int i; + + for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) { + /* switch from ARO to PLL */ + reg = mmio_read_32(AP807_CPU_ARO_CTRL(i)); + reg |= AP807_CPU_ARO_SEL_PLL_MASK; + mmio_write_32(AP807_CPU_ARO_CTRL(i), reg); + + mdelay(100); + + /* disable ARO clk driver */ + reg = mmio_read_32(AP807_CPU_ARO_CTRL(i)); + reg |= (AP807_CPU_ARO_CLK_EN_MASK); + mmio_write_32(AP807_CPU_ARO_CTRL(i), reg); + } +} + +/* switch from ARO to PLL + * in case of default frequency option, configure PLL registers + * to be aligned with new default frequency. + */ +void ap807_clocks_init(unsigned int freq_option) +{ + /* Switch from ARO to PLL */ + aro_to_pll(); + + /* Modifications in frequency table: + * 0x0: 764x: change to 2000 MHz. + * 0x2: 744x change to 1800 MHz, 764x change to 2200/2400. + * 0x3: 3900/744x/764x change to 1200 MHz. + */ + switch (freq_option) { + case CPU_2000_DDR_1200_RCLK_1200: + pll_set_freq(PLL_FREQ_2000); + break; + default: + break; + } +} diff --git a/drivers/marvell/comphy/phy-comphy-common.h b/drivers/marvell/comphy/phy-comphy-common.h index 78c7a38f..e3b430a9 100644 --- a/drivers/marvell/comphy/phy-comphy-common.h +++ b/drivers/marvell/comphy/phy-comphy-common.h @@ -18,13 +18,15 @@ #endif /* A lane is described by 4 fields: - * - bit 1~0 represent comphy polarity invert - * - bit 7~2 represent comphy speed - * - bit 11~8 represent unit index - * - bit 16~12 represent mode - * - bit 17 represent comphy indication of clock source - * - bit 19-18 represents pcie width (in case of pcie comphy config.) - * - bit 31~20 reserved + * - bit 1~0 represent comphy polarity invert + * - bit 7~2 represent comphy speed + * - bit 11~8 represent unit index + * - bit 16~12 represent mode + * - bit 17 represent comphy indication of clock source + * - bit 20~18 represents pcie width (in case of pcie comphy config.) + * - bit 21 represents the source of the request (Linux/Bootloader), + * (reguired only for PCIe!) + * - bit 31~22 reserved */ #define COMPHY_INVERT_OFFSET 0 @@ -50,6 +52,11 @@ #define COMPHY_PCI_WIDTH_LEN 3 #define COMPHY_PCI_WIDTH_MASK COMPHY_MASK(COMPHY_PCI_WIDTH_OFFSET, \ COMPHY_PCI_WIDTH_LEN) +#define COMPHY_PCI_CALLER_OFFSET \ + (COMPHY_PCI_WIDTH_OFFSET + COMPHY_PCI_WIDTH_LEN) +#define COMPHY_PCI_CALLER_LEN 1 +#define COMPHY_PCI_CALLER_MASK COMPHY_MASK(COMPHY_PCI_CALLER_OFFSET, \ + COMPHY_PCI_CALLER_LEN) #define COMPHY_MASK(offset, len) (((1 << (len)) - 1) << (offset)) @@ -69,6 +76,10 @@ #define COMPHY_GET_PCIE_WIDTH(x) (((x) & COMPHY_PCI_WIDTH_MASK) >> \ COMPHY_PCI_WIDTH_OFFSET) +/* Macro which extracts the caller for pcie power on from lane description */ +#define COMPHY_GET_CALLER(x) (((x) & COMPHY_PCI_CALLER_MASK) >> \ + COMPHY_PCI_CALLER_OFFSET) + /* Macro which extracts the polarity invert from lane description */ #define COMPHY_GET_POLARITY_INVERT(x) (((x) & COMPHY_INVERT_MASK) >> \ COMPHY_INVERT_OFFSET) diff --git a/drivers/marvell/comphy/phy-comphy-cp110.c b/drivers/marvell/comphy/phy-comphy-cp110.c index 25893a98..86e5f1c6 100644 --- a/drivers/marvell/comphy/phy-comphy-cp110.c +++ b/drivers/marvell/comphy/phy-comphy-cp110.c @@ -208,8 +208,8 @@ static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base, */ if ((mode == COMPHY_SGMII_MODE || mode == COMPHY_HS_SGMII_MODE || - mode == COMPHY_SFI_MODE) && - COMPHY_GET_ID(comphy_mode) == 1) + mode == COMPHY_SFI_MODE || mode == COMPHY_XFI_MODE) + && COMPHY_GET_ID(comphy_mode) == 1) reg |= COMMON_SELECTOR_COMPHY4_PORT1 << comphy_offset; else @@ -1205,6 +1205,22 @@ static int mvebu_cp110_comphy_pcie_power_on(uint64_t comphy_base, uint32_t clk_dir; uintptr_t hpipe_addr, comphy_addr, addr; _Bool clk_src = COMPHY_GET_CLK_SRC(comphy_mode); + _Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode); + + /* In Armada 8K DB boards, PCIe initialization can be executed + * only once (PCIe reset performed during chip power on and + * it cannot be executed via GPIO later). + * This means that power on can be executed only once, so let's + * mark if the caller is bootloader or Linux. + * If bootloader -> run power on. + * If Linux -> exit. + * + * TODO: In MacciatoBIN, PCIe reset is connected via GPIO, + * so after GPIO reset is added to Linux Kernel, it can be + * powered-on by Linux. + */ + if (!called_from_uboot) + return ret; hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); @@ -2366,14 +2382,45 @@ int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index, return err; } -int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index) +int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index, + uint64_t comphy_mode) { uintptr_t sd_ip_addr, comphy_ip_addr; uint32_t mask, data; uint8_t ap_nr, cp_nr; + _Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode); debug_enter(); + /* Power-off might happen because of 2 things: + * 1. Bootloader turns off unconnected lanes + * 2. Linux turns off all lanes during boot + * (and then reconfigure it). + * + * For PCIe, there's a problem: + * In Armada 8K DB boards, PCIe initialization can be executed + * only once (PCIe reset performed during chip power on and + * it cannot be executed via GPIO later) so a lane configured to + * PCIe should not be powered off by Linux. + * + * So, check 2 things: + * 1. Is Linux called for power-off? + * 2. Is the comphy configured to PCIe? + * If the answer is YES for both 1 and 2, skip the power-off. + * + * TODO: In MacciatoBIN, PCIe reset is connected via GPIO, + * so after GPIO reset is added to Linux Kernel, it can be + * powered-off. + */ + if (!called_from_uboot) { + data = mmio_read_32(comphy_base + + COMMON_SELECTOR_PIPE_REG_OFFSET); + data >>= (COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index); + data &= COMMON_SELECTOR_COMPHY_MASK; + if (data == COMMON_SELECTOR_PIPE_COMPHY_PCIE) + return 0; + } + mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) { diff --git a/drivers/marvell/comphy/phy-comphy-cp110.h b/drivers/marvell/comphy/phy-comphy-cp110.h index 70dbfbfc..407909bf 100644 --- a/drivers/marvell/comphy/phy-comphy-cp110.h +++ b/drivers/marvell/comphy/phy-comphy-cp110.h @@ -82,7 +82,7 @@ struct sata_params { int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base, uint8_t comphy_index); int mvebu_cp110_comphy_power_off(uint64_t comphy_base, - uint8_t comphy_index); + uint8_t comphy_index, uint64_t comphy_mode); int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index, uint64_t comphy_mode); int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base, diff --git a/include/drivers/arm/tzc380.h b/include/drivers/arm/tzc380.h new file mode 100644 index 00000000..19cf9883 --- /dev/null +++ b/include/drivers/arm/tzc380.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TZC380_H +#define TZC380_H + +#include <tzc_common.h> +#include <utils_def.h> + +#define TZC380_CONFIGURATION_OFF U(0x000) +#define ACTION_OFF U(0x004) +#define LOCKDOWN_RANGE_OFF U(0x008) +#define LOCKDOWN_SELECT_OFF U(0x00C) +#define INT_STATUS U(0x010) +#define INT_CLEAR U(0x014) + +#define FAIL_ADDRESS_LOW_OFF U(0x020) +#define FAIL_ADDRESS_HIGH_OFF U(0x024) +#define FAIL_CONTROL_OFF U(0x028) +#define FAIL_ID U(0x02c) + +#define SPECULATION_CTRL_OFF U(0x030) +#define SECURITY_INV_EN_OFF U(0x034) + +#define REGION_SETUP_LOW_OFF(n) U(0x100 + (n) * 0x10) +#define REGION_SETUP_HIGH_OFF(n) U(0x104 + (n) * 0x10) +#define REGION_ATTRIBUTES_OFF(n) U(0x108 + (n) * 0x10) + +#define BUILD_CONFIG_AW_SHIFT 8 +#define BUILD_CONFIG_AW_MASK U(0x3f) +#define BUILD_CONFIG_NR_SHIFT 0 +#define BUILD_CONFIG_NR_MASK U(0xf) + +#define ACTION_RV_SHIFT 0 +#define ACTION_RV_MASK U(0x3) +#define ACTION_RV_LOWOK U(0x0) +#define ACTION_RV_LOWERR U(0x1) +#define ACTION_RV_HIGHOK U(0x2) +#define ACTION_RV_HIGHERR U(0x3) + +/* Speculation is enabled by default. */ +#define SPECULATION_CTRL_WRITE_DISABLE BIT_32(1) +#define SPECULATION_CTRL_READ_DISABLE BIT_32(0) + +#define INT_STATUS_OVERRUN_SHIFT 1 +#define INT_STATUS_OVERRUN_MASK U(0x1) +#define INT_STATUS_STATUS_SHIFT 0 +#define INT_STATUS_STATUS_MASK U(0x1) + +#define INT_CLEAR_CLEAR_SHIFT 0 +#define INT_CLEAR_CLEAR_MASK U(0x1) + +#define TZC380_COMPONENT_ID U(0xb105f00d) +#define TZC380_PERIPH_ID_LOW U(0x001bb380) +#define TZC380_PERIPH_ID_HIGH U(0x00000004) + +#define TZC_SP_NS_W BIT_32(0) +#define TZC_SP_NS_R BIT_32(1) +#define TZC_SP_S_W BIT_32(2) +#define TZC_SP_S_R BIT_32(3) + +#define TZC_ATTR_SP_SHIFT 28 +#define TZC_ATTR_SP_ALL ((TZC_SP_S_W | TZC_SP_S_R | TZC_SP_NS_W | \ + TZC_SP_NS_R) << TZC_ATTR_SP_SHIFT) +#define TZC_ATTR_SP_S_RW ((TZC_SP_S_W | TZC_SP_S_R) << \ + TZC_ATTR_SP_SHIFT) +#define TZC_ATTR_SP_NS_RW ((TZC_SP_NS_W | TZC_SP_NS_R) << \ + TZC_ATTR_SP_SHIFT) + +#define TZC_REGION_SIZE_32K U(0xe) +#define TZC_REGION_SIZE_64K U(0xf) +#define TZC_REGION_SIZE_128K U(0x10) +#define TZC_REGION_SIZE_256K U(0x11) +#define TZC_REGION_SIZE_512K U(0x12) +#define TZC_REGION_SIZE_1M U(0x13) +#define TZC_REGION_SIZE_2M U(0x14) +#define TZC_REGION_SIZE_4M U(0x15) +#define TZC_REGION_SIZE_8M U(0x16) +#define TZC_REGION_SIZE_16M U(0x17) +#define TZC_REGION_SIZE_32M U(0x18) +#define TZC_REGION_SIZE_64M U(0x19) +#define TZC_REGION_SIZE_128M U(0x1a) +#define TZC_REGION_SIZE_256M U(0x1b) +#define TZC_REGION_SIZE_512M U(0x1c) +#define TZC_REGION_SIZE_1G U(0x1d) +#define TZC_REGION_SIZE_2G U(0x1e) +#define TZC_REGION_SIZE_4G U(0x1f) +#define TZC_REGION_SIZE_8G U(0x20) +#define TZC_REGION_SIZE_16G U(0x21) +#define TZC_REGION_SIZE_32G U(0x22) +#define TZC_REGION_SIZE_64G U(0x23) +#define TZC_REGION_SIZE_128G U(0x24) +#define TZC_REGION_SIZE_256G U(0x25) +#define TZC_REGION_SIZE_512G U(0x26) +#define TZC_REGION_SIZE_1T U(0x27) +#define TZC_REGION_SIZE_2T U(0x28) +#define TZC_REGION_SIZE_4T U(0x29) +#define TZC_REGION_SIZE_8T U(0x2a) +#define TZC_REGION_SIZE_16T U(0x2b) +#define TZC_REGION_SIZE_32T U(0x2c) +#define TZC_REGION_SIZE_64T U(0x2d) +#define TZC_REGION_SIZE_128T U(0x2e) +#define TZC_REGION_SIZE_256T U(0x2f) +#define TZC_REGION_SIZE_512T U(0x30) +#define TZC_REGION_SIZE_1P U(0x31) +#define TZC_REGION_SIZE_2P U(0x32) +#define TZC_REGION_SIZE_4P U(0x33) +#define TZC_REGION_SIZE_8P U(0x34) +#define TZC_REGION_SIZE_16P U(0x35) +#define TZC_REGION_SIZE_32P U(0x36) +#define TZC_REGION_SIZE_64P U(0x37) +#define TZC_REGION_SIZE_128P U(0x38) +#define TZC_REGION_SIZE_256P U(0x39) +#define TZC_REGION_SIZE_512P U(0x3a) +#define TZC_REGION_SIZE_1E U(0x3b) +#define TZC_REGION_SIZE_2E U(0x3c) +#define TZC_REGION_SIZE_4E U(0x3d) +#define TZC_REGION_SIZE_8E U(0x3e) +#define TZC_REGION_SIZE_16E U(0x3f) + +#define TZC_REGION_SIZE_SHIFT 0x1 +#define TZC_REGION_SIZE_MASK U(0x7e) +#define TZC_ATTR_REGION_SIZE(s) ((s) << TZC_REGION_SIZE_SHIFT) + +#define TZC_ATTR_REGION_EN_SHIFT 0x0 +#define TZC_ATTR_REGION_EN_MASK U(0x1) + +#define TZC_ATTR_REGION_EN +#define TZC_ATTR_REGION_ENABLE U(0x1) +#define TZC_ATTR_REGION_DISABLE U(0x0) + +#define REGION_MAX 16 + +void tzc380_init(uintptr_t base); +void tzc380_configure_region(uint8_t region, + uintptr_t region_base, + unsigned int attr); +void tzc380_set_action(tzc_action_t action); +static inline void tzc_init(uintptr_t base) +{ + tzc380_init(base); +} + +static inline void tzc_configure_region(uint8_t region, + uintptr_t region_base, + unsigned int attr) +{ + tzc380_configure_region(region, region_base, attr); +} + +static inline void tzc_set_action(tzc_action_t action) +{ + tzc380_set_action(action); +} + +#endif /* TZC380_H */ diff --git a/include/drivers/marvell/ap807_clocks_init.h b/include/drivers/marvell/ap807_clocks_init.h new file mode 100644 index 00000000..4353b83e --- /dev/null +++ b/include/drivers/marvell/ap807_clocks_init.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + * https://spdx.org/licenses + */ + +#ifndef AP807_INIT_CLOCKS_H +#define AP807_INIT_CLOCKS_H + +void ap807_clocks_init(unsigned int freq_option); + +#endif /* AP807_INIT_CLOCKS_H */ + diff --git a/plat/arm/board/sgi575/platform.mk b/plat/arm/board/sgi575/platform.mk index dd82d297..f31a8b73 100644 --- a/plat/arm/board/sgi575/platform.mk +++ b/plat/arm/board/sgi575/platform.mk @@ -14,12 +14,14 @@ SGI_CPU_SOURCES := lib/cpus/aarch64/cortex_a75.S BL1_SOURCES += ${SGI_CPU_SOURCES} -BL2_SOURCES += ${SGI575_BASE}/sgi575_security.c \ +BL2_SOURCES += ${SGI575_BASE}/sgi575_plat.c \ + ${SGI575_BASE}/sgi575_security.c \ drivers/arm/tzc/tzc_dmc620.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c BL31_SOURCES += ${SGI_CPU_SOURCES} \ + ${SGI575_BASE}/sgi575_plat.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c diff --git a/plat/arm/board/sgi575/sgi575_plat.c b/plat/arm/board/sgi575/sgi575_plat.c new file mode 100644 index 00000000..a8ca916d --- /dev/null +++ b/plat/arm/board/sgi575/sgi575_plat.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform.h> + +unsigned int plat_arm_sgi_get_platform_id(void) +{ + return mmio_read_32(SSC_VERSION) & SSC_VERSION_PART_NUM_MASK; +} + +unsigned int plat_arm_sgi_get_config_id(void) +{ + return (mmio_read_32(SSC_VERSION) >> SSC_VERSION_CONFIG_SHIFT) + & SSC_VERSION_CONFIG_MASK; +} diff --git a/plat/arm/board/sgiclarka/platform.mk b/plat/arm/board/sgiclarka/platform.mk index cf02219f..0773be5b 100644 --- a/plat/arm/board/sgiclarka/platform.mk +++ b/plat/arm/board/sgiclarka/platform.mk @@ -14,12 +14,14 @@ SGI_CPU_SOURCES := lib/cpus/aarch64/cortex_ares.S BL1_SOURCES += ${SGI_CPU_SOURCES} -BL2_SOURCES += ${SGICLARKA_BASE}/sgiclarka_security.c \ +BL2_SOURCES += ${SGICLARKA_BASE}/sgiclarka_plat.c \ + ${SGICLARKA_BASE}/sgiclarka_security.c \ drivers/arm/tzc/tzc_dmc620.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c BL31_SOURCES += ${SGI_CPU_SOURCES} \ + ${SGICLARKA_BASE}/sgiclarka_plat.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c diff --git a/plat/arm/board/sgiclarka/sgiclarka_plat.c b/plat/arm/board/sgiclarka/sgiclarka_plat.c new file mode 100644 index 00000000..3df2da66 --- /dev/null +++ b/plat/arm/board/sgiclarka/sgiclarka_plat.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform.h> + +unsigned int plat_arm_sgi_get_platform_id(void) +{ + return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET) + & SID_SYSTEM_ID_PART_NUM_MASK; +} + +unsigned int plat_arm_sgi_get_config_id(void) +{ + return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET); +} diff --git a/plat/arm/css/sgi/include/sgi_variant.h b/plat/arm/css/sgi/include/sgi_variant.h index dea580be..56dc3344 100644 --- a/plat/arm/css/sgi/include/sgi_variant.h +++ b/plat/arm/css/sgi/include/sgi_variant.h @@ -21,4 +21,10 @@ typedef struct sgi_platform_info { extern sgi_platform_info_t sgi_plat_info; +/* returns the part number of the platform*/ +unsigned int plat_arm_sgi_get_platform_id(void); + +/* returns the configuration id of the platform */ +unsigned int plat_arm_sgi_get_config_id(void); + #endif /* SGI_VARIANT_H */ diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/css/sgi/sgi_bl31_setup.c index d44f89c7..a254388b 100644 --- a/plat/arm/css/sgi/sgi_bl31_setup.c +++ b/plat/arm/css/sgi/sgi_bl31_setup.c @@ -42,53 +42,11 @@ scmi_channel_plat_info_t *plat_css_get_scmi_info() panic(); }; -/******************************************************************************* - * This function sets the sgi_platform_id and sgi_config_id - ******************************************************************************/ -int sgi_identify_platform(unsigned long hw_config) -{ - void *fdt; - int nodeoffset; - const unsigned int *property; - - fdt = (void *)hw_config; - - /* Check the validity of the fdt */ - assert(fdt_check_header(fdt) == 0); - - nodeoffset = fdt_subnode_offset(fdt, 0, "system-id"); - if (nodeoffset < 0) { - ERROR("Failed to get system-id node offset\n"); - return -1; - } - - property = fdt_getprop(fdt, nodeoffset, "platform-id", NULL); - if (property == NULL) { - ERROR("Failed to get platform-id property\n"); - return -1; - } - - sgi_plat_info.platform_id = fdt32_to_cpu(*property); - - property = fdt_getprop(fdt, nodeoffset, "config-id", NULL); - if (property == NULL) { - ERROR("Failed to get config-id property\n"); - return -1; - } - - sgi_plat_info.config_id = fdt32_to_cpu(*property); - - return 0; -} - void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { - int ret; - - ret = sgi_identify_platform(arg2); - if (ret == -1) - panic(); + sgi_plat_info.platform_id = plat_arm_sgi_get_platform_id(); + sgi_plat_info.config_id = plat_arm_sgi_get_config_id(); arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } diff --git a/plat/arm/css/sgi/sgi_image_load.c b/plat/arm/css/sgi/sgi_image_load.c index d97583ef..39069ca3 100644 --- a/plat/arm/css/sgi/sgi_image_load.c +++ b/plat/arm/css/sgi/sgi_image_load.c @@ -9,6 +9,7 @@ #include <desc_image_load.h> #include <libfdt.h> #include <platform.h> +#include <sgi_variant.h> /******************************************************************************* * This function inserts Platform information via device tree nodes as, @@ -23,7 +24,6 @@ static int plat_sgi_append_config_node(void) void *fdt; int nodeoffset, err; unsigned int platid = 0, platcfg = 0; - char *platform_name; mem_params = get_bl_mem_params_node(HW_CONFIG_ID); if (mem_params == NULL) { @@ -39,38 +39,20 @@ static int plat_sgi_append_config_node(void) return -1; } - platform_name = (char *)fdt_getprop(fdt, 0, "compatible", NULL); - - if (platform_name == NULL) { - ERROR("Invalid HW_CONFIG DTB passed\n"); - return -1; - } - - if (strcmp(platform_name, "arm,sgi575") == 0) { - platid = mmio_read_32(SSC_VERSION) & SSC_VERSION_PART_NUM_MASK; - platcfg = (mmio_read_32(SSC_VERSION) >> SSC_VERSION_CONFIG_SHIFT) - & SSC_VERSION_CONFIG_MASK; - } else if (strcmp(platform_name, "arm,sgi-clark") == 0) { - platid = mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET) - & SID_SYSTEM_ID_PART_NUM_MASK; - platcfg = mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET); - } else { - WARN("Invalid platform\n"); - return -1; - } - nodeoffset = fdt_subnode_offset(fdt, 0, "system-id"); if (nodeoffset < 0) { ERROR("Failed to get system-id node offset\n"); return -1; } + platid = plat_arm_sgi_get_platform_id(); err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid); if (err < 0) { ERROR("Failed to set platform-id\n"); return -1; } + platcfg = plat_arm_sgi_get_config_id(); err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg); if (err < 0) { ERROR("Failed to set config-id\n"); diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c index c1be1f62..22614706 100644 --- a/plat/hisilicon/hikey960/hikey960_bl31_setup.c +++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c @@ -14,6 +14,7 @@ #include <generic_delay_timer.h> #include <gicv2.h> #include <hi3660.h> +#include <mmio.h> #include <hisi_ipc.h> #include <interrupt_mgmt.h> #include <interrupt_props.h> @@ -143,6 +144,19 @@ void bl31_plat_arch_setup(void) BL31_COHERENT_RAM_LIMIT); } +static void hikey960_edma_init(void) +{ + int i; + uint32_t non_secure; + + non_secure = EDMAC_SEC_CTRL_INTR_SEC | EDMAC_SEC_CTRL_GLOBAL_SEC; + mmio_write_32(EDMAC_SEC_CTRL, non_secure); + + for (i = 0; i < EDMAC_CHANNEL_NUMS; i++) { + mmio_write_32(EDMAC_AXI_CONF(i), (1 << 6) | (1 << 18)); + } +} + void bl31_platform_setup(void) { /* Initialize the GIC driver, cpu and distributor interfaces */ @@ -151,6 +165,8 @@ void bl31_platform_setup(void) gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); + hikey960_edma_init(); + hisi_ipc_init(); } diff --git a/plat/hisilicon/hikey960/include/hi3660.h b/plat/hisilicon/hikey960/include/hi3660.h index 8ce531ea..c9ecd32c 100644 --- a/plat/hisilicon/hikey960/include/hi3660.h +++ b/plat/hisilicon/hikey960/include/hi3660.h @@ -366,4 +366,11 @@ /* GPIO219: PD interrupt. pull up */ #define IOCG_AO_043_REG (IOCG_AO_REG_BASE + 0x030) +#define EDMAC_BASE 0xfdf30000 +#define EDMAC_SEC_CTRL (EDMAC_BASE + 0x694) +#define EDMAC_AXI_CONF(x) (EDMAC_BASE + 0x820 + (x << 6)) +#define EDMAC_SEC_CTRL_INTR_SEC (1 << 1) +#define EDMAC_SEC_CTRL_GLOBAL_SEC (1 << 0) +#define EDMAC_CHANNEL_NUMS 16 + #endif /* HI3660_H */ diff --git a/plat/imx/common/imx_uart_console.S b/plat/imx/common/imx_uart_console.S new file mode 100644 index 00000000..7dbde795 --- /dev/null +++ b/plat/imx/common/imx_uart_console.S @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#define USE_FINISH_CONSOLE_REG_2 +#include <console_macros.S> +#include <assert_macros.S> +#include "imx_uart.h" + +#define URXD 0x0 /* Receiver Register */ +#define UTXD 0x40 /* Transmitter Register */ +#define UTS 0xb4 /* UART Test Register (mx31) */ +#define URXD_RX_DATA (0xFF) + + .globl console_uart_register + .globl console_uart_init + .globl console_uart_putc + .globl console_uart_getc + +func console_imx_uart_register + mov x7, x30 + mov x6, x3 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_DRVDATA] + + bl console_imx_uart_init + cbz x0, register_fail + + mov x0, x6 + mov x30, x7 + finish_console_register imx_uart putc=1, getc=1 + +register_fail: + ret x7 +endfunc console_imx_uart_register + +func console_imx_uart_init + mov w0, #1 + ret +endfunc console_imx_uart_init + +func console_imx_uart_putc + ldr x1, [x1, #CONSOLE_T_DRVDATA] + cbz x1, putc_error + + /* Prepare '\r' to '\n' */ + cmp w0, #0xA + b.ne 2f +1: + /* Check if the transmit FIFO is full */ + ldr w2, [x1, #UTS] + tbz w2, #6, 1b + mov w2, #0xD + str w2, [x1, #UTXD] +2: + /* Check if the transmit FIFO is full */ + ldr w2, [x1, #UTS] + tbz w2, #6, 2b + str w0, [x1, #UTXD] + ret +putc_error: + mov w0, #-1 + ret +endfunc console_imx_uart_putc + +func console_imx_uart_getc + ldr x0, [x0, #CONSOLE_T_DRVDATA] + cbz x0, getc_error +1: + ldr w1, [x0, #UTS] + tbnz w1, #5, 1b + + ldr w1, [x0, #URXD] + and w0, w1, #URXD_RX_DATA + + ret +getc_error: + mov w0, #-1 + ret +endfunc console_imx_uart_getc diff --git a/plat/imx/common/include/imx_uart.h b/plat/imx/common/include/imx_uart.h new file mode 100644 index 00000000..d2c39688 --- /dev/null +++ b/plat/imx/common/include/imx_uart.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IMX_UART_H +#define IMX_UART_H + +#include <console.h> + +#ifndef __ASSEMBLY__ + +typedef struct { + console_t console; + uintptr_t base; +} console_uart_t; + +int console_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, + console_uart_t *console); +#endif /*__ASSEMBLY__*/ + +#endif /* IMX_UART_H */ diff --git a/plat/imx/imx8m/imx8mq/gpc.c b/plat/imx/imx8m/imx8mq/gpc.c new file mode 100644 index 00000000..187a4ad1 --- /dev/null +++ b/plat/imx/imx8m/imx8mq/gpc.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <gpc.h> +#include <mmio.h> +#include <platform_def.h> +#include <psci.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <std_svc.h> + +void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint) +{ + uint64_t temp_base; + + temp_base = (uint64_t) sec_entrypoint; + temp_base >>= 2; + + mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3), + ((uint32_t)(temp_base >> 22) & 0xffff)); + mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4, + ((uint32_t)temp_base & 0x003fffff)); +} + +/* use wfi power down the core */ +void imx_set_cpu_pwr_off(unsigned int core_id) +{ + /* enable the wfi power down of the core */ + mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | + (1 << (core_id + 20))); + /* assert the pcg pcr bit of the core */ + mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); +}; + +/* use the sw method to power up the core */ +void imx_set_cpu_pwr_on(unsigned int core_id) +{ + /* clear the wfi power down bit of the core */ + mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); + /* assert the ncpuporeset */ + mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); + /* assert the pcg pcr bit of the core */ + mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); + /* sw power up the core */ + mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id)); + + /* wait for the power up finished */ + while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0) + ; + + /* deassert the pcg pcr bit of the core */ + mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); + /* deassert the ncpuporeset */ + mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); +} + +/* if out of lpm, we need to do reverse steps */ +void imx_set_cpu_lpm(unsigned int core_id, bool pdn) +{ + if (pdn) { + /* enable the core WFI PDN & IRQ PUP */ + mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | + (1 << (core_id + 20)) | COREx_IRQ_WUP(core_id)); + /* assert the pcg pcr bit of the core */ + mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); + } else { + /* disable CORE WFI PDN & IRQ PUP */ + mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | + COREx_IRQ_WUP(core_id)); + /* deassert the pcg pcr bit of the core */ + mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); + } +} + +void imx_set_sys_wakeup(unsigned int last_core, bool pdn) +{ + /* TODO */ +} + +void imx_pup_pdn_slot_config(int last_core, bool pdn) +{ + if (pdn) { + /* SLOT0 for A53 PLAT power down */ + mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN); + /* SLOT1 for A53 PLAT power up */ + mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP); + /* SLOT2 for A53 primary core power up */ + mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core)); + /* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */ + mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, + A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK); + } else { + mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF); + mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF); + mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF); + mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, + A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK); + } +} + +void imx_set_cluster_standby(bool retention) +{ + /* + * Enable BIT 6 of A53 AD register to make sure system + * don't enter LPM mode. + */ + if (retention) + mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); + else + mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); +} + +void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) +{ + uint32_t val; + + if (is_local_state_off(power_state)) { + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */ + val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */ + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + /* enable C2-3's STOP mode */ + mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP); + + /* enable PLAT/SCU power down */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); + val &= ~EN_L2_WFI_PDN; + val |= L2PGE | EN_PLAT_PDN; + val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */ + val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */ + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + + imx_pup_pdn_slot_config(last_core, true); + + /* enable PLAT PGC */ + mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); + } else { + /* clear PLAT PGC */ + mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); + + /* clear the slot and ack for cluster power down */ + imx_pup_pdn_slot_config(last_core, false); + + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */ + val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */ + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + /* set A53 LPM to RUN mode */ + mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK); + + /* clear PLAT/SCU power down */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); + val |= EN_L2_WFI_PDN; + val &= ~(L2PGE | EN_PLAT_PDN); + val &= ~COREx_LPM_PUP(last_core); /* disable C0's LPM PUP */ + mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); + } +} + +/* config the system level power mode */ +void imx_set_sys_lpm(bool retention) +{ + uint32_t val; + + /* set system DSM mode SLPCR(0x14) */ + val = mmio_read_32(IMX_GPC_BASE + SLPCR); + val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | + SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN); + + if (retention) + val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | + SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN | + SLPCR_A53_FASTWUP_STOP_MODE); + + mmio_write_32(IMX_GPC_BASE + SLPCR, val); +} + +void imx_set_rbc_count(void) +{ + mmio_setbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT); +} + +void imx_clear_rbc_count(void) +{ + mmio_clrbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT); +} + +void imx_gpc_init(void) +{ + uint32_t val; + int i; + /* mask all the interrupt by default */ + /* Due to the hardware design requirement, need to make + * sure GPR interrupt(#32) is unmasked during RUN mode to + * avoid entering DSM mode by mistake. + */ + for (i = 0; i < 4; i++) { + mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, 0xFFFFFFFE); + mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, 0xFFFFFFFE); + mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, 0xFFFFFFFE); + mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, 0xFFFFFFFE); + mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0); + } + + /* use external IRQs to wakeup C0~C3 from LPM */ + val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); + val |= IRQ_SRC_A53_WUP; + /* clear the MASTER0 LPM handshake */ + val &= ~MASTER0_LPM_HSK; + mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); + + /* mask M4 DSM trigger if M4 is NOT enabled */ + mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK); + + /* set all mix/PU in A53 domain */ + mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd); + + /* set SCU timming */ + mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING, + (0x59 << 10) | 0x5B | (0x2 << 20)); + + /* set DUMMY PDN/PUP ACK by default for A53 domain */ + mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | + A53_DUMMY_PDN_ACK); + + /* disable DSM mode by default */ + mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK); + + /* + * USB PHY power up needs to make sure RESET bit in SRC is clear, + * otherwise, the PU power up bit in GPC will NOT self-cleared. + * only need to do it once. + */ + mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1); + mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1); +} diff --git a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c new file mode 100644 index 00000000..45d2a40f --- /dev/null +++ b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <context.h> +#include <context_mgmt.h> +#include <debug.h> +#include <gpc.h> +#include <imx_uart.h> +#include <stdbool.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <plat_imx8.h> +#include <xlat_tables.h> +#include <tzc380.h> + +IMPORT_SYM(uintptr_t, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START); +IMPORT_SYM(uintptr_t, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END); +IMPORT_SYM(uintptr_t, __RO_START__, BL31_RO_START); +IMPORT_SYM(uintptr_t, __RO_END__, BL31_RO_END); +IMPORT_SYM(uintptr_t, __RW_START__, BL31_RW_START); +IMPORT_SYM(uintptr_t, __RW_END__, BL31_RW_END); + +static const mmap_region_t imx_mmap[] = { + MAP_REGION_FLAT(GPV_BASE, GPV_SIZE, MT_DEVICE | MT_RW), /* GPV map */ + MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */ + MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), /* GIC map */ + {0}, +}; + +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +/* get SPSR for BL33 entry */ +static uint32_t get_spsr_for_bl33_entry(void) +{ + unsigned long el_status; + unsigned long mode; + uint32_t spsr; + + /* figure out what mode we enter the non-secure world */ + el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; + el_status &= ID_AA64PFR0_ELX_MASK; + + mode = (el_status) ? MODE_EL2 : MODE_EL1; + + spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + return spsr; +} + +static void bl31_tz380_setup(void) +{ + unsigned int val; + + val = mmio_read_32(IMX_IOMUX_GPR_BASE + IOMUXC_GPR10); + if ((val & GPR_TZASC_EN) != GPR_TZASC_EN) + return; + + tzc380_init(IMX_TZASC_BASE); + /* + * Need to substact offset 0x40000000 from CPU address when + * programming tzasc region for i.mx8mq. Enable 1G-5G S/NS RW + */ + tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) | + TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL); +} + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + int i; + /* enable CSU NS access permission */ + for (i = 0; i < 64; i++) { + mmio_write_32(IMX_CSU_BASE + i * 4, 0xffffffff); + } + +#if DEBUG_CONSOLE + static console_uart_t console; + + console_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ, + IMX_CONSOLE_BAUDRATE, &console); +#endif + /* + * tell BL3-1 where the non-secure software image is located + * and the entry state information. + */ + bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET; + bl33_image_ep_info.spsr = get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + + bl31_tz380_setup(); +} + +void bl31_plat_arch_setup(void) +{ + mmap_add_region(BL31_RO_START, BL31_RO_START, (BL31_RO_END - BL31_RO_START), + MT_MEMORY | MT_RO | MT_SECURE); + mmap_add_region(BL31_RW_START, BL31_RW_START, (BL31_RW_END - BL31_RW_START), + MT_MEMORY | MT_RW | MT_SECURE); + + mmap_add(imx_mmap); + +#if USE_COHERENT_MEM + mmap_add_region(BL31_COHERENT_RAM_START, BL31_COHERENT_RAM_START, + BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START, + MT_DEVICE | MT_RW | MT_SECURE); +#endif + /* setup xlat table */ + init_xlat_tables(); + /* enable the MMU */ + enable_mmu_el3(0); +} + +void bl31_platform_setup(void) +{ + /* init the GICv3 cpu and distributor interface */ + plat_gic_driver_init(); + plat_gic_init(); + + /* gpc init */ + imx_gpc_init(); +} + +entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type) +{ + if (type == NON_SECURE) + return &bl33_image_ep_info; + if (type == SECURE) + return &bl32_image_ep_info; + + return NULL; +} + +unsigned int plat_get_syscnt_freq2(void) +{ + return COUNTER_FREQUENCY; +} + +void bl31_plat_runtime_setup(void) +{ + return; +} diff --git a/plat/imx/imx8m/imx8mq/imx8mq_psci.c b/plat/imx/imx8m/imx8mq/imx8mq_psci.c new file mode 100644 index 00000000..7afe52d3 --- /dev/null +++ b/plat/imx/imx8m/imx8mq/imx8mq_psci.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <debug.h> +#include <gpc.h> +#include <stdbool.h> +#include <plat_imx8.h> +#include <psci.h> +#include <mmio.h> + +#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) +#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) +#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) + +int imx_pwr_domain_on(u_register_t mpidr) +{ + unsigned int core_id; + uint64_t base_addr = BL31_BASE; + + core_id = MPIDR_AFFLVL0_VAL(mpidr); + + /* set the secure entrypoint */ + imx_set_cpu_secure_entry(core_id, base_addr); + /* power up the core */ + imx_set_cpu_pwr_on(core_id); + + return PSCI_E_SUCCESS; +} + +void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + /* program the GIC per cpu dist and rdist interface */ + plat_gic_pcpu_init(); + /* enable the GICv3 cpu interface */ + plat_gic_cpuif_enable(); +} + +void imx_pwr_domain_off(const psci_power_state_t *target_state) +{ + uint64_t mpidr = read_mpidr_el1(); + unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); + + /* disable the GIC cpu interface first */ + plat_gic_cpuif_disable(); + /* config the core for power down */ + imx_set_cpu_pwr_off(core_id); +} + +int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) +{ + /* The non-secure entrypoint should be in RAM space */ + if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET) + return PSCI_E_INVALID_PARAMS; + + return PSCI_E_SUCCESS; +} + +int imx_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + int pwr_type = psci_get_pstate_type(power_state); + int state_id = psci_get_pstate_id(power_state); + + if (pwr_lvl > PLAT_MAX_PWR_LVL) + return PSCI_E_INVALID_PARAMS; + + if (pwr_type == PSTATE_TYPE_STANDBY) { + CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; + CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; + } + + if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { + CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; + CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; + } + + return PSCI_E_SUCCESS; +} + +void imx_cpu_standby(plat_local_state_t cpu_state) +{ + dsb(); + write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); + isb(); + + wfi(); + + write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); + isb(); +} + +void imx_domain_suspend(const psci_power_state_t *target_state) +{ + uint64_t base_addr = BL31_BASE; + uint64_t mpidr = read_mpidr_el1(); + unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); + + if (is_local_state_off(CORE_PWR_STATE(target_state))) { + /* disable the cpu interface */ + plat_gic_cpuif_disable(); + imx_set_cpu_secure_entry(core_id, base_addr); + imx_set_cpu_lpm(core_id, true); + } else { + dsb(); + write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); + isb(); + } + + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) + imx_set_cluster_powerdown(core_id, true); + else + imx_set_cluster_standby(true); + + if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { + imx_set_sys_lpm(true); + } +} + +void imx_domain_suspend_finish(const psci_power_state_t *target_state) +{ + uint64_t mpidr = read_mpidr_el1(); + unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); + + /* check the system level status */ + if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { + imx_set_sys_lpm(false); + imx_clear_rbc_count(); + } + + /* check the cluster level power status */ + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) + imx_set_cluster_powerdown(core_id, false); + else + imx_set_cluster_standby(false); + + /* check the core level power status */ + if (is_local_state_off(CORE_PWR_STATE(target_state))) { + /* clear the core lpm setting */ + imx_set_cpu_lpm(core_id, false); + /* enable the gic cpu interface */ + plat_gic_cpuif_enable(); + } else { + write_scr_el3(read_scr_el3() & (~0x4)); + isb(); + } +} + +void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + unsigned int i; + + for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; + + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE; +} + +void __dead2 imx_system_reset(void) +{ + uintptr_t wdog_base = IMX_WDOG_BASE; + unsigned int val; + + /* WDOG_B reset */ + val = mmio_read_16(wdog_base); +#ifdef IMX_WDOG_B_RESET + val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE | + WDOG_WCR_WDT | WDOG_WCR_SRS; +#else + val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS; +#endif + mmio_write_16(wdog_base, val); + + mmio_write_16(wdog_base + WDOG_WSR, 0x5555); + mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa); + while (1) + ; +} + + + +void __dead2 imx_system_off(void) +{ + mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV | + SNVS_LPCR_DP_EN | SNVS_LPCR_TOP); + + while (1) + ; +} + +void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) +{ + if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) + imx_set_rbc_count(); + + while (1) + wfi(); +} + +static const plat_psci_ops_t imx_plat_psci_ops = { + .pwr_domain_on = imx_pwr_domain_on, + .pwr_domain_on_finish = imx_pwr_domain_on_finish, + .pwr_domain_off = imx_pwr_domain_off, + .validate_ns_entrypoint = imx_validate_ns_entrypoint, + .validate_power_state = imx_validate_power_state, + .cpu_standby = imx_cpu_standby, + .pwr_domain_suspend = imx_domain_suspend, + .pwr_domain_suspend_finish = imx_domain_suspend_finish, + .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi, + .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, + .system_reset = imx_system_reset, + .system_off = imx_system_off, +}; + +/* export the platform specific psci ops */ +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + imx_mailbox_init(sec_entrypoint); + /* sec_entrypoint is used for warm reset */ + *psci_ops = &imx_plat_psci_ops; + + return 0; +} diff --git a/plat/imx/imx8m/imx8mq/include/platform_def.h b/plat/imx/imx8m/imx8mq/include/platform_def.h new file mode 100644 index 00000000..4957582a --- /dev/null +++ b/plat/imx/imx8m/imx8mq/include/platform_def.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" +#define PLATFORM_LINKER_ARCH aarch64 + +#define PLATFORM_STACK_SIZE 0x800 +#define CACHE_WRITEBACK_GRANULE 64 + +#define PLAT_PRIMARY_CPU 0x0 +#define PLATFORM_MAX_CPU_PER_CLUSTER 4 +#define PLATFORM_CLUSTER_COUNT 1 +#define PLATFORM_CLUSTER0_CORE_COUNT 4 +#define PLATFORM_CLUSTER1_CORE_COUNT 0 +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT) + +#define IMX_PWR_LVL0 MPIDR_AFFLVL0 +#define IMX_PWR_LVL1 MPIDR_AFFLVL1 +#define IMX_PWR_LVL2 MPIDR_AFFLVL2 + +#define PWR_DOMAIN_AT_MAX_LVL U(1) +#define PLAT_MAX_PWR_LVL U(2) +#define PLAT_MAX_OFF_STATE U(4) +#define PLAT_MAX_RET_STATE U(1) + +#define PLAT_WAIT_OFF_STATE U(2) +#define PLAT_STOP_OFF_STATE U(3) + +#define BL31_BASE U(0x910000) +#define BL31_LIMIT U(0x920000) +#define BL32_BASE U(0xfe000000) + +/* non-secure uboot base */ +#define PLAT_NS_IMAGE_OFFSET U(0x40200000) + +/* GICv3 base address */ +#define PLAT_GICD_BASE U(0x38800000) +#define PLAT_GICR_BASE U(0x38880000) + +#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) +#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) + +#define MAX_XLAT_TABLES 4 +#define MAX_MMAP_REGIONS 14 + +#define HAB_RVT_BASE U(0x00000880) /* HAB_RVT for i.MX8MQ */ + +#define IMX_BOOT_UART_BASE U(0x30860000) +#define IMX_BOOT_UART_CLK_IN_HZ 25000000 /* Select 25Mhz oscillator */ +#define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE +#define PLAT_CRASH_UART_CLK_IN_HZ 25000000 +#define IMX_CONSOLE_BAUDRATE 115200 + +#define IMX_AIPS_BASE U(0x30200000) +#define IMX_AIPS_SIZE U(0xC00000) +#define IMX_AIPS1_BASE U(0x30200000) +#define IMX_AIPS3_ARB_BASE U(0x30800000) +#define IMX_ANAMIX_BASE U(0x30360000) +#define IMX_CCM_BASE U(0x30380000) +#define IMX_SRC_BASE U(0x30390000) +#define IMX_GPC_BASE U(0x303a0000) +#define IMX_RDC_BASE U(0x303d0000) +#define IMX_CSU_BASE U(0x303e0000) +#define IMX_WDOG_BASE U(0x30280000) +#define IMX_SNVS_BASE U(0x30370000) +#define IMX_NOC_BASE U(0x32700000) +#define IMX_TZASC_BASE U(0x32F80000) +#define IMX_IOMUX_GPR_BASE U(0x30340000) +#define IMX_DDRC_BASE U(0x3d400000) +#define IMX_DDRPHY_BASE U(0x3c000000) +#define IMX_DDR_IPS_BASE U(0x3d000000) +#define IMX_ROM_BASE U(0x00000000) + +#define AIPSTZ1_BASE U(0x301f0000) +#define AIPSTZ2_BASE U(0x305f0000) +#define AIPSTZ3_BASE U(0x309f0000) +#define AIPSTZ4_BASE U(0x32df0000) + +#define GPV_BASE U(0x32000000) +#define GPV_SIZE U(0x800000) +#define IMX_GIC_BASE PLAT_GICD_BASE +#define IMX_GIC_SIZE U(0x200000) + +#define WDOG_WSR U(0x2) +#define WDOG_WCR_WDZST BIT(0) +#define WDOG_WCR_WDBG BIT(1) +#define WDOG_WCR_WDE BIT(2) +#define WDOG_WCR_WDT BIT(3) +#define WDOG_WCR_SRS BIT(4) +#define WDOG_WCR_WDA BIT(5) +#define WDOG_WCR_SRE BIT(6) +#define WDOG_WCR_WDW BIT(7) + +#define SRC_A53RCR0 U(0x4) +#define SRC_A53RCR1 U(0x8) +#define SRC_OTG1PHY_SCR U(0x20) +#define SRC_OTG2PHY_SCR U(0x24) +#define SRC_GPR1_OFFSET U(0x74) + +#define SNVS_LPCR U(0x38) +#define SNVS_LPCR_SRTC_ENV BIT(0) +#define SNVS_LPCR_DP_EN BIT(5) +#define SNVS_LPCR_TOP BIT(6) + + +#define IOMUXC_GPR10 U(0x28) +#define GPR_TZASC_EN BIT(0) +#define GPR_TZASC_EN_LOCK BIT(16) + +#define OCRAM_S_BASE U(0x00180000) +#define OCRAM_S_SIZE U(0x8000) +#define OCRAM_S_LIMIT (OCRAM_S_BASE + OCRAM_S_SIZE) + +#define COUNTER_FREQUENCY 8000000 /* 8MHz */ + +#define DEBUG_CONSOLE 0 +#define IMX_WDOG_B_RESET +#define PLAT_IMX8M 1 diff --git a/plat/imx/imx8m/imx8mq/platform.mk b/plat/imx/imx8m/imx8mq/platform.mk new file mode 100644 index 00000000..0255268f --- /dev/null +++ b/plat/imx/imx8m/imx8mq/platform.mk @@ -0,0 +1,36 @@ +# +# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_INCLUDES := -Iplat/imx/common/include \ + -Iplat/imx/imx8m/include \ + -Iplat/imx/imx8m/imx8mq/include + +IMX_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ + drivers/arm/gic/v3/arm_gicv3_common.c \ + drivers/arm/gic/v3/gic500.c \ + drivers/arm/gic/v3/gicv3_main.c \ + drivers/arm/gic/common/gic_common.c \ + plat/common/plat_gicv3.c \ + plat/common/plat_psci_common.c \ + plat/imx/common/plat_imx8_gic.c + +BL31_SOURCES += plat/imx/common/imx8_helpers.S \ + plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c \ + plat/imx/imx8m/imx8mq/imx8mq_psci.c \ + plat/imx/imx8m/imx8mq/gpc.c \ + plat/imx/common/imx8_topology.c \ + plat/imx/common/imx_uart_console.S \ + lib/xlat_tables/aarch64/xlat_tables.c \ + lib/xlat_tables/xlat_tables_common.c \ + lib/cpus/aarch64/cortex_a53.S \ + drivers/console/aarch64/console.S \ + drivers/arm/tzc/tzc380.c \ + ${IMX_GIC_SOURCES} + +USE_COHERENT_MEM := 1 +RESET_TO_BL31 := 1 +A53_DISABLE_NON_TEMPORAL_HINT := 0 +MULTI_CONSOLE_API := 1 diff --git a/plat/imx/imx8m/include/gpc.h b/plat/imx/imx8m/include/gpc.h new file mode 100644 index 00000000..6fdf6ad6 --- /dev/null +++ b/plat/imx/imx8m/include/gpc.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IMX8M_GPC_H +#define IMX8M_GPC_H + +#define LPCR_A53_BSC 0x0 +#define LPCR_A53_BSC2 0x108 +#define LPCR_A53_AD 0x4 +#define LPCR_M4 0x8 +#define SLPCR 0x14 +#define MST_CPU_MAPPING 0x18 +#define MLPCR 0x20 +#define PGC_ACK_SEL_A53 0x24 +#define IMR1_CORE0_A53 0x30 +#define IMR1_CORE1_A53 0x40 +#define IMR1_CORE2_A53 0x1C0 +#define IMR1_CORE3_A53 0x1D0 +#define IMR1_CORE0_M4 0x50 +#define SLT0_CFG 0xB0 +#define GPC_PU_PWRHSK 0x1FC +#define PGC_CPU_0_1_MAPPING 0xEC +#define CPU_PGC_UP_TRG 0xF0 +#define PU_PGC_UP_TRG 0xF8 +#define CPU_PGC_DN_TRG 0xFC +#define PU_PGC_DN_TRG 0x104 +#define A53_CORE0_PGC 0x800 +#define A53_PLAT_PGC 0x900 +#define PGC_SCU_TIMING 0x910 + +#define MASK_DSM_TRIGGER_A53 BIT(31) +#define IRQ_SRC_A53_WUP BIT(30) +#define IRQ_SRC_C1 BIT(29) +#define IRQ_SRC_C0 BIT(28) +#define IRQ_SRC_C3 BIT(23) +#define IRQ_SRC_C2 BIT(22) +#define CPU_CLOCK_ON_LPM BIT(14) +#define MASTER0_LPM_HSK BIT(6) + +#define L2PGE BIT(31) +#define EN_L2_WFI_PDN BIT(5) +#define EN_PLAT_PDN BIT(4) + +#define SLPCR_EN_DSM BIT(31) +#define SLPCR_RBC_EN BIT(30) +#define SLPCR_A53_FASTWUP_STOP_MODE BIT(17) +#define SLPCR_A53_FASTWUP_WAIT_MODE BIT(16) +#define SLPCR_VSTBY BIT(2) +#define SLPCR_SBYOS BIT(1) +#define SLPCR_BYPASS_PMIC_READY BIT(0) +#define SLPCR_RBC_COUNT_SHIFT 24 + +#define A53_DUMMY_PDN_ACK BIT(15) +#define A53_DUMMY_PUP_ACK BIT(31) +#define A53_PLAT_PDN_ACK BIT(2) +#define A53_PLAT_PUP_ACK BIT(18) + +#define SLT_PLAT_PDN BIT(8) +#define SLT_PLAT_PUP BIT(9) + +/* helper macro */ +#define A53_LPM_MASK U(0xF) +#define A53_LPM_WAIT U(0x5) +#define A53_LPM_STOP U(0xA) + +#define DSM_MODE_MASK BIT(31) + +#define A53_CORE_WUP_SRC(core_id) (1 << ((core_id) < 2 ? 28 + (core_id) : 22 + (core_id) - 2)) +#define COREx_PGC_PCR(core_id) (0x800 + (core_id) * 0x40) +#define COREx_WFI_PDN(core_id) (1 << ((core_id) < 2 ? (core_id) * 2 : ((core_id) - 2) * 2 + 16)) +#define COREx_IRQ_WUP(core_id) ((core_id) < 2 ? (1 << ((core_id) * 2 + 8)) : (1 << ((core_id) * 2 + 20))) +#define COREx_LPM_PUP(core_id) ((core_id) < 2 ? (1 << ((core_id) * 2 + 9)) : (1 << ((core_id) * 2 + 21))) +#define SLTx_CFG(n) ((SLT0_CFG + ((n) * 4))) +#define SLT_COREx_PUP(core_id) (0x2 << ((core_id) * 2)) + +/* function declare */ +void imx_gpc_init(void); +void imx_set_cpu_secure_entry(unsigned int core_index, uintptr_t sec_entrypoint); +void imx_set_cpu_pwr_off(unsigned int core_index); +void imx_set_cpu_pwr_on(unsigned int core_index); +void imx_set_cpu_lpm(unsigned int core_index, bool pdn); +void imx_set_cluster_standby(bool retention); +void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state); +void imx_set_sys_lpm(bool retention); +void imx_set_rbc_count(void); +void imx_clear_rbc_count(void); + +#endif /*IMX8M_GPC_H */ diff --git a/plat/layerscape/board/ls1043/include/soc_tzasc.h b/plat/layerscape/board/ls1043/include/soc_tzasc.h index b2483d98..46dfba0f 100644 --- a/plat/layerscape/board/ls1043/include/soc_tzasc.h +++ b/plat/layerscape/board/ls1043/include/soc_tzasc.h @@ -7,8 +7,6 @@ #ifndef SOC_TZASC_H #define SOC_TZASC_H -#include "tzc380.h" - #define MAX_NUM_TZC_REGION 3 /* TZASC related constants */ @@ -58,6 +56,15 @@ #define CCI_TERMINATE_BARRIER_TX 0x8 #define CONFIG_SYS_FSL_TZASC_ADDR 0x1500000 +struct tzc380_reg { + unsigned int secure; + unsigned int enabled; + unsigned int low_addr; + unsigned int high_addr; + unsigned int size; + unsigned int sub_mask; +}; + /* List of MAX_NUM_TZC_REGION TZC regions' boundaries and configurations. */ static const struct tzc380_reg tzc380_reg_list[] = { diff --git a/plat/layerscape/common/include/tzc380.h b/plat/layerscape/common/include/tzc380.h deleted file mode 100644 index 88063a97..00000000 --- a/plat/layerscape/common/include/tzc380.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef TZC380_H -#define TZC380_H - -struct tzc380_reg { - unsigned int secure; - unsigned int enabled; - unsigned int low_addr; - unsigned int high_addr; - unsigned int size; - unsigned int sub_mask; -}; - -#endif /* TZC380_H */ diff --git a/plat/marvell/a3700/common/plat_pm.c b/plat/marvell/a3700/common/plat_pm.c index 5cebc922..dce48416 100644 --- a/plat/marvell/a3700/common/plat_pm.c +++ b/plat/marvell/a3700/common/plat_pm.c @@ -288,18 +288,9 @@ int a3700_validate_ns_entrypoint(uintptr_t entrypoint) */ void a3700_pwr_domain_off(const psci_power_state_t *target_state) { - uint32_t cpu_idx = plat_my_core_pos(); - /* Prevent interrupts from spuriously waking up this cpu */ plat_marvell_gic_cpuif_disable(); - /* - * Enable Core VDD OFF, core is supposed to be powered - * off by PMU when WFI command is issued. - */ - mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG + 4 * cpu_idx, - MVEBU_PM_CORE_PD); - /* Core can not be powered down with pending IRQ, * acknowledge all the pending IRQ */ diff --git a/plat/marvell/a8k/a80x0/board/phy-porting-layer.h b/plat/marvell/a8k/a80x0/board/phy-porting-layer.h index 38497fb5..abd85b5d 100644 --- a/plat/marvell/a8k/a80x0/board/phy-porting-layer.h +++ b/plat/marvell/a8k/a80x0/board/phy-porting-layer.h @@ -27,7 +27,14 @@ static const struct xfi_params .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy2 */ { 0 }, /* Comphy3 */ - { 0 }, /* Comphy4 */ + { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, + .align90 = 0x5f, + .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, + .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, + .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, + .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, + .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, + .valid = 0x1 }, /* Comphy4 */ { 0 }, /* Comphy5 */ }, @@ -44,7 +51,14 @@ static const struct xfi_params .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy2 */ { 0 }, /* Comphy3 */ - { 0 }, /* Comphy4 */ + { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, + .align90 = 0x5f, + .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, + .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, + .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, + .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, + .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, + .valid = 0x1 }, /* Comphy4 */ { 0 }, /* Comphy5 */ }, }, diff --git a/plat/marvell/a8k/common/a8k_common.mk b/plat/marvell/a8k/common/a8k_common.mk index 6136a1f5..88d93111 100644 --- a/plat/marvell/a8k/common/a8k_common.mk +++ b/plat/marvell/a8k/common/a8k_common.mk @@ -13,6 +13,9 @@ PLAT_COMMON_BASE := $(PLAT_FAMILY_BASE)/common MARVELL_DRV_BASE := drivers/marvell MARVELL_COMMON_BASE := plat/marvell/common +MARVELL_SVC_TEST := 0 +$(eval $(call add_define,MARVELL_SVC_TEST)) + ERRATA_A72_859971 := 1 # Enable MSS support for a8k family @@ -60,14 +63,15 @@ BLE_PORTING_SOURCES := $(PLAT_FAMILY_BASE)/$(PLAT)/board/dram_port.c \ MARVELL_MOCHI_DRV += $(MARVELL_DRV_BASE)/mochi/cp110_setup.c -BLE_SOURCES := drivers/mentor/i2c/mi2cv.c \ - $(PLAT_COMMON_BASE)/plat_ble_setup.c \ - $(MARVELL_MOCHI_DRV) \ - $(PLAT_COMMON_BASE)/plat_pm.c \ - $(MARVELL_DRV_BASE)/thermal.c \ - $(PLAT_COMMON_BASE)/plat_thermal.c \ - $(BLE_PORTING_SOURCES) \ - $(MARVELL_DRV_BASE)/ccu.c \ +BLE_SOURCES := drivers/mentor/i2c/mi2cv.c \ + $(PLAT_COMMON_BASE)/plat_ble_setup.c \ + $(MARVELL_MOCHI_DRV) \ + $(PLAT_COMMON_BASE)/plat_pm.c \ + $(MARVELL_DRV_BASE)/ap807_clocks_init.c \ + $(MARVELL_DRV_BASE)/thermal.c \ + $(PLAT_COMMON_BASE)/plat_thermal.c \ + $(BLE_PORTING_SOURCES) \ + $(MARVELL_DRV_BASE)/ccu.c \ $(MARVELL_DRV_BASE)/io_win.c BL1_SOURCES += $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \ diff --git a/plat/marvell/a8k/common/mss/mss_pm_ipc.c b/plat/marvell/a8k/common/mss/mss_pm_ipc.c index 6ff4abcc..d1297b07 100644 --- a/plat/marvell/a8k/common/mss/mss_pm_ipc.c +++ b/plat/marvell/a8k/common/mss/mss_pm_ipc.c @@ -26,7 +26,7 @@ #define MSS_MSG_INT_MASK (0x80000000) #define MSS_TIMER_BASE (MVEBU_REGS_BASE_MASK + 0x580110) -#define MSS_TRIGGER_TIMEOUT (1000) +#define MSS_TRIGGER_TIMEOUT (2000) /***************************************************************************** * mss_pm_ipc_msg_send diff --git a/plat/marvell/a8k/common/plat_ble_setup.c b/plat/marvell/a8k/common/plat_ble_setup.c index 7438f69c..dbadeb76 100644 --- a/plat/marvell/a8k/common/plat_ble_setup.c +++ b/plat/marvell/a8k/common/plat_ble_setup.c @@ -15,14 +15,15 @@ #include <mv_ddr_if.h> #include <mvebu_def.h> #include <plat_marvell.h> +#include "ap807_clocks_init.h" /* Register for skip image use */ #define SCRATCH_PAD_REG2 0xF06F00A8 #define SCRATCH_PAD_SKIP_VAL 0x01 #define NUM_OF_GPIO_PER_REG 32 -#define MMAP_SAVE_AND_CONFIG 0 -#define MMAP_RESTORE_SAVED 1 +#define MMAP_SAVE_AND_CONFIG 0 +#define MMAP_RESTORE_SAVED 1 /* SAR clock settings */ #define MVEBU_AP_GEN_MGMT_BASE (MVEBU_RFU_BASE + 0x8000) @@ -40,6 +41,7 @@ #define SAR_CLOCK_FREQ_MODE(v) (((v) & SAR_CLOCK_FREQ_MODE_MASK) >> \ SAR_CLOCK_FREQ_MODE_OFFSET) +#define AVS_I2C_EEPROM_ADDR 0x57 /* EEPROM */ #define AVS_EN_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x130) #define AVS_ENABLE_OFFSET (0) #define AVS_SOFT_RESET_OFFSET (2) @@ -71,28 +73,25 @@ (0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \ (0x1 << AVS_SOFT_RESET_OFFSET) | \ (0x1 << AVS_ENABLE_OFFSET)) - +/* VDD limit is 0.82V for all A3900 devices + * AVS offsets are not the same as in A70x0 + */ #define AVS_A3900_CLK_VALUE ((0x80 << 24) | \ (0x2c2 << 13) | \ (0x2c2 << 3) | \ (0x1 << AVS_SOFT_RESET_OFFSET) | \ (0x1 << AVS_ENABLE_OFFSET)) +/* VDD is 0.88V for 2GHz clock */ +#define AVS_A3900_HIGH_CLK_VALUE ((0x80 << 24) | \ + (0x2f5 << 13) | \ + (0x2f5 << 3) | \ + (0x1 << AVS_SOFT_RESET_OFFSET) | \ + (0x1 << AVS_ENABLE_OFFSET)) #define MVEBU_AP_EFUSE_SRV_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x8) #define EFUSE_SRV_CTRL_LD_SELECT_OFFS 6 #define EFUSE_SRV_CTRL_LD_SEL_USER_MASK (1 << EFUSE_SRV_CTRL_LD_SELECT_OFFS) -/* Notify bootloader on DRAM setup */ -#define AP807_CPU_ARO_0_CTRL_0 (MVEBU_RFU_BASE + 0x82A8) -#define AP807_CPU_ARO_1_CTRL_0 (MVEBU_RFU_BASE + 0x8D00) - -/* 0 - ARO clock is enabled, 1 - ARO clock is disabled */ -#define AP807_CPU_ARO_CLK_EN_OFFSET 0 -#define AP807_CPU_ARO_CLK_EN_MASK (0x1 << AP807_CPU_ARO_CLK_EN_OFFSET) - -/* 0 - ARO is the clock source, 1 - PLL is the clock source */ -#define AP807_CPU_ARO_SEL_PLL_OFFSET 5 -#define AP807_CPU_ARO_SEL_PLL_MASK (0x1 << AP807_CPU_ARO_SEL_PLL_OFFSET) /* * - Identification information in the LD-0 eFuse: @@ -143,9 +142,16 @@ #define EFUSE_AP_LD0_WP_MASK 0x3FF #endif -#define EFUSE_AP_LD0_SVC4_OFFS 42 /* LD0[112:105] */ +#define EFUSE_AP_LD0_SVC4_OFFS 42 /* LD0[112:105] */ -#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS 4 +#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS 4 + +#if MARVELL_SVC_TEST +#define MVEBU_CP_MPP_CTRL37_OFFS 20 +#define MVEBU_CP_MPP_CTRL38_OFFS 24 +#define MVEBU_CP_MPP_I2C_FUNC 2 +#define MVEBU_MPP_CTRL_MASK 0xf +#endif /* Return the AP revision of the chip */ static unsigned int ble_get_ap_type(void) @@ -205,41 +211,156 @@ static void ble_plat_mmap_config(int restore) * Setup Adaptive Voltage Switching - this is required for some platforms **************************************************************************** */ +#if !MARVELL_SVC_TEST static void ble_plat_avs_config(void) { - uint32_t reg_val, device_id; + uint32_t freq_mode, device_id; + uint32_t avs_val = 0; + freq_mode = + SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE( + FREQ_MODE_AP_SAR_REG_NUM))); /* Check which SoC is running and act accordingly */ if (ble_get_ap_type() == CHIP_ID_AP807) { - VERBOSE("AVS: Setting AP807 AVS CTRL to 0x%x\n", - AVS_A3900_CLK_VALUE); - mmio_write_32(AVS_EN_CTRL_REG, AVS_A3900_CLK_VALUE); - return; + /* Increase CPU voltage for higher CPU clock */ + if (freq_mode == CPU_2000_DDR_1200_RCLK_1200) + avs_val = AVS_A3900_HIGH_CLK_VALUE; + else + avs_val = AVS_A3900_CLK_VALUE; + } else { + /* Check which SoC is running and act accordingly */ + device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); + switch (device_id) { + case MVEBU_80X0_DEV_ID: + case MVEBU_80X0_CP115_DEV_ID: + /* Always fix the default AVS value on A80x0 */ + avs_val = AVS_A8K_CLK_VALUE; + break; + case MVEBU_70X0_DEV_ID: + case MVEBU_70X0_CP115_DEV_ID: + /* Fix AVS for CPU clocks lower than 1600MHz on A70x0 */ + if ((freq_mode > CPU_1600_DDR_900_RCLK_900_2) && + (freq_mode < CPU_DDR_RCLK_INVALID)) + avs_val = AVS_A7K_LOW_CLK_VALUE; + break; + default: + ERROR("Unsupported Device ID 0x%x\n", device_id); + return; + } } - /* Check which SoC is running and act accordingly */ - device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); - switch (device_id) { - case MVEBU_80X0_DEV_ID: - case MVEBU_80X0_CP115_DEV_ID: - /* Set the new AVS value - fix the default one on A80x0 */ - mmio_write_32(AVS_EN_CTRL_REG, AVS_A8K_CLK_VALUE); - break; - case MVEBU_70X0_DEV_ID: - case MVEBU_70X0_CP115_DEV_ID: - /* Only fix AVS for CPU clocks lower than 1600MHz on A70x0 */ - reg_val = mmio_read_32(MVEBU_AP_SAR_REG_BASE( - FREQ_MODE_AP_SAR_REG_NUM)); - reg_val &= SAR_CLOCK_FREQ_MODE_MASK; - reg_val >>= SAR_CLOCK_FREQ_MODE_OFFSET; - if ((reg_val > CPU_1600_DDR_900_RCLK_900_2) && - (reg_val < CPU_DDR_RCLK_INVALID)) - mmio_write_32(AVS_EN_CTRL_REG, AVS_A7K_LOW_CLK_VALUE); - break; - default: - ERROR("Unsupported Device ID 0x%x\n", device_id); + if (avs_val) { + VERBOSE("AVS: Setting AVS CTRL to 0x%x\n", avs_val); + mmio_write_32(AVS_EN_CTRL_REG, avs_val); } } +#endif +/****************************************************************************** + * Update or override current AVS work point value using data stored in EEPROM + * This is only required by QA/validation flows and activated by + * MARVELL_SVC_TEST flag. + * + * The function is expected to be called twice. + * + * First time with AVS value of 0 for testing if the EEPROM requests completely + * override the AVS value and bypass the eFuse test + * + * Second time - with non-zero AVS value obtained from eFuses as an input. + * In this case the EEPROM may contain AVS correction value (either positive + * or negative) that is added to the input AVS value and returned back for + * further processing. + ****************************************************************************** + */ +static uint32_t avs_update_from_eeprom(uint32_t avs_workpoint) +{ + uint32_t new_wp = avs_workpoint; +#if MARVELL_SVC_TEST + /* --------------------------------------------------------------------- + * EEPROM | Data description (avs_step) + * address | + * --------------------------------------------------------------------- + * 0x120 | AVS workpoint correction value + * | if not 0 and not 0xff, correct the AVS taken from eFuse + * | by the number of steps indicated by bit[6:0] + * | bit[7] defines correction direction. + * | If bit[7]=1, add the value from bit[6:0] to AVS workpoint, + * | othervise substruct this value from AVS workpoint. + * --------------------------------------------------------------------- + * 0x121 | AVS workpoint override value + * | Override the AVS workpoint with the value stored in this + * | byte. When running on AP806, the AVS workpoint is 7 bits + * | wide and override value is valid when bit[6:0] holds + * | value greater than zero and smaller than 0x33. + * | When running on AP807, the AVS workpoint is 10 bits wide. + * | Additional 2 MSB bits are supplied by EEPROM byte 0x122. + * | AVS override value is valid when byte @ 0x121 and bit[1:0] + * | of byte @ 0x122 combined have non-zero value. + * --------------------------------------------------------------------- + * 0x122 | Extended AVS workpoint override value + * | Valid only for AP807 platforms and must be less than 0x4 + * --------------------------------------------------------------------- + */ + static uint8_t avs_step[3] = {0}; + uintptr_t reg; + uint32_t val; + unsigned int ap_type = ble_get_ap_type(); + + /* Always happens on second call to this function */ + if (avs_workpoint != 0) { + /* Get correction steps from the EEPROM */ + if ((avs_step[0] != 0) && (avs_step[0] != 0xff)) { + NOTICE("AVS request to step %s by 0x%x from old 0x%x\n", + avs_step[0] & 0x80 ? "DOWN" : "UP", + avs_step[0] & 0x7f, new_wp); + if (avs_step[0] & 0x80) + new_wp -= avs_step[0] & 0x7f; + else + new_wp += avs_step[0] & 0x7f; + } + + return new_wp; + } + + /* AVS values are located in EEPROM + * at CP0 i2c bus #0, device 0x57 offset 0x120 + * The SDA and SCK pins of CP0 i2c-0: MPP[38:37], i2c function 0x2. + */ + reg = MVEBU_CP_MPP_REGS(0, 4); + val = mmio_read_32(reg); + val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) | + (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS)); + val |= (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL37_OFFS) | + (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL38_OFFS); + mmio_write_32(reg, val); + + /* Init CP0 i2c-0 */ + i2c_init((void *)(MVEBU_CP0_I2C_BASE)); + + /* Read EEPROM only once at the fist call! */ + i2c_read(AVS_I2C_EEPROM_ADDR, 0x120, 2, avs_step, 3); + NOTICE("== SVC test build ==\n"); + NOTICE("EEPROM holds values 0x%x, 0x%x and 0x%x\n", + avs_step[0], avs_step[1], avs_step[2]); + + /* Override the AVS value? */ + if ((ap_type != CHIP_ID_AP807) && (avs_step[1] < 0x33)) { + /* AP806 - AVS is 7 bits */ + new_wp = avs_step[1]; + + } else if (ap_type == CHIP_ID_AP807 && (avs_step[2] < 0x4)) { + /* AP807 - AVS is 10 bits */ + new_wp = avs_step[2]; + new_wp <<= 8; + new_wp |= avs_step[1]; + } + + if (new_wp == 0) + NOTICE("Ignore BAD AVS Override value in EEPROM!\n"); + else + NOTICE("Override AVS by EEPROM value 0x%x\n", new_wp); +#endif /* MARVELL_SVC_TEST */ + return new_wp; +} /**************************************************************************** * SVC flow - v0.10 @@ -262,6 +383,11 @@ static void ble_plat_svc_config(void) unsigned int ap_type; /* Set access to LD0 */ + avs_workpoint = avs_update_from_eeprom(0); + if (avs_workpoint) + goto set_aws_wp; + + /* Set access to LD0 */ reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG); reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_OFFS; mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val); @@ -279,7 +405,12 @@ static void ble_plat_svc_config(void) sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK; if (sw_ver < 1) { NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver); +#if MARVELL_SVC_TEST + NOTICE("SVC_TEST: AVS bypassed\n"); + +#else ble_plat_avs_config(); +#endif return; } @@ -447,6 +578,10 @@ static void ble_plat_svc_config(void) if (ap_type != CHIP_ID_AP807) avs_workpoint &= 0x7F; + /* Update WP from EEPROM if needed */ + avs_workpoint = avs_update_from_eeprom(avs_workpoint); + +set_aws_wp: reg_val = mmio_read_32(AVS_EN_CTRL_REG); NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n", (reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET, @@ -543,35 +678,11 @@ static int ble_skip_current_image(void) } #endif -/* Switch to ARO from PLL in ap807 */ -static void aro_to_pll(void) -{ - unsigned int reg; - - /* switch from ARO to PLL */ - reg = mmio_read_32(AP807_CPU_ARO_0_CTRL_0); - reg |= AP807_CPU_ARO_SEL_PLL_MASK; - mmio_write_32(AP807_CPU_ARO_0_CTRL_0, reg); - - reg = mmio_read_32(AP807_CPU_ARO_1_CTRL_0); - reg |= AP807_CPU_ARO_SEL_PLL_MASK; - mmio_write_32(AP807_CPU_ARO_1_CTRL_0, reg); - - mdelay(1000); - - /* disable ARO clk driver */ - reg = mmio_read_32(AP807_CPU_ARO_0_CTRL_0); - reg |= (AP807_CPU_ARO_CLK_EN_MASK); - mmio_write_32(AP807_CPU_ARO_0_CTRL_0, reg); - - reg = mmio_read_32(AP807_CPU_ARO_1_CTRL_0); - reg |= (AP807_CPU_ARO_CLK_EN_MASK); - mmio_write_32(AP807_CPU_ARO_1_CTRL_0, reg); -} int ble_plat_setup(int *skip) { int ret; + unsigned int freq_mode; /* Power down unused CPUs */ plat_marvell_early_cpu_powerdown(); @@ -598,9 +709,14 @@ int ble_plat_setup(int *skip) /* Setup AVS */ ble_plat_svc_config(); + /* read clk option from sampled-at-reset register */ + freq_mode = + SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE( + FREQ_MODE_AP_SAR_REG_NUM))); + /* work with PLL clock driver in AP807 */ if (ble_get_ap_type() == CHIP_ID_AP807) - aro_to_pll(); + ap807_clocks_init(freq_mode); /* Do required AP setups for BLE stage */ ap_ble_init(); diff --git a/plat/marvell/a8k/common/plat_pm.c b/plat/marvell/a8k/common/plat_pm.c index 1b68d076..28544169 100644 --- a/plat/marvell/a8k/common/plat_pm.c +++ b/plat/marvell/a8k/common/plat_pm.c @@ -79,7 +79,7 @@ enum CPU_ID { #define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 1 #define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET 0 #else -#define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 0 + #define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 0 #define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET 31 #endif @@ -106,7 +106,7 @@ enum CPU_ID { #define AP807_PWRC_LDO_CR0_OFFSET 16 #define AP807_PWRC_LDO_CR0_MASK \ (0xff << AP807_PWRC_LDO_CR0_OFFSET) -#define AP807_PWRC_LDO_CR0_VAL 0xfd +#define AP807_PWRC_LDO_CR0_VAL 0xfc /* * Power down CPU: diff --git a/plat/marvell/common/mrvl_sip_svc.c b/plat/marvell/common/mrvl_sip_svc.c index 8bc633b1..bc4b6211 100644 --- a/plat/marvell/common/mrvl_sip_svc.c +++ b/plat/marvell/common/mrvl_sip_svc.c @@ -87,7 +87,7 @@ uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid, SMC_RET1(handle, ret); case MV_SIP_COMPHY_POWER_OFF: /* x1: comphy_base, x2: comphy_index */ - ret = mvebu_cp110_comphy_power_off(x1, x2); + ret = mvebu_cp110_comphy_power_off(x1, x2, x3); SMC_RET1(handle, ret); case MV_SIP_COMPHY_PLL_LOCK: /* x1: comphy_base, x2: comphy_index */ diff --git a/plat/marvell/version.mk b/plat/marvell/version.mk index 16b0a16a..e072e12d 100644 --- a/plat/marvell/version.mk +++ b/plat/marvell/version.mk @@ -1 +1 @@ -SUBVERSION = devel-18.09.1 +SUBVERSION = devel-18.12.0 |