From d3cb154936240d90ec8c0e3f16483d06cce87ba5 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 4 Jun 2021 05:48:06 +0800 Subject: chip/mt_scp: support mt8195 clock Supports mt8195 clock and move chip-specific clock registers from common to chip-specific. BRANCH=none BUG=b:189300514 TEST=make BOARD=asurada_scp && make BOARD=cherry_scp Change-Id: I8ef058f6314652050dead46e7f48d3420bbdd1d1 Signed-off-by: Roger Lu Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2939167 Tested-by: tinghan shen Tested-by: Tzung-Bi Shih Reviewed-by: Tzung-Bi Shih Commit-Queue: Tzung-Bi Shih --- chip/mt_scp/mt8192/build.mk | 1 + chip/mt_scp/mt8192/clock.c | 369 +++++++++++++++++++++++++++++ chip/mt_scp/mt8192/clock_regs.h | 85 +++++++ chip/mt_scp/mt8195/build.mk | 1 + chip/mt_scp/mt8195/clock.c | 432 ++++++++++++++++++++++++++++++++++ chip/mt_scp/mt8195/clock_regs.h | 92 ++++++++ chip/mt_scp/rv32i_common/build.mk | 1 - chip/mt_scp/rv32i_common/clock.c | 363 ---------------------------- chip/mt_scp/rv32i_common/clock_chip.h | 23 -- chip/mt_scp/rv32i_common/registers.h | 73 +----- 10 files changed, 982 insertions(+), 458 deletions(-) create mode 100644 chip/mt_scp/mt8192/clock.c create mode 100644 chip/mt_scp/mt8192/clock_regs.h create mode 100644 chip/mt_scp/mt8195/clock.c create mode 100644 chip/mt_scp/mt8195/clock_regs.h delete mode 100644 chip/mt_scp/rv32i_common/clock.c delete mode 100644 chip/mt_scp/rv32i_common/clock_chip.h diff --git a/chip/mt_scp/mt8192/build.mk b/chip/mt_scp/mt8192/build.mk index 02ffdaeefe..5ca0f1033c 100644 --- a/chip/mt_scp/mt8192/build.mk +++ b/chip/mt_scp/mt8192/build.mk @@ -5,3 +5,4 @@ # Required chip modules chip-y+=$(CHIP_VARIANT)/uart.o +chip-y+=$(CHIP_VARIANT)/clock.o diff --git a/chip/mt_scp/mt8192/clock.c b/chip/mt_scp/mt8192/clock.c new file mode 100644 index 0000000000..43f570fc62 --- /dev/null +++ b/chip/mt_scp/mt8192/clock.c @@ -0,0 +1,369 @@ +/* Copyright 2021 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 +#include + +#include "clock.h" +#include "common.h" +#include "console.h" +#include "csr.h" +#include "ec_commands.h" +#include "power.h" +#include "registers.h" +#include "timer.h" + +#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ##args) +#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ##args) + +enum scp_clock_source { + SCP_CLK_26M = CLK_SW_SEL_26M, + SCP_CLK_32K = CLK_SW_SEL_32K, + SCP_CLK_ULPOSC2 = CLK_SW_SEL_ULPOSC2, + SCP_CLK_ULPOSC1 = CLK_SW_SEL_ULPOSC1, +}; + +static struct opp_ulposc_cfg { + uint32_t osc; + uint32_t div; + uint32_t fband; + uint32_t mod; + uint32_t cali; + uint32_t target_mhz; +} opp[] = { + { + .osc = 1, .target_mhz = 196, .div = 20, .fband = 10, .mod = 3, + .cali = 64, + }, + { + .osc = 0, .target_mhz = 260, .div = 14, .fband = 2, .mod = 0, + .cali = 64, + }, + { + .osc = 1, .target_mhz = 280, .div = 20, .fband = 2, .mod = 0, + .cali = 64, + }, + { + .osc = 1, .target_mhz = 360, .div = 20, .fband = 10, .mod = 0, + .cali = 64, + }, +}; + +static inline void clock_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' in order to avoid compiler to optimize the function out + * (otherwise, the function will be eliminated). + */ + volatile int i = usec * 28; + + while (--i) + ; +} + +static void clock_ulposc_config_default(struct opp_ulposc_cfg *opp) +{ + unsigned int val = 0; + + /* set div */ + val |= opp->div << OSC_DIV_SHIFT; + /* set F-band; I-band = 82 */ + val |= (opp->fband << OSC_FBAND_SHIFT) | (82 << OSC_IBAND_SHIFT); + /* set calibration */ + val |= opp->cali; + /* set control register 0 */ + AP_ULPOSC_CON0(opp->osc) = val; + + /* set mod */ + val = opp->mod << OSC_MOD_SHIFT; + /* rsv2 = 0, rsv1 = 41, cali_32k = 0 */ + val |= 41 << OSC_RSV1_SHIFT; + /* set control register 1 */ + AP_ULPOSC_CON1(opp->osc) = val; + + /* bias = 64 */ + AP_ULPOSC_CON2(opp->osc) = 64; +} + +static void clock_ulposc_config_cali(struct opp_ulposc_cfg *opp, + uint32_t cali_val) +{ + uint32_t val; + + val = AP_ULPOSC_CON0(opp->osc); + val &= ~OSC_CALI_MASK; + val |= cali_val; + AP_ULPOSC_CON0(opp->osc) = val; + + clock_busy_udelay(50); +} + +static uint32_t clock_ulposc_measure_freq(uint32_t osc) +{ + uint32_t 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 clock_busy_udelay may not be accurate when sysclk is not 26Mhz + * (e.g. when recalibrating/measuring after boot). + */ + for (cnt = 100; cnt > 0; --cnt) { + clock_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; +} + +#define CAL_MIS_RATE 40 +static int clock_ulposc_is_calibrated(struct opp_ulposc_cfg *opp) +{ + uint32_t curr, target; + + curr = clock_ulposc_measure_freq(opp->osc); + target = opp->target_mhz * 1024 / 26; + + /* check if calibrated value is in the range of target value +- 4% */ + if (curr > (target * (1000 - CAL_MIS_RATE) / 1000) && + curr < (target * (1000 + CAL_MIS_RATE) / 1000)) + return 1; + else + return 0; +} + +static uint32_t clock_ulposc_process_cali(struct opp_ulposc_cfg *opp) +{ + uint32_t current_val = 0; + uint32_t target_val = opp->target_mhz * 1024 / 26; + uint32_t middle, min = 0, max = OSC_CALI_MASK; + uint32_t diff_by_min, diff_by_max, cal_result; + + do { + middle = (min + max) / 2; + if (middle == min) + break; + + clock_ulposc_config_cali(opp, middle); + current_val = clock_ulposc_measure_freq(opp->osc); + + if (current_val > target_val) + max = middle; + else + min = middle; + } while (min <= max); + + clock_ulposc_config_cali(opp, min); + current_val = clock_ulposc_measure_freq(opp->osc); + if (current_val > target_val) + diff_by_min = current_val - target_val; + else + diff_by_min = target_val - current_val; + + clock_ulposc_config_cali(opp, max); + current_val = clock_ulposc_measure_freq(opp->osc); + if (current_val > target_val) + diff_by_max = current_val - target_val; + else + diff_by_max = target_val - current_val; + + if (diff_by_min < diff_by_max) + cal_result = min; + else + cal_result = max; + + clock_ulposc_config_cali(opp, cal_result); + if (!clock_ulposc_is_calibrated(opp)) + assert(0); + + return cal_result; +} + +static void clock_high_enable(int osc) +{ + /* enable high speed clock */ + SCP_CLK_ENABLE |= CLK_HIGH_EN; + + switch (osc) { + case 0: + /* after 150us, enable ULPOSC */ + clock_busy_udelay(150); + SCP_CLK_ENABLE |= CLK_HIGH_CG; + break; + case 1: + /* turn off ULPOSC2 high-core-disable switch */ + SCP_CLK_ON_CTRL &= ~HIGH_CORE_DIS_SUB; + /* after 150us, turn on ULPOSC2 high core clock gate */ + clock_busy_udelay(150); + SCP_CLK_HIGH_CORE_CG |= HIGH_CORE_CG; + clock_busy_udelay(50); + break; + default: + break; + } +} + +static void clock_high_disable(int osc) +{ + switch (osc) { + case 0: + SCP_CLK_ENABLE &= ~CLK_HIGH_CG; + clock_busy_udelay(50); + SCP_CLK_ENABLE &= ~CLK_HIGH_EN; + clock_busy_udelay(50); + break; + case 1: + SCP_CLK_HIGH_CORE_CG &= ~HIGH_CORE_CG; + clock_busy_udelay(50); + SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; + clock_busy_udelay(50); + break; + default: + break; + } +} + +static void clock_calibrate_ulposc(struct opp_ulposc_cfg *opp) +{ + /* + * ULPOSC1(osc=0) is already + * - calibrated + * - enabled in coreboot + * - used by pmic wrapper + */ + if (opp->osc != 0) { + clock_high_disable(opp->osc); + clock_ulposc_config_default(opp); + clock_high_enable(opp->osc); + } + + /* Calibrate only if it is not accurate enough. */ + if (!clock_ulposc_is_calibrated(opp)) + opp->cali = clock_ulposc_process_cali(opp); + +#ifdef DEBUG + CPRINTF("osc:%u, target=%uMHz, cal:%u\n", + opp->osc, opp->target_mhz, opp->cali); +#endif +} + +static void clock_select_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_DIV_SEL2; + + SCP_CLK_SW_SEL = src; + + if (src != SCP_CLK_ULPOSC1) + SCP_CLK_DIV_SEL = CLK_DIV_SEL1; +} + +__override void +power_chipset_handle_host_sleep_event(enum host_sleep_event state, + struct host_sleep_event_context *ctx) +{ + if (state == HOST_SLEEP_EVENT_S3_SUSPEND) { + CPRINTS("AP suspend"); + clock_select_clock(SCP_CLK_ULPOSC1); + } else if (state == HOST_SLEEP_EVENT_S3_RESUME) { + CPRINTS("AP resume"); + clock_select_clock(SCP_CLK_ULPOSC2); + } +} + +void clock_init(void) +{ + int i; + + /* select default 26M system clock */ + clock_select_clock(SCP_CLK_26M); + + /* set VREQ to HW mode */ + SCP_CPU_VREQ_CTRL = VREQ_SEL | VREQ_DVFS_SEL; + SCP_CLK_CTRL_GENERAL_CTRL &= ~VREQ_PMIC_WRAP_SEL; + SCP_SEC_CTRL &= ~VREQ_SECURE_DIS; + + /* set DDREN to auto mode */ + SCP_SYS_CTRL |= AUTO_DDREN; + + /* set settle time */ + SCP_CLK_SYS_VAL = + (SCP_CLK_SYS_VAL & ~CLK_SYS_VAL_MASK) | CLK_SYS_VAL_VAL(1); + SCP_CLK_HIGH_VAL = + (SCP_CLK_HIGH_VAL & ~CLK_HIGH_VAL_MASK) | CLK_HIGH_VAL_VAL(1); + SCP_SLEEP_CTRL = + (SCP_SLEEP_CTRL & ~VREQ_COUNT_MASK) | VREQ_COUNT_VAL(1); + + /* turn off ULPOSC2 */ + SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; + + /* calibrate ULPOSC */ + for (i = 0; i < ARRAY_SIZE(opp); ++i) + clock_calibrate_ulposc(&opp[i]); + + /* select ULPOSC2 high speed CPU clock */ + clock_select_clock(SCP_CLK_ULPOSC2); + + /* select BCLK to use ULPOSC1 / 8 = 260MHz / 8 = 32.5MHz */ + SCP_BCLK_CK_SEL = BCLK_CK_SEL_ULPOSC_DIV8; + + /* enable default clock gate */ + SCP_SET_CLK_CG |= CG_DMA_CH3 | CG_DMA_CH2 | CG_DMA_CH1 | CG_DMA_CH0 | + CG_I2C_MCLK | CG_MAD_MCLK | CG_AP2P_MCLK; +} + +#ifdef DEBUG +int command_ulposc(int argc, char *argv[]) +{ + int i; + + for (i = 0; i <= 1; ++i) + ccprintf("ULPOSC%u frequency: %u kHz\n", + i + 1, + clock_ulposc_measure_freq(i) * 26 * 1000 / 1024); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[ulposc]", + "Measure ULPOSC frequency"); +#endif diff --git a/chip/mt_scp/mt8192/clock_regs.h b/chip/mt_scp/mt8192/clock_regs.h new file mode 100644 index 0000000000..5928ca0473 --- /dev/null +++ b/chip/mt_scp/mt8192/clock_regs.h @@ -0,0 +1,85 @@ +/* Copyright 2021 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. + */ + +/* SCP clock module registers */ + +#ifndef __CROS_EC_CLOCK_REGS_H +#define __CROS_EC_CLOCK_REGS_H + +/* clock source select */ +#define SCP_CLK_SW_SEL REG32(SCP_CLK_CTRL_BASE + 0x0000) +#define CLK_SW_SEL_26M 0 +#define CLK_SW_SEL_32K 1 +#define CLK_SW_SEL_ULPOSC2 2 +#define CLK_SW_SEL_ULPOSC1 3 +#define SCP_CLK_ENABLE REG32(SCP_CLK_CTRL_BASE + 0x0004) +#define CLK_HIGH_EN BIT(1) /* ULPOSC */ +#define CLK_HIGH_CG BIT(2) +/* clock general control */ +#define SCP_CLK_CTRL_GENERAL_CTRL REG32(SCP_CLK_CTRL_BASE + 0x009C) +#define VREQ_PMIC_WRAP_SEL (0x2) + +/* TOPCK clk */ +#define TOPCK_BASE AP_REG_BASE +#define AP_CLK_MISC_CFG_0 REG32(TOPCK_BASE + 0x0140) +#define MISC_METER_DIVISOR_MASK 0xff000000 +#define MISC_METER_DIV_1 0 +/* OSC meter */ +#define AP_CLK_DBG_CFG REG32(TOPCK_BASE + 0x017C) +#define DBG_MODE_MASK 3 +#define DBG_MODE_SET_CLOCK 0 +#define DBG_BIST_SOURCE_MASK (0x3f << 16) +#define DBG_BIST_SOURCE_ULPOSC1 (0x25 << 16) +#define DBG_BIST_SOURCE_ULPOSC2 (0x24 << 16) +#define AP_SCP_CFG_0 REG32(TOPCK_BASE + 0x0220) +#define CFG_FREQ_METER_RUN BIT(4) +#define CFG_FREQ_METER_ENABLE BIT(12) +#define AP_SCP_CFG_1 REG32(TOPCK_BASE + 0x0224) +#define CFG_FREQ_COUNTER(CFG1) ((CFG1) & 0xFFFF) +/* + * ULPOSC + * osc: 0 for ULPOSC1, 1 for ULPOSC2. + */ +#define AP_ULPOSC_CON0_BASE (AP_REG_BASE + 0xC2B0) +#define AP_ULPOSC_CON1_BASE (AP_REG_BASE + 0xC2B4) +#define AP_ULPOSC_CON2_BASE (AP_REG_BASE + 0xC2B8) +#define AP_ULPOSC_CON0(osc) \ + REG32(AP_ULPOSC_CON0_BASE + (osc) * 0x10) +#define AP_ULPOSC_CON1(osc) \ + REG32(AP_ULPOSC_CON1_BASE + (osc) * 0x10) +#define AP_ULPOSC_CON2(osc) \ + REG32(AP_ULPOSC_CON2_BASE + (osc) * 0x10) +/* + * AP_ULPOSC_CON0 + * bit0-6: calibration + * bit7-13: iband + * bit14-17: fband + * bit18-23: div + * bit24: cp_en + * bit25-31: reserved + */ +#define OSC_CALI_MASK 0x7f +#define OSC_IBAND_SHIFT 7 +#define OSC_FBAND_SHIFT 14 +#define OSC_DIV_SHIFT 18 +#define OSC_CP_EN BIT(24) +/* AP_ULPOSC_CON1 + * bit0-7: 32K calibration + * bit 8-15: rsv1 + * bit 16-23: rsv2 + * bit 24-25: mod + * bit26: div2_en + * bit27-31: reserved + */ +#define OSC_RSV1_SHIFT 8 +#define OSC_RSV2_SHIFT 16 +#define OSC_MOD_SHIFT 24 +#define OSC_DIV2_EN BIT(26) +/* AP_ULPOSC_CON2 + * bit0-7: bias + * bit8-31: reserved + */ + +#endif /* __CROS_EC_CLOCK_REGS_H */ diff --git a/chip/mt_scp/mt8195/build.mk b/chip/mt_scp/mt8195/build.mk index 02ffdaeefe..5ca0f1033c 100644 --- a/chip/mt_scp/mt8195/build.mk +++ b/chip/mt_scp/mt8195/build.mk @@ -5,3 +5,4 @@ # Required chip modules chip-y+=$(CHIP_VARIANT)/uart.o +chip-y+=$(CHIP_VARIANT)/clock.o diff --git a/chip/mt_scp/mt8195/clock.c b/chip/mt_scp/mt8195/clock.c new file mode 100644 index 0000000000..bf85af2254 --- /dev/null +++ b/chip/mt_scp/mt8195/clock.c @@ -0,0 +1,432 @@ +/* Copyright 2021 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 +#include + +#include "clock.h" +#include "common.h" +#include "console.h" +#include "csr.h" +#include "ec_commands.h" +#include "power.h" +#include "registers.h" +#include "timer.h" + +#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ##args) +#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ##args) + +enum scp_clock_source { + SCP_CLK_SYSTEM, + SCP_CLK_32K, + SCP_CLK_ULPOSC1, + SCP_CLK_ULPOSC2_LOW_SPEED, + SCP_CLK_ULPOSC2_HIGH_SPEED, +}; + +enum { + OPP_ULPOSC2_LOW_SPEED, + OPP_ULPOSC2_HIGH_SPEED, +}; + +static struct opp_ulposc_cfg { + uint32_t osc; + uint32_t div; + uint32_t fband; + uint32_t mod; + uint32_t cali; + uint32_t target_mhz; + uint32_t clk_div; +} opp[] = { + [OPP_ULPOSC2_LOW_SPEED] = { + .osc = 1, .target_mhz = 326, .clk_div = CLK_DIV_SEL2, .div = 19, + .fband = 10, .mod = 0, .cali = 64, /* 326MHz / 2 = 163MHz */ + }, + [OPP_ULPOSC2_HIGH_SPEED] = { + .osc = 1, .target_mhz = 360, .clk_div = CLK_DIV_SEL1, .div = 21, + .fband = 10, .mod = 0, .cali = 64, /* 360MHz / 1 = 360MHz */ + }, +}; + +static inline void clock_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' in order to avoid compiler to optimize the function out + * (otherwise, the function will be eliminated). + */ + volatile int i = usec * 28; + + while (--i) + ; +} + +static void clock_ulposc_config_default(struct opp_ulposc_cfg *opp) +{ + uint32_t val = 0; + + /* set mod, div2_en = 0, cp_en = 0 */ + val |= opp->mod << OSC_MOD_SHIFT; + /* set div */ + val |= opp->div << OSC_DIV_SHIFT; + /* set F-band, I-band = 82 */ + val |= (opp->fband << OSC_FBAND_SHIFT) | (82 << OSC_IBAND_SHIFT); + /* set calibration */ + val |= opp->cali; + /* set control register 0 */ + AP_ULPOSC_CON0(opp->osc) = val; + + clock_busy_udelay(50); + + /* bias = 65 */ + val = 65 << OSC_BIAS_SHIFT; + /* rsv2 = 0, rsv1 = 41, cali_32k = 0 */ + val |= 41 << OSC_RSV1_SHIFT; + /* set control register 1 */ + AP_ULPOSC_CON1(opp->osc) = val; + + /* set settle time */ + SCP_CLK_HIGH_VAL = + (SCP_CLK_HIGH_VAL & ~CLK_HIGH_VAL_MASK) | CLK_HIGH_VAL_VAL(2); +} + +static void clock_ulposc_config_cali(struct opp_ulposc_cfg *opp, + uint32_t cali_val) +{ + uint32_t val; + + val = AP_ULPOSC_CON0(opp->osc); + val &= ~OSC_CALI_MASK; + val |= cali_val; + AP_ULPOSC_CON0(opp->osc) = val; + opp->cali = cali_val; + + clock_busy_udelay(50); +} + +static uint32_t clock_ulposc_measure_freq(uint32_t osc) +{ + uint32_t result = 0; + int cnt; + + /* Set ckgen_load_cnt: CLK26CALI_1[25:16] */ + AP_CLK26CALI_1 = CFG_CKGEN_LOAD_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 monclk_ext2fqmtr_sel: AP_CLK_DBG_CFG[14:8] */ + 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_CLK26CALI_0 |= CFG_FREQ_METER_ENABLE; + + /* trigger frequency meter start */ + AP_CLK26CALI_0 |= CFG_FREQ_METER_RUN; + + clock_busy_udelay(45); + + for (cnt = 10000; cnt > 0; --cnt) { + clock_busy_udelay(10); + if (!(AP_CLK26CALI_0 & CFG_FREQ_METER_RUN)) { + result = CFG_FREQ_COUNTER(AP_CLK26CALI_1); + break; + } + } + + /* disable freq meter */ + AP_CLK26CALI_0 &= ~CFG_FREQ_METER_ENABLE; + + return result; +} + +#define CAL_MIS_RATE 40 +static int clock_ulposc_is_calibrated(struct opp_ulposc_cfg *opp) +{ + uint32_t curr, target; + + curr = clock_ulposc_measure_freq(opp->osc); + target = opp->target_mhz * 512 / 26; + +#ifdef DEBUG + CPRINTF("osc:%u, target=%uMHz, curr=%uMHz, cali:%u\n", + opp->osc, opp->target_mhz, (curr * 26) / 512, opp->cali); +#endif + + /* check if calibrated value is in the range of target value +- 4% */ + if (curr > (target * (1000 - CAL_MIS_RATE) / 1000) && + curr < (target * (1000 + CAL_MIS_RATE) / 1000)) + return 1; + else + return 0; +} + +static uint32_t clock_ulposc_process_cali(struct opp_ulposc_cfg *opp) +{ + uint32_t current_val = 0; + uint32_t target_val = opp->target_mhz * 512 / 26; + uint32_t middle, min = 0, max = OSC_CALI_MASK; + uint32_t diff_by_min, diff_by_max, cal_result; + + do { + middle = (min + max) / 2; + if (middle == min) + break; + + clock_ulposc_config_cali(opp, middle); + current_val = clock_ulposc_measure_freq(opp->osc); + + if (current_val > target_val) + max = middle; + else + min = middle; + } while (min <= max); + + clock_ulposc_config_cali(opp, min); + current_val = clock_ulposc_measure_freq(opp->osc); + if (current_val > target_val) + diff_by_min = current_val - target_val; + else + diff_by_min = target_val - current_val; + + clock_ulposc_config_cali(opp, max); + current_val = clock_ulposc_measure_freq(opp->osc); + if (current_val > target_val) + diff_by_max = current_val - target_val; + else + diff_by_max = target_val - current_val; + + if (diff_by_min < diff_by_max) + cal_result = min; + else + cal_result = max; + + clock_ulposc_config_cali(opp, cal_result); + if (!clock_ulposc_is_calibrated(opp)) + assert(0); + + return cal_result; +} + +static void clock_high_enable(int osc) +{ + /* enable high speed clock */ + SCP_CLK_ENABLE |= CLK_HIGH_EN; + + switch (osc) { + case 0: + /* after 150us, enable ULPOSC */ + clock_busy_udelay(150); + SCP_CLK_ENABLE |= CLK_HIGH_CG | CLK_HIGH_EN; + + /* topck ulposc1 clk gating off */ + AP_CLK_CFG_29_CLR = PDN_F_ULPOSC_CK; + /* select topck ulposc1 as scp clk parent */ + AP_CLK_CFG_29_CLR = ULPOSC1_CLK_SEL; + + AP_CLK_CFG_UPDATE3 = F_ULPOSC_CK_UPDATE; + clock_busy_udelay(50); + break; + case 1: + /* turn off ULPOSC2 high-core-disable switch */ + SCP_CLK_ON_CTRL &= ~HIGH_CORE_DIS_SUB; + /* after 150us, scp requests ULPOSC2 high core clock */ + clock_busy_udelay(150); + SCP_CLK_HIGH_CORE_CG |= HIGH_CORE_CG; + SCP_CLK_ENABLE &= ~CLK_HIGH_CG; + clock_busy_udelay(50); + + /* topck ulposc2 clk gating off */ + AP_CLK_CFG_29_CLR = PDN_F_ULPOSC_CORE_CK; + /* select topck ulposc2 as scp clk parent */ + AP_CLK_CFG_29_CLR = ULPOSC2_CLK_SEL; + + AP_CLK_CFG_UPDATE3 = F_ULPOSC_CORE_CK_UPDATE; + clock_busy_udelay(50); + break; + default: + break; + } +} + +static void clock_high_disable(int osc) +{ + switch (osc) { + case 0: + /* topck ulposc1 clk gating on */ + AP_CLK_CFG_29_SET = PDN_F_ULPOSC_CK; + AP_CLK_CFG_UPDATE3 = F_ULPOSC_CK_UPDATE; + clock_busy_udelay(50); + + /* scp doesn't request ulposc1 clk */ + SCP_CLK_ENABLE &= ~CLK_HIGH_CG; + clock_busy_udelay(50); + SCP_CLK_ENABLE &= ~CLK_HIGH_EN; + clock_busy_udelay(50); + break; + case 1: + /* topck ulposc2 clk gating on */ + AP_CLK_CFG_29_SET = PDN_F_ULPOSC_CORE_CK; + AP_CLK_CFG_UPDATE3 = F_ULPOSC_CORE_CK_UPDATE; + clock_busy_udelay(50); + + /* scp doesn't request ulposc2 clk */ + SCP_CLK_HIGH_CORE_CG &= ~HIGH_CORE_CG; + clock_busy_udelay(50); + SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; + clock_busy_udelay(50); + break; + default: + break; + } +} + +static void clock_calibrate_ulposc(struct opp_ulposc_cfg *opp) +{ + /* + * ULPOSC1(osc=0) is already + * - calibrated + * - enabled in coreboot + * - used by pmic wrapper + */ + if (opp->osc != 0) { + clock_high_disable(opp->osc); + clock_ulposc_config_default(opp); + clock_high_enable(opp->osc); + } + + /* Calibrate only if it is not accurate enough. */ + if (!clock_ulposc_is_calibrated(opp)) + opp->cali = clock_ulposc_process_cali(opp); +} + +static void clock_select_clock(enum scp_clock_source src) +{ + uint32_t sel; + uint32_t div; + + switch (src) { + case SCP_CLK_SYSTEM: + div = CLK_DIV_SEL1; + sel = CLK_SW_SEL_SYSTEM; + break; + case SCP_CLK_32K: + div = CLK_DIV_SEL1; + sel = CLK_SW_SEL_32K; + break; + case SCP_CLK_ULPOSC1: + div = CLK_DIV_SEL1; + sel = CLK_SW_SEL_ULPOSC1; + break; + case SCP_CLK_ULPOSC2_LOW_SPEED: + /* parking at scp system clk until ulposc clk is ready */ + clock_select_clock(SCP_CLK_SYSTEM); + + clock_ulposc_config_cali(&opp[OPP_ULPOSC2_LOW_SPEED], + opp[OPP_ULPOSC2_LOW_SPEED].cali); + div = opp[OPP_ULPOSC2_LOW_SPEED].clk_div; + + sel = CLK_SW_SEL_ULPOSC2; + break; + case SCP_CLK_ULPOSC2_HIGH_SPEED: + /* parking at scp system clk until ulposc clk is ready */ + clock_select_clock(SCP_CLK_SYSTEM); + + clock_ulposc_config_cali(&opp[OPP_ULPOSC2_HIGH_SPEED], + opp[OPP_ULPOSC2_HIGH_SPEED].cali); + div = opp[OPP_ULPOSC2_HIGH_SPEED].clk_div; + + sel = CLK_SW_SEL_ULPOSC2; + break; + default: + div = CLK_DIV_SEL1; + sel = CLK_SW_SEL_SYSTEM; + break; + } + + SCP_CLK_DIV_SEL = div; + SCP_CLK_SW_SEL = sel; +} + +__override void +power_chipset_handle_host_sleep_event(enum host_sleep_event state, + struct host_sleep_event_context *ctx) +{ + if (state == HOST_SLEEP_EVENT_S3_SUSPEND) { + CPRINTS("AP suspend"); + clock_select_clock(SCP_CLK_ULPOSC2_LOW_SPEED); + } else if (state == HOST_SLEEP_EVENT_S3_RESUME) { + CPRINTS("AP resume"); + clock_select_clock(SCP_CLK_ULPOSC2_HIGH_SPEED); + } +} + +void clock_init(void) +{ + uint32_t i; + + /* select scp system clock (default 26MHz) */ + clock_select_clock(SCP_CLK_SYSTEM); + + /* set VREQ to HW mode */ + SCP_CPU_VREQ_CTRL = VREQ_SEL | VREQ_DVFS_SEL; + SCP_CLK_CTRL_GENERAL_CTRL &= ~VREQ_PMIC_WRAP_SEL; + SCP_SEC_CTRL &= ~VREQ_SECURE_DIS; + + /* set DDREN to auto mode */ + SCP_SYS_CTRL |= AUTO_DDREN; + + /* set settle time */ + SCP_CLK_SYS_VAL = + (SCP_CLK_SYS_VAL & ~CLK_SYS_VAL_MASK) | CLK_SYS_VAL_VAL(1); + SCP_CLK_HIGH_VAL = + (SCP_CLK_HIGH_VAL & ~CLK_HIGH_VAL_MASK) | CLK_HIGH_VAL_VAL(1); + SCP_SLEEP_CTRL = + (SCP_SLEEP_CTRL & ~VREQ_COUNT_MASK) | VREQ_COUNT_VAL(1); + + /* turn off ULPOSC2 */ + SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; + + /* calibrate ULPOSC2 */ + for (i = 0; i < ARRAY_SIZE(opp); ++i) + clock_calibrate_ulposc(&opp[i]); + + /* select ULPOSC2 high speed SCP clock */ + clock_select_clock(SCP_CLK_ULPOSC2_HIGH_SPEED); + + /* select BCLK to use ULPOSC / 8 */ + SCP_BCLK_CK_SEL = BCLK_CK_SEL_ULPOSC_DIV8; + + /* enable default clock gate */ + SCP_SET_CLK_CG |= CG_DMA_CH3 | CG_DMA_CH2 | CG_DMA_CH1 | CG_DMA_CH0 | + CG_I2C_MCLK | CG_MAD_MCLK | CG_AP2P_MCLK; +} + +#ifdef DEBUG +int command_ulposc(int argc, char *argv[]) +{ + uint32_t osc; + + for (osc = 0; osc <= OPP_ULPOSC2_HIGH_SPEED; ++osc) + ccprintf("ULPOSC%u frequency: %u kHz\n", osc + 1, + clock_ulposc_measure_freq(osc) * 26 * 1000 / 512); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[ulposc]", + "Measure ULPOSC frequency"); +#endif diff --git a/chip/mt_scp/mt8195/clock_regs.h b/chip/mt_scp/mt8195/clock_regs.h new file mode 100644 index 0000000000..6e7ec6bdbb --- /dev/null +++ b/chip/mt_scp/mt8195/clock_regs.h @@ -0,0 +1,92 @@ +/* Copyright 2021 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. + */ + +/* SCP clock module registers */ + +#ifndef __CROS_EC_CLOCK_REGS_H +#define __CROS_EC_CLOCK_REGS_H + +/* clock source select */ +#define SCP_CLK_SW_SEL REG32(SCP_CLK_CTRL_BASE + 0x0000) +#define CLK_SW_SEL_SYSTEM 0 +#define CLK_SW_SEL_32K 1 +#define CLK_SW_SEL_ULPOSC2 2 +#define CLK_SW_SEL_ULPOSC1 3 +#define SCP_CLK_ENABLE REG32(SCP_CLK_CTRL_BASE + 0x0004) +#define CLK_HIGH_EN BIT(1) /* ULPOSC */ +#define CLK_HIGH_CG BIT(2) +/* clock general control */ +#define SCP_CLK_CTRL_GENERAL_CTRL REG32(SCP_CLK_CTRL_BASE + 0x009C) +#define VREQ_PMIC_WRAP_SEL (0x3) + +/* TOPCK clk */ +#define TOPCK_BASE AP_REG_BASE +#define AP_CLK_CFG_UPDATE3 REG32(TOPCK_BASE + 0x0010) +#define F_ULPOSC_CK_UPDATE BIT(21) +#define F_ULPOSC_CORE_CK_UPDATE BIT(22) +#define AP_CLK_CFG_29_SET REG32(TOPCK_BASE + 0x0180) +#define AP_CLK_CFG_29_CLR REG32(TOPCK_BASE + 0x0184) +#define ULPOSC1_CLK_SEL (0x3 << 8) +#define PDN_F_ULPOSC_CK BIT(15) +#define ULPOSC2_CLK_SEL (0x3 << 16) +#define PDN_F_ULPOSC_CORE_CK BIT(23) +/* OSC meter */ +#define AP_CLK_DBG_CFG REG32(TOPCK_BASE + 0x020C) +#define DBG_MODE_MASK 3 +#define DBG_MODE_SET_CLOCK 0 +#define DBG_BIST_SOURCE_MASK (0x7f << 8) +#define DBG_BIST_SOURCE_ULPOSC1 (0x30 << 8) +#define DBG_BIST_SOURCE_ULPOSC2 (0x32 << 8) +#define AP_CLK26CALI_0 REG32(TOPCK_BASE + 0x0218) +#define CFG_FREQ_METER_RUN BIT(4) +#define CFG_FREQ_METER_ENABLE BIT(7) +#define AP_CLK26CALI_1 REG32(TOPCK_BASE + 0x021C) +#define CFG_CKGEN_LOAD_CNT 0x01ff0000 +#define CFG_FREQ_COUNTER(CFG1) ((CFG1) & 0xFFFF) +#define AP_CLK_MISC_CFG_0 REG32(TOPCK_BASE + 0x022C) +#define MISC_METER_DIVISOR_MASK 0xff000000 +#define MISC_METER_DIV_1 0 +/* + * ULPOSC + * osc: 0 for ULPOSC1, 1 for ULPOSC2. + */ +#define AP_ULPOSC_CON0_BASE (AP_REG_BASE + 0xC2B0) +#define AP_ULPOSC_CON1_BASE (AP_REG_BASE + 0xC2B4) +#define AP_ULPOSC_CON0(osc) \ + REG32(AP_ULPOSC_CON0_BASE + (osc) * 0x10) +#define AP_ULPOSC_CON1(osc) \ + REG32(AP_ULPOSC_CON1_BASE + (osc) * 0x10) +/* + * AP_ULPOSC_CON0 + * bit0-6: calibration + * bit7-13: iband + * bit14-17: fband + * bit18-23: div + * bit24: cp_en + * bit25-26: mod + * bit27: div2_en + * bit28-31: reserved + */ +#define OSC_CALI_SHIFT 0 +#define OSC_CALI_MASK 0x7f +#define OSC_IBAND_SHIFT 7 +#define OSC_FBAND_SHIFT 14 +#define OSC_DIV_SHIFT 18 +#define OSC_CP_EN BIT(24) +#define OSC_MOD_SHIFT 25 +#define OSC_DIV2_EN BIT(27) +/* + * AP_ULPOSC_CON1 + * bit0-7: rsv1 + * bit8-15: rsv2 + * bit16-23: 32K calibration + * bit24-31: bias + */ +#define OSC_RSV1_SHIFT 0 +#define OSC_RSV2_SHIFT 8 +#define OSC_32KCALI_SHIFT 16 +#define OSC_BIAS_SHIFT 24 + +#endif /* __CROS_EC_CLOCK_REGS_H */ diff --git a/chip/mt_scp/rv32i_common/build.mk b/chip/mt_scp/rv32i_common/build.mk index 3c09548a8c..ac7e13db77 100644 --- a/chip/mt_scp/rv32i_common/build.mk +++ b/chip/mt_scp/rv32i_common/build.mk @@ -10,7 +10,6 @@ CORE:=riscv-rv32i # Required chip modules chip-y+=rv32i_common/cache.o -chip-y+=rv32i_common/clock.o chip-y+=rv32i_common/gpio.o chip-y+=rv32i_common/intc.o chip-y+=rv32i_common/memmap.o diff --git a/chip/mt_scp/rv32i_common/clock.c b/chip/mt_scp/rv32i_common/clock.c deleted file mode 100644 index a460d818c7..0000000000 --- a/chip/mt_scp/rv32i_common/clock.c +++ /dev/null @@ -1,363 +0,0 @@ -/* Copyright 2020 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 -#include - -#include "clock_chip.h" -#include "clock.h" -#include "common.h" -#include "console.h" -#include "csr.h" -#include "ec_commands.h" -#include "power.h" -#include "registers.h" -#include "timer.h" - -#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ##args) -#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ##args) - -static struct opp_ulposc_cfg { - uint32_t osc; - uint32_t div; - uint32_t fband; - uint32_t mod; - uint32_t cali; - uint32_t target_mhz; -} opp[] = { - { - .osc = 1, .target_mhz = 196, .div = 20, .fband = 10, .mod = 3, - .cali = 64, - }, - { - .osc = 0, .target_mhz = 260, .div = 14, .fband = 2, .mod = 0, - .cali = 64, - }, - { - .osc = 1, .target_mhz = 280, .div = 20, .fband = 2, .mod = 0, - .cali = 64, - }, - { - .osc = 1, .target_mhz = 360, .div = 20, .fband = 10, .mod = 0, - .cali = 64, - }, -}; - -static inline void clock_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' in order to avoid compiler to optimize the function out - * (otherwise, the function will be eliminated). - */ - volatile int i = usec * 28; - - while (--i) - ; -} - -static void clock_ulposc_config_default(struct opp_ulposc_cfg *opp) -{ - unsigned int val = 0; - - /* set div */ - val |= opp->div << OSC_DIV_SHIFT; - /* set F-band; I-band = 82 */ - val |= (opp->fband << OSC_FBAND_SHIFT) | (82 << OSC_IBAND_SHIFT); - /* set calibration */ - val |= opp->cali; - /* set control register 0 */ - AP_ULPOSC_CON0(opp->osc) = val; - - /* set mod */ - val = opp->mod << OSC_MOD_SHIFT; - /* rsv2 = 0, rsv1 = 41, cali_32k = 0 */ - val |= 41 << OSC_RSV1_SHIFT; - /* set control register 1 */ - AP_ULPOSC_CON1(opp->osc) = val; - - /* bias = 64 */ - AP_ULPOSC_CON2(opp->osc) = 64; -} - -static void clock_ulposc_config_cali(struct opp_ulposc_cfg *opp, - uint32_t cali_val) -{ - uint32_t val; - - val = AP_ULPOSC_CON0(opp->osc); - val &= ~OSC_CALI_MASK; - val |= cali_val; - AP_ULPOSC_CON0(opp->osc) = val; - - clock_busy_udelay(50); -} - -static uint32_t clock_ulposc_measure_freq(uint32_t osc) -{ - uint32_t 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 clock_busy_udelay may not be accurate when sysclk is not 26Mhz - * (e.g. when recalibrating/measuring after boot). - */ - for (cnt = 100; cnt > 0; --cnt) { - clock_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; -} - -#define CAL_MIS_RATE 40 -static int clock_ulposc_is_calibrated(struct opp_ulposc_cfg *opp) -{ - uint32_t curr, target; - - curr = clock_ulposc_measure_freq(opp->osc); - target = opp->target_mhz * 1024 / 26; - - /* check if calibrated value is in the range of target value +- 4% */ - if (curr > (target * (1000 - CAL_MIS_RATE) / 1000) && - curr < (target * (1000 + CAL_MIS_RATE) / 1000)) - return 1; - else - return 0; -} - -static uint32_t clock_ulposc_process_cali(struct opp_ulposc_cfg *opp) -{ - uint32_t current_val = 0; - uint32_t target_val = opp->target_mhz * 1024 / 26; - uint32_t middle, min = 0, max = OSC_CALI_MASK; - uint32_t diff_by_min, diff_by_max, cal_result; - - do { - middle = (min + max) / 2; - if (middle == min) - break; - - clock_ulposc_config_cali(opp, middle); - current_val = clock_ulposc_measure_freq(opp->osc); - - if (current_val > target_val) - max = middle; - else - min = middle; - } while (min <= max); - - clock_ulposc_config_cali(opp, min); - current_val = clock_ulposc_measure_freq(opp->osc); - if (current_val > target_val) - diff_by_min = current_val - target_val; - else - diff_by_min = target_val - current_val; - - clock_ulposc_config_cali(opp, max); - current_val = clock_ulposc_measure_freq(opp->osc); - if (current_val > target_val) - diff_by_max = current_val - target_val; - else - diff_by_max = target_val - current_val; - - if (diff_by_min < diff_by_max) - cal_result = min; - else - cal_result = max; - - clock_ulposc_config_cali(opp, cal_result); - if (!clock_ulposc_is_calibrated(opp)) - assert(0); - - return cal_result; -} - -static void clock_high_enable(int osc) -{ - /* enable high speed clock */ - SCP_CLK_ENABLE |= CLK_HIGH_EN; - - switch (osc) { - case 0: - /* after 150us, enable ULPOSC */ - clock_busy_udelay(150); - SCP_CLK_ENABLE |= CLK_HIGH_CG; - break; - case 1: - /* turn off ULPOSC2 high-core-disable switch */ - SCP_CLK_ON_CTRL &= ~HIGH_CORE_DIS_SUB; - /* after 150us, turn on ULPOSC2 high core clock gate */ - clock_busy_udelay(150); - SCP_CLK_HIGH_CORE_CG |= HIGH_CORE_CG; - clock_busy_udelay(50); - break; - default: - break; - } -} - -static void clock_high_disable(int osc) -{ - switch (osc) { - case 0: - SCP_CLK_ENABLE &= ~CLK_HIGH_CG; - clock_busy_udelay(50); - SCP_CLK_ENABLE &= ~CLK_HIGH_EN; - clock_busy_udelay(50); - break; - case 1: - SCP_CLK_HIGH_CORE_CG &= ~HIGH_CORE_CG; - clock_busy_udelay(50); - SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; - clock_busy_udelay(50); - break; - default: - break; - } -} - -static void clock_calibrate_ulposc(struct opp_ulposc_cfg *opp) -{ - /* - * ULPOSC1(osc=0) is already - * - calibrated - * - enabled in coreboot - * - used by pmic wrapper - */ - if (opp->osc != 0) { - clock_high_disable(opp->osc); - clock_ulposc_config_default(opp); - clock_high_enable(opp->osc); - } - - /* Calibrate only if it is not accurate enough. */ - if (!clock_ulposc_is_calibrated(opp)) - opp->cali = clock_ulposc_process_cali(opp); - -#ifdef DEBUG - CPRINTF("osc:%u, target=%uMHz, cal:%u\n", - opp->osc, opp->target_mhz, opp->cali); -#endif -} - -void clock_select_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_DIV_SEL2; - - SCP_CLK_SW_SEL = src; - - if (src != SCP_CLK_ULPOSC1) - SCP_CLK_DIV_SEL = CLK_DIV_SEL1; -} - -__override void -power_chipset_handle_host_sleep_event(enum host_sleep_event state, - struct host_sleep_event_context *ctx) -{ - if (state == HOST_SLEEP_EVENT_S3_SUSPEND) { - CPRINTS("AP suspend"); - clock_select_clock(SCP_CLK_ULPOSC1); - } else if (state == HOST_SLEEP_EVENT_S3_RESUME) { - CPRINTS("AP resume"); - clock_select_clock(SCP_CLK_ULPOSC2); - } -} - -void clock_init(void) -{ - int i; - - /* select default 26M system clock */ - clock_select_clock(SCP_CLK_26M); - - /* set VREQ to HW mode */ - SCP_CPU_VREQ_CTRL = VREQ_SEL | VREQ_DVFS_SEL; - SCP_CLK_CTRL_GENERAL_CTRL &= ~VREQ_PMIC_WRAP_SEL; - SCP_SEC_CTRL &= ~VREQ_SECURE_DIS; - - /* set DDREN to auto mode */ - SCP_SYS_CTRL |= AUTO_DDREN; - - /* set settle time */ - SCP_CLK_SYS_VAL = - (SCP_CLK_SYS_VAL & ~CLK_SYS_VAL_MASK) | CLK_SYS_VAL_VAL(1); - SCP_CLK_HIGH_VAL = - (SCP_CLK_HIGH_VAL & ~CLK_HIGH_VAL_MASK) | CLK_HIGH_VAL_VAL(1); - SCP_SLEEP_CTRL = - (SCP_SLEEP_CTRL & ~VREQ_COUNT_MASK) | VREQ_COUNT_VAL(1); - - /* turn off ULPOSC2 */ - SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; - - /* calibrate ULPOSC */ - for (i = 0; i < ARRAY_SIZE(opp); ++i) - clock_calibrate_ulposc(&opp[i]); - - /* select ULPOSC2 high speed CPU clock */ - clock_select_clock(SCP_CLK_ULPOSC2); - - /* select BCLK to use ULPOSC1 / 8 = 260MHz / 8 = 32.5MHz */ - SCP_BCLK_CK_SEL = BCLK_CK_SEL_ULPOSC_DIV8; - - /* enable default clock gate */ - SCP_SET_CLK_CG |= CG_DMA_CH3 | CG_DMA_CH2 | CG_DMA_CH1 | CG_DMA_CH0 | - CG_I2C_MCLK | CG_MAD_MCLK | CG_AP2P_MCLK; -} - -#ifdef DEBUG -int command_ulposc(int argc, char *argv[]) -{ - int i; - - for (i = 0; i <= 1; ++i) - ccprintf("ULPOSC%u frequency: %u kHz\n", - i + 1, - clock_ulposc_measure_freq(i) * 26 * 1000 / 1024); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[ulposc]", - "Measure ULPOSC frequency"); -#endif diff --git a/chip/mt_scp/rv32i_common/clock_chip.h b/chip/mt_scp/rv32i_common/clock_chip.h deleted file mode 100644 index ee1c22be92..0000000000 --- a/chip/mt_scp/rv32i_common/clock_chip.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2020 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 */ - -#ifndef __CROS_EC_CLOCK_CHIP_H -#define __CROS_EC_CLOCK_CHIP_H - -#include "registers.h" - -enum scp_clock_source { - SCP_CLK_26M = CLK_SW_SEL_26M, - SCP_CLK_32K = CLK_SW_SEL_32K, - SCP_CLK_ULPOSC2 = CLK_SW_SEL_ULPOSC2, - SCP_CLK_ULPOSC1 = CLK_SW_SEL_ULPOSC1, -}; - -/* Switches to use 'src' clock */ -void clock_select_clock(enum scp_clock_source src); - -#endif /* __CROS_EC_CLOCK_CHIP_H */ diff --git a/chip/mt_scp/rv32i_common/registers.h b/chip/mt_scp/rv32i_common/registers.h index f4d03aa228..b19afe5e0d 100644 --- a/chip/mt_scp/rv32i_common/registers.h +++ b/chip/mt_scp/rv32i_common/registers.h @@ -17,15 +17,6 @@ /* clock control */ #define SCP_CLK_CTRL_BASE (SCP_REG_BASE + 0x21000) -/* clock source select */ -#define SCP_CLK_SW_SEL REG32(SCP_CLK_CTRL_BASE + 0x0000) -#define CLK_SW_SEL_26M 0 -#define CLK_SW_SEL_32K 1 -#define CLK_SW_SEL_ULPOSC2 2 -#define CLK_SW_SEL_ULPOSC1 3 -#define SCP_CLK_ENABLE REG32(SCP_CLK_CTRL_BASE + 0x0004) -#define CLK_HIGH_EN BIT(1) /* ULPOSC */ -#define CLK_HIGH_CG BIT(2) /* system clock counter value */ #define SCP_CLK_SYS_VAL REG32(SCP_CLK_CTRL_BASE + 0x0014) #define CLK_SYS_VAL_MASK (0x3ff << 0) @@ -117,9 +108,6 @@ #define HIGH_CORE_AO BIT(4) #define HIGH_CORE_DIS_SUB BIT(5) #define HIGH_CORE_CG_AO BIT(6) -/* clock general control */ -#define SCP_CLK_CTRL_GENERAL_CTRL REG32(SCP_CLK_CTRL_BASE + 0x009C) -#define VREQ_PMIC_WRAP_SEL (0x2) /* system control */ #define SCP_SYS_CTRL REG32(SCP_REG_BASE + 0x24000) @@ -212,22 +200,6 @@ /* external address: AP */ #define AP_REG_BASE 0x60000000 /* 0x10000000 remap to 0x6 */ -/* OSC meter */ -#define TOPCK_BASE AP_REG_BASE -#define AP_CLK_MISC_CFG_0 REG32(TOPCK_BASE + 0x0140) -#define MISC_METER_DIVISOR_MASK 0xff000000 -#define MISC_METER_DIV_1 0 -#define AP_CLK_DBG_CFG REG32(TOPCK_BASE + 0x017C) -#define DBG_MODE_MASK 3 -#define DBG_MODE_SET_CLOCK 0 -#define DBG_BIST_SOURCE_MASK (0x3f << 16) -#define DBG_BIST_SOURCE_ULPOSC1 (0x25 << 16) -#define DBG_BIST_SOURCE_ULPOSC2 (0x24 << 16) -#define AP_SCP_CFG_0 REG32(TOPCK_BASE + 0x0220) -#define CFG_FREQ_METER_RUN BIT(4) -#define CFG_FREQ_METER_ENABLE BIT(12) -#define AP_SCP_CFG_1 REG32(TOPCK_BASE + 0x0224) -#define CFG_FREQ_COUNTER(CFG1) ((CFG1) & 0xFFFF) /* AP GPIO */ #define AP_GPIO_BASE (AP_REG_BASE + 0x5000) #define AP_GPIO_MODE11_SET REG32(AP_GPIO_BASE + 0x03B4) @@ -236,49 +208,8 @@ #define AP_GPIO_MODE12_CLR REG32(AP_GPIO_BASE + 0x03C8) #define AP_GPIO_MODE20_SET REG32(AP_GPIO_BASE + 0x0444) #define AP_GPIO_MODE20_CLR REG32(AP_GPIO_BASE + 0x0448) -/* - * ULPOSC - * osc: 0 for ULPOSC1, 1 for ULPOSC2. - */ -#define AP_ULPOSC_CON0_BASE (AP_REG_BASE + 0xC2B0) -#define AP_ULPOSC_CON1_BASE (AP_REG_BASE + 0xC2B4) -#define AP_ULPOSC_CON2_BASE (AP_REG_BASE + 0xC2B8) -#define AP_ULPOSC_CON0(osc) \ - REG32(AP_ULPOSC_CON0_BASE + (osc) * 0x10) -#define AP_ULPOSC_CON1(osc) \ - REG32(AP_ULPOSC_CON1_BASE + (osc) * 0x10) -#define AP_ULPOSC_CON2(osc) \ - REG32(AP_ULPOSC_CON2_BASE + (osc) * 0x10) -/* - * AP_ULPOSC_CON0 - * bit0-6: calibration - * bit7-13: iband - * bit14-17: fband - * bit18-23: div - * bit24: cp_en - * bit25-31: reserved - */ -#define OSC_CALI_MASK 0x7f -#define OSC_IBAND_SHIFT 7 -#define OSC_FBAND_SHIFT 14 -#define OSC_DIV_SHIFT 18 -#define OSC_CP_EN BIT(24) -/* AP_ULPOSC_CON1 - * bit0-7: 32K calibration - * bit 8-15: rsv1 - * bit 16-23: rsv2 - * bit 24-25: mod - * bit26: div2_en - * bit27-31: reserved - */ -#define OSC_RSV1_SHIFT 8 -#define OSC_RSV2_SHIFT 16 -#define OSC_MOD_SHIFT 24 -#define OSC_DIV2_EN BIT(26) -/* AP_ULPOSC_CON2 - * bit0-7: bias - * bit8-31: reserved - */ + +#include "clock_regs.h" /* IRQ numbers */ #define SCP_IRQ_GIPC_IN0 0 -- cgit v1.2.1