diff options
author | Yilun Lin <yllin@chromium.org> | 2019-04-25 07:16:21 +0000 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-26 09:09:10 -0700 |
commit | bd4273f88da59e8beecaee8e891f1a558e513fbf (patch) | |
tree | 30013dfc7418b9be967134db46785eb6a0d6ad9a /chip | |
parent | 5c87411b3a573eb8d9d6f3b63e099e7ab44cbd5b (diff) | |
download | chrome-ec-bd4273f88da59e8beecaee8e891f1a558e513fbf.tar.gz |
Revert "kukui: scp: calibrate ULPOSC1&2"
This reverts commit e08a71fd05bfc9e32dd64b7e15840e7232d72788.
Reason for revert: SCP will hang with this CL.
Original change's description:
> kukui: scp: calibrate ULPOSC1&2
>
> ULPOSC generates clock for SCP core and peripherals. The calibration
> process adjust 2 values, div and cali. Both values are positive
> correlated to OSC frequency. The frequency function is:
> f(div, cali) = k1 * (div + k2) / R(cali) * C
> Where:
> R(cali) = k3 / (1 + k4 * (cali - k4))
>
> The actual frequency is not linear to cali parameter. This change
> selects the div that generates closest frequency when cali == 32. And
> then adjust cali to get better output.
>
> BRANCH=none
> BUG=b:120176040,b:120169529
> TEST=manual
> check SCP console command:
> > ulposc
> ULPOSC1 frequency: 248 MHz
> ULPOSC2 frequency: 330 MHz
>
> Change-Id: Ifac9d481e654064ee60d84819added5e164ed7c2
> Signed-off-by: Rong Chang <rongchang@chromium.org>
> Reviewed-on: https://chromium-review.googlesource.com/1520571
> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Bug: b:120176040, b:120169529, b:131273034
Change-Id: Ifaeb9a7835a35556587fac4c039b9fde6d66504d
Reviewed-on: https://chromium-review.googlesource.com/1583481
Commit-Ready: Yilun Lin <yllin@chromium.org>
Tested-by: Yilun Lin <yllin@chromium.org>
Reviewed-by: Yilun Lin <yllin@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/mt_scp/clock.c | 247 | ||||
-rw-r--r-- | chip/mt_scp/registers.h | 2 |
2 files changed, 66 insertions, 183 deletions
diff --git a/chip/mt_scp/clock.c b/chip/mt_scp/clock.c index 218ff1e9db..c58c4671a1 100644 --- a/chip/mt_scp/clock.c +++ b/chip/mt_scp/clock.c @@ -6,7 +6,6 @@ /* Clocks, PLL and power settings */ #include "clock.h" -#include "clock_chip.h" #include "common.h" #include "console.h" #include "registers.h" @@ -14,19 +13,6 @@ #include "timer.h" #include "util.h" -#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ## args) - -/* Default ULPOSC clock speed in Hz */ -#ifndef ULPOSC1_CLOCK_HZ -#define ULPOSC1_CLOCK_HZ 250000000 -#endif -#ifndef ULPOSC2_CLOCK_HZ -#define ULPOSC2_CLOCK_HZ 330000000 -#endif - -#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 */ @@ -77,20 +63,33 @@ void clock_init(void) task_enable_irq(SCP_IRQ_CLOCK2); } -static void scp_ulposc_config(int osc, uint32_t osc_div, uint32_t osc_cali) +/* TODO(b/120176040): add ULPOSC calibration */ +static const struct { + uint8_t div; + uint8_t cali; +} ulposc_config[] = { + /* Default config */ + { .div = 12, .cali = 32}, + { .div = 16, .cali = 32}, +}; + +static void scp_ulposc_config(int osc) { uint32_t val; + if (osc != 0 && osc != 1) + return; + /* Clear all bits */ val = 0; /* Enable CP */ val |= OSC_CP_EN; /* Set div */ - val |= osc_div << 17; + val |= ulposc_config[osc].div << 17; /* F-band = 0, I-band = 4 */ val |= 4 << 6; /* Set calibration */ - val |= osc_cali; + val |= ulposc_config[osc].cali; /* Set control register 1 */ AP_ULPOSC_CON02(osc) = val; /* Set control register 2, enable div2 */ @@ -110,153 +109,7 @@ static inline void busy_udelay(int usec) ; } -static unsigned int scp_measure_ulposc_freq(int osc) -{ - unsigned int result = 0; - - /* 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 * 1000) second period. - * freq_in_hz = freq_counter * 26 * 1000 - * - * The hardware takes 38us to count cycles. Delay 50us then check - * METER_RUN flag. - */ - udelay(50); - if (!(AP_SCP_CFG_0 & CFG_FREQ_METER_RUN)) - result = CFG_FREQ_COUNTER(AP_SCP_CFG_1); - - /* 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 (%dMHz)\n", - osc + 1, div, cali, freq, - freq * 26 / 1000); - - return freq; -} - -/** - * Calibrate ULPOSC to target frequency. - * - * @param osc 0:ULPOSC1, 1:ULPOSC2 - * @param target_hz Target frequency to set - * @return Frequency counter output - * - */ -static int scp_calibrate_ulposc(int osc, int target_hz) -{ - int target_freq = target_hz / (26 * 1000); - struct ulposc { - int div; /* frequency divisor/multiplier */ - int cali; /* variable resistor calibrator */ - int freq; /* frequency counter measure result */ - int inc; /* next div or cali param diff */ - } curr, prev = {0}; - - curr.div = ULPOSC_DIV_MAX / 2; - curr.cali = ULPOSC_CALI_MAX / 2; - - /* - * 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. The search - * starts on cali==CALI_MAX/2 line to find best div value, then linear - * search cali value with a fixed div. The output result is usually - * good enough for core clock. - */ - while (1) { - curr.freq = scp_ulposc_config_measure(osc, curr.div, curr.cali); - - if (!curr.freq) - return 0; - if (curr.freq == target_freq) - return curr.freq; - - /* Linear search is enough for both div and cali params */ - curr.inc = signum(target_freq - curr.freq); - - /* Search div value */ - if (prev.div != curr.div) { - if (!prev.freq) { - prev = curr; - if (target_freq > curr.freq) { - curr.div++; - curr.inc = prev.inc = 1; - } else { - curr.div--; - curr.inc = prev.inc = -1; - } - continue; - } - if (curr.inc == prev.inc) { - prev = curr; - curr.div += curr.inc; - if (curr.div < 0 || curr.div >= ULPOSC_DIV_MAX) - return 0; - } else { - prev = curr; - curr.cali += curr.inc; - } - continue; - } - - /* Search cali value */ - if (curr.inc == prev.inc) { - prev = curr; - curr.cali += curr.inc; - if (curr.cali < 0 || curr.cali >= ULPOSC_CALI_MAX) - return 0; - continue; - } - - if (abs(target_freq - curr.freq) > - abs(target_freq - prev.freq)) { - scp_ulposc_config_measure(osc, prev.div, prev.cali); - return prev.freq; - } - } - - return 0; -} - -static void scp_clock_high_enable(int osc) +void scp_clock_high_enable(int osc) { /* Enable high speed clock */ SCP_CLK_EN |= EN_CLK_HIGH; @@ -303,15 +156,11 @@ void scp_enable_clock(void) /* Turn off ULPOSC2 */ SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; - scp_ulposc_config(0, ULPOSC_DIV_MAX / 2, ULPOSC_CALI_MAX / 2); + scp_ulposc_config(0); scp_clock_high_enable(0); /* Turn on ULPOSC1 */ - scp_ulposc_config(1, ULPOSC_DIV_MAX / 2, ULPOSC_CALI_MAX / 2); + scp_ulposc_config(1); scp_clock_high_enable(1); /* Turn on ULPOSC2 */ - /* Calibrate ULPOSC */ - scp_calibrate_ulposc(0, ULPOSC1_CLOCK_HZ); - scp_calibrate_ulposc(1, ULPOSC2_CLOCK_HZ); - /* Select ULPOSC2 high speed CPU clock */ SCP_CLK_SEL = CLK_SEL_ULPOSC_2; @@ -320,6 +169,49 @@ void scp_enable_clock(void) CG_I2C_M | CG_MAD_M; } +unsigned int clock_measure_ulposc_freq(int osc) +{ + timestamp_t deadline; + unsigned int result = 0; + + if (osc != 0 && osc != 1) + return result; + + /* 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; + + deadline.val = get_time().val + 400 * MSEC; + while (AP_SCP_CFG_0 & CFG_FREQ_METER_RUN) { + if (timestamp_expired(deadline, NULL)) + goto exit; + msleep(1); + } + + /* Get result */ + result = CFG_FREQ_COUNTER(AP_SCP_CFG_1); + +exit: + /* Disable freq meter */ + AP_SCP_CFG_0 &= ~CFG_FREQ_METER_ENABLE; + return result; +} + void clock_control_irq(void) { /* Read ack CLK_IRQ */ @@ -339,19 +231,12 @@ DECLARE_IRQ(SCP_IRQ_CLOCK2, clock_fast_wakeup_irq, 3); /* Console command */ int command_ulposc(int argc, char *argv[]) { - if (argc > 1 && !strncmp(argv[1], "cal", 3)) { - scp_calibrate_ulposc(0, ULPOSC1_CLOCK_HZ); - scp_calibrate_ulposc(1, ULPOSC2_CLOCK_HZ); - } - - /* SCP clock meter counts every (26MHz / 1000) tick */ + /* SCP clock meter counts every (26MHz / 1024) tick */ ccprintf("ULPOSC1 frequency: %u MHz\n", - scp_measure_ulposc_freq(0) * 26 / 1000); + clock_measure_ulposc_freq(0) * 26 / 1024); ccprintf("ULPOSC2 frequency: %u MHz\n", - scp_measure_ulposc_freq(1) * 26 / 1000); + clock_measure_ulposc_freq(1) * 26 / 1024); return EC_SUCCESS; } -DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[calibrate]", - "Calibrate ULPOSC frequency"); - +DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, NULL, NULL); diff --git a/chip/mt_scp/registers.h b/chip/mt_scp/registers.h index 07db4df07c..e6bcbecac3 100644 --- a/chip/mt_scp/registers.h +++ b/chip/mt_scp/registers.h @@ -527,11 +527,9 @@ * bit24-31: reserved */ #define OSC_CALI_MSK (0x3f << 0) -#define OSC_CALI_BITS 6 #define OSC_IBAND_MASK (0x7f << 6) #define OSC_FBAND_MASK (0x0f << 13) #define OSC_DIV_MASK (0x1f << 17) -#define OSC_DIV_BITS 5 #define OSC_CP_EN BIT(23) #define OSC_RESERVED_MASK (0xff << 24) /* AP_ULPOSC_CON[1,3] */ |