diff options
-rw-r--r-- | drivers/marvell/aro.c | 345 | ||||
-rw-r--r-- | include/drivers/marvell/aro.h | 77 | ||||
-rw-r--r-- | plat/marvell/a8k/common/a8k_common.mk | 12 | ||||
-rw-r--r-- | plat/marvell/a8k/common/plat_ble_setup.c | 23 |
4 files changed, 432 insertions, 25 deletions
diff --git a/drivers/marvell/aro.c b/drivers/marvell/aro.c new file mode 100644 index 00000000..72a1bcbf --- /dev/null +++ b/drivers/marvell/aro.c @@ -0,0 +1,345 @@ +/* +* *************************************************************************** +* Copyright (C) 2017 Marvell International Ltd. +* *************************************************************************** +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* Neither the name of Marvell nor the names of its contributors may be used +* to endorse or promote products derived from this software without specific +* prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*************************************************************************** +*/ + +#include <plat_def.h> +#include <debug.h> +#include <mmio.h> +#include <aro.h> +#include <mvebu.h> +#include <plat_config.h> +#include <delay_timer.h> + +#define CPU_ARO_CTRL_BASE MVEBU_REGS_BASE + (0x6F8D00) +#define SAR_REG_ADDR MVEBU_REGS_BASE + 0x6f4400 +#define RST2_CLOCK_FREQ_MODE_OFFS 0 +#define RST2_CLOCK_FREQ_MODE_MASK 0x1f + +/* cpu0_pll_ro_cfg0 + * cpu1_pll_ro_cfg0 + */ +#define CPU_ARO_CTRL0(CPU) (CPU_ARO_CTRL_BASE + 0x08 + (CPU * 0xc)) + +/* Enable ARO Value */ +#define USR_REF_STOP_CPU_CNT_OFF 0 +#define USR_REF_STOP_CPU_CNT_MASK (0x1 << USR_REF_STOP_CPU_CNT_OFF) +#define USR_RO_RESET_OFF 5 +#define USR_RO_RESET_MASK (0x1 << USR_RO_RESET_OFF) + +/* cpu0_pll_ro_cfg1 + * cpu1_pll_ro_cfg1 + */ +#define CPU_ARO_CTRL1(CPU) (CPU_ARO_CTRL_BASE + 0x0c + (CPU * 0xc)) + +/* Set initial ARO freq targets */ +#define UPDATED_VAL_OFF 16 +#define UPDATED_VAL_MASK (0x7 << UPDATED_VAL_OFF) +#define CHOOSE_TRGT1_FREQ_OFF 12 +#define CHOOSE_TRGT1_FREQ_MASK (0x8 << CHOOSE_TRGT1_FREQ_OFF) +#define CHOOSE_PLL_OFF 4 +#define CHOOSE_PLL_MASK (0x8 << CHOOSE_PLL_OFF) + +/* Stop Forcing Calibration mode */ +#define USER_RO_SEL_TRGT_OFF 18 +#define USER_RO_SEL_TRGT_MASK (0x1 << USER_RO_SEL_TRGT_OFF) + +#define USER_UPDATE_RO_TRGT_OFF 17 +#define USER_UPDATE_RO_TRGT_MASK (0x1 << USER_UPDATE_RO_TRGT_OFF) + +#define CHANGE_PLL_TO_ARO_OFF 16 +#define CHANGE_PLL_TO_ARO_MASK (0x1 << CHANGE_PLL_TO_ARO_OFF) + +#define ENABLE_CALIB_MODE_OFF 21 +#define ENABLE_CALIB_MODE_MASK (0x1 << ENABLE_CALIB_MODE_OFF) + +/* cpu0_pll_ro_cfg2 + * cpu1_pll_ro_cfg2 + */ +#define CPU_ARO_CTRL2(CPU) (CPU_ARO_CTRL_BASE + 0x10 + (CPU * 0xc)) + +/* Initialize the calibration counters. */ +#define INIT_CALIB_COUNTER_OFF 0 +#define INIT_CALIB_COUNTER_MASK (0x7fffffff << INIT_CALIB_COUNTER_OFF) + +#define SET_ARO_TARGET_OFF 0 +#define SET_ARO_TARGET_MASK (0x7fffffff << SET_ARO_TARGET_OFF) + +#define SET_REF_INIT_VAL_OFF 31 +#define SET_REF_INIT_VAL_MASK (0x1 << SET_REF_INIT_VAL_OFF) + +/* cpu1_pll_ro_cfg2 */ +#define DEV_GENERIC_CTRL_32 CPU_ARO_CTRL_BASE + (0x20) + +/* Change the ARO bypass mux to point on the ARO */ +#define CHANGE_ARO_BYPASS_OFF 0 +#define CHANGE_ARO_BYPASS_MASK (0x3 << CHANGE_ARO_BYPASS_OFF) + +void reg_set_val(uintptr_t addr, uint32_t data, uint32_t mask) +{ + uint32_t reg_data; + reg_data = mmio_read_32(addr); + reg_data &= ~mask; + reg_data |= data; + mmio_write_32(addr, reg_data); +} + +/* Take the ARO module out of reset, + * set the correct clock tree muxing to start working with the ARO, + * set the initial ARO freq targets (~600Mhz) + * note: after This stage - PLL still drivers the CPU clock + */ +static unsigned int enable_aro_module(void) +{ + unsigned int mask, data; + /* -Set the Ref counter to stop the CPU counter, + * Needed for calibration mode + * -Take the ARO out of reset + */ + data = 0x1 << USR_RO_RESET_OFF; + mask = USR_RO_RESET_MASK; + data |= 0x1 << USR_REF_STOP_CPU_CNT_OFF; + mask |= USR_REF_STOP_CPU_CNT_MASK; + + /* Write registers for cluster 0 and cluster 1 */ + reg_set_val(CPU_ARO_CTRL0(0), data, mask); + reg_set_val(CPU_ARO_CTRL0(1), data, mask); + + /* -Take the update values + * -Choose taregt 1 Freq + * -Choose the PLL + * -Initial target freq in USER mode + * -Initial target freq in calibration mode + */ + data = 0x7 << UPDATED_VAL_OFF; + mask = UPDATED_VAL_MASK; + data |= 0x8 << CHOOSE_TRGT1_FREQ_OFF; + mask |= CHOOSE_TRGT1_FREQ_MASK; + data |= 0x8 << CHOOSE_PLL_OFF; + mask |= CHOOSE_PLL_MASK; + reg_set_val(CPU_ARO_CTRL1(0), data, mask); + reg_set_val(CPU_ARO_CTRL1(1), data, mask); + + /* Change the ARO bypass mux to point on the ARO */ + data = 0x0 << CHANGE_ARO_BYPASS_OFF; + mask = CHANGE_ARO_BYPASS_MASK; + reg_set_val(DEV_GENERIC_CTRL_32, data, mask); + + return 0; +} + +/* Initialize the calibration counters + * set the ARO to intermediate targets + * change from PLL to ARO + */ +static void start_aro_mode(unsigned int ref_counter_init_val, unsigned int cpu_counter_init_val) +{ + unsigned int data, mask; + + /* Initialize the calibration counters */ + data = (ref_counter_init_val - 1) << INIT_CALIB_COUNTER_OFF; + mask = INIT_CALIB_COUNTER_MASK; + reg_set_val(CPU_ARO_CTRL2(0), data, mask); + reg_set_val(CPU_ARO_CTRL2(1), data, mask); + + /* Set ref_init_val_ld */ + data = 0x1 << SET_REF_INIT_VAL_OFF; + mask = SET_REF_INIT_VAL_MASK; + reg_set_val(CPU_ARO_CTRL2(0), data, mask); + reg_set_val(CPU_ARO_CTRL2(1), data, mask); + + /* Wait 1 nanosecond */ + udelay(1); + + /* clear ref_init_val_ld */ + data = 0x0 << SET_REF_INIT_VAL_OFF; + mask = SET_REF_INIT_VAL_MASK; + reg_set_val(CPU_ARO_CTRL2(0), data, mask); + reg_set_val(CPU_ARO_CTRL2(1), data, mask); + + /* Wait 1 microsecond */ + udelay(1); + + /* Set the ARO to intermediate targets */ + data = cpu_counter_init_val << SET_ARO_TARGET_OFF; + mask = SET_ARO_TARGET_MASK; + reg_set_val(CPU_ARO_CTRL2(0), data, mask); + reg_set_val(CPU_ARO_CTRL2(1), data, mask); + + /* Change from PLL to ARO */ + data = 0x0 << CHANGE_PLL_TO_ARO_OFF; + mask = CHANGE_PLL_TO_ARO_MASK; + reg_set_val(CPU_ARO_CTRL1(0), data, mask); + reg_set_val(CPU_ARO_CTRL1(1), data, mask); + + /* enable calibration mode. */ + data = 0x1 << ENABLE_CALIB_MODE_OFF; + mask = ENABLE_CALIB_MODE_MASK; + reg_set_val(CPU_ARO_CTRL1(0), data, mask); + reg_set_val(CPU_ARO_CTRL1(1), data, mask); +} + +/* list of allowed frequencies listed in order of enum hws_freq */ +uint32_t cpu_freq_val[DDR_FREQ_LAST] = { + 2000, /* CPU_FREQ_2000 */ + 1800, /* CPU_FREQ_1800 */ + 1600, /* CPU_FREQ_1600 */ + 1400, /* CPU_FREQ_1400 */ + 1300, /* CPU_FREQ_1300 */ + 1200, /* CPU_FREQ_1200 */ + 1000, /* CPU_FREQ_1000 */ + 600, /* CPU_FREQ_600 */ + 800, /* CPU_FREQ_800 */ +}; + +/* return CPU frequency from sar */ +static int sar_freq_get(int dev_num, enum hws_freq *freq) +{ + uint32_t clk_config; + + /* Read clk config from sar */ + clk_config = (mmio_read_32(SAR_REG_ADDR) >> + RST2_CLOCK_FREQ_MODE_OFFS) & + RST2_CLOCK_FREQ_MODE_MASK; + + switch (clk_config) { + case CPU_2000_DDR_1200_RCLK_1200: + *freq = CPU_FREQ_2000; + break; + case CPU_2000_DDR_1050_RCLK_1050: + *freq = CPU_FREQ_2000; + break; + case CPU_1600_DDR_800_RCLK_800: + *freq = CPU_FREQ_1600; + break; + case CPU_1800_DDR_1200_RCLK_1200: + *freq = CPU_FREQ_1800; + break; + case CPU_1800_DDR_1050_RCLK_1050: + *freq = CPU_FREQ_1800; + break; + case CPU_1600_DDR_1050_RCLK_1050: + *freq = CPU_FREQ_1600; + break; + case CPU_1000_DDR_650_RCLK_650: + *freq = CPU_FREQ_1000; + break; + case CPU_1300_DDR_800_RCLK_800: + *freq = CPU_FREQ_1300; + break; + case CPU_1300_DDR_650_RCLK_650: + *freq = CPU_FREQ_1300; + break; + case CPU_1200_DDR_800_RCLK_800: + *freq = CPU_FREQ_1200; + break; + case CPU_1400_DDR_800_RCLK_800: + *freq = CPU_FREQ_1400; + break; + case CPU_600_DDR_800_RCLK_800: + *freq = CPU_FREQ_600; + break; + case CPU_800_DDR_800_RCLK_800: + *freq = CPU_FREQ_800; + break; + case CPU_1000_DDR_800_RCLK_800: + *freq = CPU_FREQ_1000; + default: + *freq = 0; + return -1; + } + + return 0; +} + +int init_aro(void) +{ + unsigned int cpu_counter_init_val, max_freq_guardeband, ref_counter_init_val; + unsigned int data, mask; + uint32_t target_freq; + enum hws_freq freq; + + sar_freq_get(0, &freq); + target_freq = cpu_freq_val[freq]; + + /* Set initial ARO freq targets (600 Mhz) + * After this stage, PLL still drives the CPU clock + */ + enable_aro_module(); + + /* -Stop forcing USER mode, if callibration mode will be enabled + * ARO would work in calibrationb mode + */ + data = 0x0 << USER_RO_SEL_TRGT_OFF; + mask = USER_RO_SEL_TRGT_MASK; + reg_set_val(CPU_ARO_CTRL1(0), data, mask); + reg_set_val(CPU_ARO_CTRL1(1), data, mask); + + udelay(1); + + data = 0x0 << USER_UPDATE_RO_TRGT_OFF; + mask = USER_UPDATE_RO_TRGT_MASK; + reg_set_val(CPU_ARO_CTRL1(0), data, mask); + reg_set_val(CPU_ARO_CTRL1(1), data, mask); + + /* 2000 and 1800 touch the device speed limit, + * therefore it requires a special flow when building + * the clock frequency from a certain stage, else the device may fail + */ + if (target_freq == (2000) || target_freq == (1800)) { + max_freq_guardeband = 200; + ref_counter_init_val = 5; + cpu_counter_init_val = ((target_freq - max_freq_guardeband) / (25 * ref_counter_init_val)); + start_aro_mode(ref_counter_init_val, cpu_counter_init_val); + + /* CPU is now running in ARO mode*/ + udelay(100); + + /* update the Ref count to higher value to gain accuracy. */ + ref_counter_init_val = 10000; + cpu_counter_init_val = (target_freq / 25 * (ref_counter_init_val)); + start_aro_mode(ref_counter_init_val, cpu_counter_init_val); + + } else { + max_freq_guardeband = 0; + ref_counter_init_val = 5; + cpu_counter_init_val = (((target_freq - max_freq_guardeband) / 25) * ref_counter_init_val); + start_aro_mode(ref_counter_init_val, cpu_counter_init_val); + + /* CPU is now running in ARO mode*/ + udelay(100); + } + + return 0; +} + + diff --git a/include/drivers/marvell/aro.h b/include/drivers/marvell/aro.h new file mode 100644 index 00000000..f02a69a4 --- /dev/null +++ b/include/drivers/marvell/aro.h @@ -0,0 +1,77 @@ +/* +* *************************************************************************** +* Copyright (C) 2017 Marvell International Ltd. +* *************************************************************************** +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* Neither the name of Marvell nor the names of its contributors may be used +* to endorse or promote products derived from this software without specific +* prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +*************************************************************************** +*/ + +#ifndef _ARO_H_ +#define _ARO_H_ + +#include <stdint.h> + +enum hws_freq { + CPU_FREQ_2000, + CPU_FREQ_1800, + CPU_FREQ_1600, + CPU_FREQ_1400, + CPU_FREQ_1300, + CPU_FREQ_1200, + CPU_FREQ_1000, + CPU_FREQ_600, + CPU_FREQ_800, + DDR_FREQ_LAST, + DDR_FREQ_SAR +}; + +enum cpu_clock_freq_mode { + CPU_2000_DDR_1200_RCLK_1200 = 0x0, + CPU_2000_DDR_1050_RCLK_1050 = 0x1, + CPU_1600_DDR_800_RCLK_800 = 0x4, + CPU_1800_DDR_1200_RCLK_1200 = 0x6, + CPU_1800_DDR_1050_RCLK_1050 = 0x7, + CPU_1600_DDR_900_RCLK_900 = 0x0B, + CPU_1600_DDR_1050_RCLK_1050 = 0x0D, + CPU_1600_DDR_900_RCLK_900_2 = 0x0E, + CPU_1000_DDR_650_RCLK_650 = 0x13, + CPU_1300_DDR_800_RCLK_800 = 0x14, + CPU_1300_DDR_650_RCLK_650 = 0x17, + CPU_1200_DDR_800_RCLK_800 = 0x19, + CPU_1400_DDR_800_RCLK_800 = 0x1a, + CPU_600_DDR_800_RCLK_800 = 0x1B, + CPU_800_DDR_800_RCLK_800 = 0x1C, + CPU_1000_DDR_800_RCLK_800 = 0x1D, + CPU_DDR_RCLK_INVALID +}; + +int init_aro(void); + +#endif /* _ARO_H_ */ + diff --git a/plat/marvell/a8k/common/a8k_common.mk b/plat/marvell/a8k/common/a8k_common.mk index b9df51c9..c5224b2c 100644 --- a/plat/marvell/a8k/common/a8k_common.mk +++ b/plat/marvell/a8k/common/a8k_common.mk @@ -62,12 +62,14 @@ PLAT_BL_COMMON_SOURCES := $(PLAT_COMMON_BASE)/aarch64/a8k_common.c \ BLE_PORTING_SOURCES := $(PLAT_FAMILY_BASE)/$(PLAT)/board/dram_port.c \ $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c -BLE_SOURCES := plat/marvell/common/sys_info.c \ - plat/marvell/a8k/common/plat_ble_setup.c \ - $(MARVELL_DRV_BASE)/mochi/cp110_setup.c \ - $(MARVELL_DRV_BASE)/i2c/a8k_i2c.c \ - $(PLAT_COMMON_BASE)/plat_pm.c \ +BLE_SOURCES := plat/marvell/common/sys_info.c \ + plat/marvell/a8k/common/plat_ble_setup.c \ + $(MARVELL_DRV_BASE)/mochi/cp110_setup.c \ + $(MARVELL_DRV_BASE)/i2c/a8k_i2c.c \ + $(PLAT_COMMON_BASE)/plat_pm.c \ + $(MARVELL_DRV_BASE)/aro.c \ $(BLE_PORTING_SOURCES) + ifeq (${PCI_EP_SUPPORT}, 1) BLE_SOURCES += plat/marvell/common/pci_ep_setup.c \ $(MARVELL_DRV_BASE)/dw-pcie-ep.c \ diff --git a/plat/marvell/a8k/common/plat_ble_setup.c b/plat/marvell/a8k/common/plat_ble_setup.c index 8815051a..7203a11d 100644 --- a/plat/marvell/a8k/common/plat_ble_setup.c +++ b/plat/marvell/a8k/common/plat_ble_setup.c @@ -39,6 +39,7 @@ #include <sys_info.h> #include <dram_if.h> #include <ccu.h> +#include <aro.h> #include <rfu.h> #include <apn806_setup.h> #include <cp110_setup.h> @@ -143,26 +144,6 @@ #define EFUSE_SVC_REVISION_ID_0 0x8 #define EFUSE_SVC_BIN_PREMIUM 0x1 -enum cpu_clock_freq_mode { - CPU_2000_DDR_1200_RCLK_1200 = 0x0, - CPU_2000_DDR_1050_RCLK_1050 = 0x1, - CPU_1600_DDR_800_RCLK_800 = 0x4, - CPU_1800_DDR_1200_RCLK_1200 = 0x6, - CPU_1800_DDR_1050_RCLK_1050 = 0x7, - CPU_1600_DDR_900_RCLK_900 = 0x0B, - CPU_1600_DDR_1050_RCLK_1050 = 0x0D, - CPU_1600_DDR_900_RCLK_900_2 = 0x0E, - CPU_1000_DDR_650_RCLK_650 = 0x13, - CPU_1300_DDR_800_RCLK_800 = 0x14, - CPU_1300_DDR_650_RCLK_650 = 0x17, - CPU_1200_DDR_800_RCLK_800 = 0x19, - CPU_1400_DDR_800_RCLK_800 = 0x1a, - CPU_600_DDR_800_RCLK_800 = 0x1B, - CPU_800_DDR_800_RCLK_800 = 0x1C, - CPU_1000_DDR_800_RCLK_800 = 0x1D, - CPU_DDR_RCLK_INVALID -}; - /* Notify bootloader on DRAM setup */ void pass_dram_sys_info(struct dram_config *cfg) { @@ -504,6 +485,8 @@ int ble_plat_setup(int *skip) /* Setup AVS */ ble_plat_svc_config(); + init_aro(); + /* Get dram data from platform */ cfg = (struct dram_config *)plat_get_dram_data(); |