diff options
author | Christine Gharzuzi <chrisg@marvell.com> | 2017-10-22 16:09:08 +0300 |
---|---|---|
committer | Kostya Porotchkin <kostap@marvell.com> | 2018-02-06 17:34:22 +0200 |
commit | e846d2c32f7f8e1946ecaeb031bebc78f40b54c5 (patch) | |
tree | 0255c37c8583e1f5409f65b29144f4a6f802cf53 /drivers | |
parent | a37eb21156af9c905d00270f75ca1d4145b29675 (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.c | 98 |
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); + } + } +} |