summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorChristine Gharzuzi <chrisg@marvell.com>2017-10-22 16:09:08 +0300
committerKostya Porotchkin <kostap@marvell.com>2018-02-06 17:34:22 +0200
commite846d2c32f7f8e1946ecaeb031bebc78f40b54c5 (patch)
tree0255c37c8583e1f5409f65b29144f4a6f802cf53 /drivers
parenta37eb21156af9c905d00270f75ca1d4145b29675 (diff)
mvebu: aro: introduce adaptive ring oscillator
ARO is a clock generator, which is used in AP810 as a source clock for the CPU clusters. In AP810 the ARO is the major clock and in the default state the ARO is also in calibration mode. to configure the CPU frequency a flow of 2 steps is needed. Change-Id: Ie1d5550c7cd08ed8df6d1d404582ced54ba604d7 Signed-off-by: Christine Gharzuzi <chrisg@marvell.com> Reviewed-on: http://vgitil04.il.marvell.com:8080/47084 Tested-by: iSoC Platform CI <ykjenk@marvell.com> Reviewed-by: Hanna Hawa <hannah@marvell.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/marvell/ap810_aro.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/drivers/marvell/ap810_aro.c b/drivers/marvell/ap810_aro.c
new file mode 100644
index 00000000..dc84c065
--- /dev/null
+++ b/drivers/marvell/ap810_aro.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <ap810_setup.h>
+#include <ap810_aro.h>
+#include <delay_timer.h>
+#include <plat_def.h>
+#include <mmio.h>
+
+#define ARO_REG_BASE_ADDR(ap) (MVEBU_DFX_SR_BASE(ap) + (0xD00))
+#define ARO_CLUSTER_REG0_ADDR(cluster, ap) (ARO_REG_BASE_ADDR(ap) + 0x48 + ((cluster) * 0x8))
+#define ARO_CLUSTER_REG1_ADDR(cluster, ap) (ARO_CLUSTER_REG0_ADDR(cluster, ap) + 0x4)
+
+#define CPU_FREQ_3000 0x000004B0
+#define CPU_FREQ_2700 0x00000438
+#define CPU_FREQ_2500 0x000003E8
+#define CPU_FREQ_2400 0x000003C0
+#define CPU_FREQ_2200 0x00000370
+#define CPU_FREQ_2000 0x00000320
+#define CPU_FREQ_1800 0x000002D0
+#define CPU_FREQ_1600 0x00000280
+#define CPU_FREQ_1200 0x000001E0
+#define CPU_FREQ_1000 0x00000190
+
+#define ARO_DELAY 0x9
+
+/* In case of target frequency 2700 and 3000,
+ * ARO flow is done in 2 steps, in step A a smaller
+ * frequency (than 2700 and 3000) is configured and afterwards in Step B
+ * the actual target frequency is configured (2700 OR 3000).
+ */
+#define ARO_FREQ_2700_STEP_A 0x270F
+#define ARO_FREQ_2700_STEP_B 0x107AC0
+#define ARO_FREQ_3000_STEP_A 0x270F
+#define ARO_FREQ_3000_STEP_B 0x124F80
+
+static int cpu_freq_table[10] = {
+ CPU_FREQ_1000,
+ CPU_FREQ_1200,
+ CPU_FREQ_1600,
+ CPU_FREQ_1800,
+ CPU_FREQ_2000,
+ CPU_FREQ_2200,
+ CPU_FREQ_2400,
+ CPU_FREQ_2500,
+ CPU_FREQ_2700,
+ CPU_FREQ_3000,
+};
+
+/* Init all CPU's for each AP required. */
+void ap810_aro_init(int target_freq, int ap_num)
+{
+ int cluster_num;
+ int freq, cluster0_shift;
+
+ freq = cpu_freq_table[target_freq];
+
+ /* 2700 and 3000 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
+ */
+ for (cluster_num = 0 ; cluster_num < PLAT_MARVELL_CLUSTER_PER_NB ; cluster_num++) {
+
+ /* Due to shift by 2 in cluster0 registers (A0 bug) .
+ * TODO: update with EERATA number.
+ */
+ cluster0_shift = 1;
+ if (cluster_num == 0 && !ap810_rev_id_get(ap_num))
+ cluster0_shift = 4;
+
+ if (freq == CPU_FREQ_2700) {
+ mmio_write_32(ARO_CLUSTER_REG1_ADDR(cluster_num, ap_num), ARO_DELAY);
+ mmio_write_32(ARO_CLUSTER_REG0_ADDR(cluster_num, ap_num), CPU_FREQ_2400 * cluster0_shift);
+ /* delay for 10 ms */
+ udelay(10000);
+ mmio_write_32(ARO_CLUSTER_REG1_ADDR(cluster_num, ap_num), ARO_FREQ_2700_STEP_A);
+ mmio_write_32(ARO_CLUSTER_REG0_ADDR(cluster_num, ap_num),
+ ARO_FREQ_2700_STEP_B * cluster0_shift);
+
+ } else if (freq == CPU_FREQ_3000) {
+ mmio_write_32(ARO_CLUSTER_REG1_ADDR(cluster_num, ap_num), ARO_DELAY);
+ mmio_write_32(ARO_CLUSTER_REG0_ADDR(cluster_num, ap_num), CPU_FREQ_2700 * cluster0_shift);
+ /* delay for 10 ms */
+ udelay(10000);
+ mmio_write_32(ARO_CLUSTER_REG1_ADDR(cluster_num, ap_num), ARO_FREQ_3000_STEP_A);
+ mmio_write_32(ARO_CLUSTER_REG0_ADDR(cluster_num, ap_num),
+ ARO_FREQ_3000_STEP_B * cluster0_shift);
+
+ } else {
+ mmio_write_32(ARO_CLUSTER_REG1_ADDR(cluster_num, ap_num), ARO_DELAY);
+ mmio_write_32(ARO_CLUSTER_REG0_ADDR(cluster_num, ap_num), freq * cluster0_shift);
+ }
+ }
+}