summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/marvell/aro.c345
-rw-r--r--include/drivers/marvell/aro.h77
-rw-r--r--plat/marvell/a8k/common/a8k_common.mk12
-rw-r--r--plat/marvell/a8k/common/plat_ble_setup.c23
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();