summaryrefslogtreecommitdiff
path: root/chip/mt_scp/mt8183/clock.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /chip/mt_scp/mt8183/clock.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14526.73.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'chip/mt_scp/mt8183/clock.c')
-rw-r--r--chip/mt_scp/mt8183/clock.c374
1 files changed, 0 insertions, 374 deletions
diff --git a/chip/mt_scp/mt8183/clock.c b/chip/mt_scp/mt8183/clock.c
deleted file mode 100644
index 3029a00a01..0000000000
--- a/chip/mt_scp/mt8183/clock.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/* Copyright 2018 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* Clocks, PLL and power settings */
-
-#include "clock.h"
-#include "clock_chip.h"
-#include "common.h"
-#include "console.h"
-#include "registers.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-
-#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ## args)
-
-#define ULPOSC_DIV_MAX (1 << OSC_DIV_BITS)
-#define ULPOSC_CALI_MAX (1 << OSC_CALI_BITS)
-
-void clock_init(void)
-{
- /* Set VREQ to HW mode */
- SCP_CPU_VREQ = CPU_VREQ_HW_MODE;
- SCP_SECURE_CTRL &= ~ENABLE_SPM_MASK_VREQ;
-
- /* Set DDREN auto mode */
- SCP_SYS_CTRL |= AUTO_DDREN;
-
- /* Initialize 26MHz system clock counter reset value to 1. */
- SCP_CLK_SYS_VAL =
- (SCP_CLK_SYS_VAL & ~CLK_SYS_VAL_MASK) | CLK_SYS_VAL(1);
- /* Initialize high frequency ULPOSC counter reset value to 1. */
- SCP_CLK_HIGH_VAL =
- (SCP_CLK_HIGH_VAL & ~CLK_HIGH_VAL_MASK) | CLK_HIGH_VAL(1);
- /* Initialize sleep mode control VREQ counter. */
- SCP_CLK_SLEEP_CTRL =
- (SCP_CLK_SLEEP_CTRL & ~VREQ_COUNTER_MASK) | VREQ_COUNTER_VAL(1);
-
- /* Set normal wake clock */
- SCP_WAKE_CKSW &= ~WAKE_CKSW_SEL_NORMAL_MASK;
-
- /* Enable fast wakeup support */
- SCP_CLK_SLEEP = 0;
- SCP_CLK_ON_CTRL = (SCP_CLK_ON_CTRL & ~HIGH_FINAL_VAL_MASK) |
- HIGH_FINAL_VAL_DEFAULT;
- SCP_FAST_WAKE_CNT_END =
- (SCP_FAST_WAKE_CNT_END & ~FAST_WAKE_CNT_END_MASK) |
- FAST_WAKE_CNT_END_DEFAULT;
-
- /* Set slow wake clock */
- SCP_WAKE_CKSW = (SCP_WAKE_CKSW & ~WAKE_CKSW_SEL_SLOW_MASK) |
- WAKE_CKSW_SEL_SLOW_DEFAULT;
-
- /* Select CLK_HIGH as wakeup clock */
- SCP_CLK_SLOW_SEL = (SCP_CLK_SLOW_SEL &
- ~(CKSW_SEL_SLOW_MASK | CKSW_SEL_SLOW_DIV_MASK)) |
- CKSW_SEL_SLOW_ULPOSC2_CLK;
-
- /*
- * Set legacy wakeup
- * - disable SPM sleep control
- * - disable SCP sleep mode
- */
- SCP_CLK_SLEEP_CTRL &= ~(EN_SLEEP_CTRL | SPM_SLEEP_MODE);
-
- task_enable_irq(SCP_IRQ_CLOCK);
- task_enable_irq(SCP_IRQ_CLOCK2);
-}
-
-static void scp_ulposc_config(int osc, uint32_t osc_div, uint32_t osc_cali)
-{
- uint32_t val;
-
- /* Clear all bits */
- val = 0;
- /* Enable CP */
- val |= OSC_CP_EN;
- /* Set div */
- val |= osc_div << 17;
- /* F-band = 0, I-band = 4 */
- val |= 4 << 6;
- /* Set calibration */
- val |= osc_cali;
- /* Set control register 1 */
- AP_ULPOSC_CON02(osc) = val;
- /* Set control register 2, enable div2 */
- AP_ULPOSC_CON13(osc) |= OSC_DIV2_EN;
-}
-
-static inline void busy_udelay(int usec)
-{
- /*
- * Delaying by busy-looping, for place that can't use udelay because of
- * the clock not configured yet. The value 28 is chosen approximately
- * from experiment.
- */
- volatile int i = usec * 28;
-
- while (i--)
- ;
-}
-
-static unsigned int scp_measure_ulposc_freq(int osc)
-{
- unsigned int result = 0;
- int cnt;
-
- /* Before select meter clock input, bit[1:0] = b00 */
- AP_CLK_DBG_CFG = (AP_CLK_DBG_CFG & ~DBG_MODE_MASK) |
- DBG_MODE_SET_CLOCK;
-
- /* Select source, bit[21:16] = clk_src */
- AP_CLK_DBG_CFG = (AP_CLK_DBG_CFG & ~DBG_BIST_SOURCE_MASK) |
- (osc == 0 ? DBG_BIST_SOURCE_ULPOSC1 :
- DBG_BIST_SOURCE_ULPOSC2);
-
- /* Set meter divisor to 1, bit[31:24] = b00000000 */
- AP_CLK_MISC_CFG_0 = (AP_CLK_MISC_CFG_0 & ~MISC_METER_DIVISOR_MASK) |
- MISC_METER_DIV_1;
-
- /* Enable frequency meter, without start */
- AP_SCP_CFG_0 |= CFG_FREQ_METER_ENABLE;
-
- /* Trigger frequency meter start */
- AP_SCP_CFG_0 |= CFG_FREQ_METER_RUN;
-
- /*
- * Frequency meter counts cycles in 1 / (26 * 1024) second period.
- * freq_in_hz = freq_counter * 26 * 1024
- *
- * The hardware takes 38us to count cycles. Delay up to 100us,
- * as busy_udelay may not be accurate when sysclk is not 26Mhz
- * (e.g. when recalibrating/measuring after boot).
- */
- for (cnt = 100; cnt; cnt--) {
- busy_udelay(1);
- if (!(AP_SCP_CFG_0 & CFG_FREQ_METER_RUN)) {
- result = CFG_FREQ_COUNTER(AP_SCP_CFG_1);
- break;
- }
- }
-
- /* Disable freq meter */
- AP_SCP_CFG_0 &= ~CFG_FREQ_METER_ENABLE;
- return result;
-}
-
-static inline int signum(int v)
-{
- return (v > 0) - (v < 0);
-}
-
-static inline int abs(int v)
-{
- return (v >= 0) ? v : -v;
-}
-
-static int scp_ulposc_config_measure(int osc, int div, int cali)
-{
- int freq;
-
- scp_ulposc_config(osc, div, cali);
- freq = scp_measure_ulposc_freq(osc);
- CPRINTF("ULPOSC%d: %d %d %d (%dkHz)\n",
- osc + 1, div, cali, freq,
- freq * 26 * 1000 / 1024);
-
- return freq;
-}
-
-/**
- * Calibrate ULPOSC to target frequency.
- *
- * @param osc 0:ULPOSC1, 1:ULPOSC2
- * @param target_mhz Target frequency to set
- * @return Frequency counter output
- *
- */
-static int scp_calibrate_ulposc(int osc, int target_mhz)
-{
- int target_freq = DIV_ROUND_NEAREST(target_mhz * 1024, 26);
- struct ulposc {
- int div; /* frequency divisor/multiplier */
- int cali; /* variable resistor calibrator */
- int freq; /* frequency counter measure result */
- } curr, prev = {0};
- enum { STAGE_DIV, STAGE_CALI } stage = STAGE_DIV;
- int param, param_max;
-
- curr.div = ULPOSC_DIV_MAX / 2;
- curr.cali = ULPOSC_CALI_MAX / 2;
-
- param = curr.div;
- param_max = ULPOSC_DIV_MAX;
-
- /*
- * In the loop below, linear search closest div value to get desired
- * frequency counter value. Then adjust cali to get a better result.
- * Note that this doesn't give optimal output frequency, but it's
- * usually close enough.
- * TODO(b:120176040): See if we can efficiently calibrate the clock with
- * more precision by exploring more of the cali/div space.
- *
- * The frequency function follows. Note that f is positively correlated
- * with both div and cali:
- * f(div, cali) = k1 * (div + k2) / R(cali) * C
- * Where:
- * R(cali) = k3 / (1 + k4 * (cali - k4))
- */
- while (1) {
- curr.freq = scp_ulposc_config_measure(osc, curr.div, curr.cali);
-
- if (!curr.freq)
- return 0;
-
- /*
- * If previous and current are on either side of the desired
- * frequency, pick the closest one.
- */
- if (prev.freq && signum(target_freq - curr.freq) !=
- signum(target_freq - prev.freq)) {
- if (abs(target_freq - prev.freq) <
- abs(target_freq - curr.freq))
- curr = prev;
-
- if (stage == STAGE_CALI)
- break;
-
- /* Switch to optimizing cali */
- stage = STAGE_CALI;
- param = curr.cali;
- param_max = ULPOSC_CALI_MAX;
- }
-
- prev = curr;
- param += signum(target_freq - curr.freq);
-
- if (param < 0 || param >= param_max)
- return 0;
-
- if (stage == STAGE_DIV)
- curr.div = param;
- else
- curr.cali = param;
- }
-
- /*
- * It's possible we end up using prev, so reset the configuration and
- * measure again.
- */
- return scp_ulposc_config_measure(osc, curr.div, curr.cali);
-}
-
-static void scp_clock_high_enable(int osc)
-{
- /* Enable high speed clock */
- SCP_CLK_EN |= EN_CLK_HIGH;
-
- switch (osc) {
- case 0:
- /* After 25ms, enable ULPOSC */
- busy_udelay(25 * MSEC);
- SCP_CLK_EN |= CG_CLK_HIGH;
- break;
- case 1:
- /* Turn off ULPOSC2 high-core-disable switch */
- SCP_CLK_ON_CTRL &= ~HIGH_CORE_DIS_SUB;
- /* After 25ms, turn on ULPOSC2 high core clock gate */
- busy_udelay(25 * MSEC);
- SCP_CLK_HIGH_CORE |= CLK_HIGH_CORE_CG;
- break;
- default:
- break;
- }
-}
-
-void scp_use_clock(enum scp_clock_source src)
-{
- /*
- * DIV2 divider takes precedence over clock selection to prevent
- * over-clocking.
- */
- if (src == SCP_CLK_ULPOSC1)
- SCP_CLK_DIV_SEL = CLK_DIV2;
-
- SCP_CLK_SEL = src;
-
- if (src != SCP_CLK_ULPOSC1)
- SCP_CLK_DIV_SEL = CLK_DIV1;
-}
-
-void scp_enable_clock(void)
-{
- /* Select default CPU clock */
- scp_use_clock(SCP_CLK_26M);
-
- /* VREQ */
- SCP_CPU_VREQ = 0x10001;
- SCP_SECURE_CTRL &= ~ENABLE_SPM_MASK_VREQ;
-
- /* DDREN auto mode */
- SCP_SYS_CTRL |= AUTO_DDREN;
-
- /* Set settle time */
- SCP_CLK_SYS_VAL = 1; /* System clock */
- SCP_CLK_HIGH_VAL = 1; /* ULPOSC */
- SCP_CLK_SLEEP_CTRL = (SCP_CLK_SLEEP_CTRL & ~VREQ_COUNTER_MASK) | 2;
-
- /* Disable slow wake */
- SCP_CLK_SLEEP = SLOW_WAKE_DISABLE;
- /* Disable SPM sleep control, disable sleep mode */
- SCP_CLK_SLEEP_CTRL &= ~(SPM_SLEEP_MODE | EN_SLEEP_CTRL);
-
- /* Turn off ULPOSC2 */
- SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB;
- scp_ulposc_config(0, 12, 32);
- scp_clock_high_enable(0); /* Turn on ULPOSC1 */
- scp_ulposc_config(1, 16, 32);
- scp_clock_high_enable(1); /* Turn on ULPOSC2 */
-
- /* Calibrate ULPOSC */
- scp_calibrate_ulposc(0, ULPOSC1_CLOCK_MHZ);
- scp_calibrate_ulposc(1, ULPOSC2_CLOCK_MHZ);
-
- /* Select ULPOSC2 high speed CPU clock */
- scp_use_clock(SCP_CLK_ULPOSC2);
-
- /* Enable default clock gate */
- SCP_CLK_GATE |= CG_DMA_CH3 | CG_DMA_CH2 | CG_DMA_CH1 | CG_DMA_CH0 |
- CG_I2C_M | CG_MAD_M | CG_AP2P_M;
-
- /* Select pwrap_ulposc */
- AP_CLK_CFG_5 = (AP_CLK_CFG_5 & ~PWRAP_ULPOSC_MASK) | OSC_D16;
-
- /* Enable pwrap_ulposc clock gate */
- AP_CLK_CFG_5_CLR = PWRAP_ULPOSC_CG;
-}
-
-DECLARE_IRQ(SCP_IRQ_CLOCK, clock_control_irq, 3);
-void clock_control_irq(void)
-{
- /* Read ack CLK_IRQ */
- (SCP_CLK_IRQ_ACK);
- task_clear_pending_irq(SCP_IRQ_CLOCK);
-}
-
-DECLARE_IRQ(SCP_IRQ_CLOCK2, clock_fast_wakeup_irq, 3);
-void clock_fast_wakeup_irq(void)
-{
- /* Ack fast wakeup */
- SCP_SLEEP_IRQ2 = 1;
- task_clear_pending_irq(SCP_IRQ_CLOCK2);
-}
-
-/* Console command */
-int command_ulposc(int argc, char *argv[])
-{
- if (argc > 1 && !strncmp(argv[1], "cal", 3)) {
- scp_calibrate_ulposc(0, ULPOSC1_CLOCK_MHZ);
- scp_calibrate_ulposc(1, ULPOSC2_CLOCK_MHZ);
- }
-
- /* SCP clock meter counts every (26MHz / 1024) tick */
- ccprintf("ULPOSC1 frequency: %u kHz\n",
- scp_measure_ulposc_freq(0) * 26 * 1000 / 1024);
- ccprintf("ULPOSC2 frequency: %u kHz\n",
- scp_measure_ulposc_freq(1) * 26 * 1000 / 1024);
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[calibrate]",
- "Calibrate ULPOSC frequency");