From 22f8370def35d33a67189b9643114bf3e00e2c47 Mon Sep 17 00:00:00 2001 From: Hsin-Hsiung Wang Date: Fri, 29 May 2020 19:46:14 +0800 Subject: soc/mediatek/mt8192: add pmif driver MT8192 uses power management interface (PMIF) to access pmics by spmi and spi, so we add pmif driver to control pmics. BUG=b:155253454 BRANCH=none TEST=boot asurada correctly Signed-off-by: Hsin-Hsiung Wang Change-Id: I32fc28f72d9522133baa06f9d67c383f814d862c Reviewed-on: https://review.coreboot.org/c/coreboot/+/45398 Reviewed-by: Hung-Te Lin Tested-by: build bot (Jenkins) --- src/soc/mediatek/mt8192/pmif_clk.c | 172 +++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/soc/mediatek/mt8192/pmif_clk.c (limited to 'src/soc/mediatek/mt8192/pmif_clk.c') diff --git a/src/soc/mediatek/mt8192/pmif_clk.c b/src/soc/mediatek/mt8192/pmif_clk.c new file mode 100644 index 0000000000..4e68f3e7b0 --- /dev/null +++ b/src/soc/mediatek/mt8192/pmif_clk.c @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* APMIXED, ULPOSC1_CON0 */ +DEFINE_BITFIELD(OSC1_CALI, 6, 0) +DEFINE_BITFIELD(OSC1_IBAND, 13, 7) +DEFINE_BITFIELD(OSC1_FBAND, 17, 14) +DEFINE_BITFIELD(OSC1_DIV, 23, 18) +DEFINE_BIT(OSC1_CP_EN, 24) + +/* APMIXED, ULPOSC1_CON1 */ +DEFINE_BITFIELD(OSC1_32KCALI, 7, 0) +DEFINE_BITFIELD(OSC1_RSV1, 15, 8) +DEFINE_BITFIELD(OSC1_RSV2, 23, 16) +DEFINE_BITFIELD(OSC1_MOD, 25, 24) +DEFINE_BIT(OSC1_DIV2_EN, 26) + +/* APMIXED, ULPOSC1_CON2 */ +DEFINE_BITFIELD(OSC1_BIAS, 7, 0) + +/* SPM, POWERON_CONFIG_EN */ +DEFINE_BIT(BCLK_CG_EN, 0) +DEFINE_BITFIELD(PROJECT_CODE, 31, 16) + +/* SPM, ULPOSC_CON */ +DEFINE_BIT(ULPOSC_EN, 0) +DEFINE_BIT(ULPOSC_CG_EN, 2) + +/* INFRA, MODULE_SW_CG */ +DEFINE_BIT(PMIC_CG_TMR, 0) +DEFINE_BIT(PMIC_CG_AP, 1) +DEFINE_BIT(PMIC_CG_MD, 2) +DEFINE_BIT(PMIC_CG_CONN, 3) + +/* INFRA, INFRA_GLOBALCON_RST2 */ +DEFINE_BIT(PMIC_WRAP_SWRST, 0) +DEFINE_BIT(PMICSPMI_SWRST, 14) + +/* INFRA, PMICW_CLOCK_CTRL */ +DEFINE_BITFIELD(PMIC_SYSCK_26M_SEL, 3, 0) + +/* TOPCKGEN, CLK_CFG_8 */ +DEFINE_BITFIELD(CLK_PWRAP_ULPOSC_SET, 10, 8) +DEFINE_BIT(CLK_PWRAP_ULPOSC_INV, 12) +DEFINE_BIT(PDN_PWRAP_ULPOSC, 15) + +/* TOPCKGEN, CLK_CFG_UPDATE1 */ +DEFINE_BIT(CLK_CFG_UPDATE1, 2) + +static void pmif_ulposc_config(void) +{ + /* ULPOSC1_CON0 */ + SET32_BITFIELDS(&mtk_apmixed->ulposc1_con0, OSC1_CP_EN, 0, OSC1_DIV, 0xe, + OSC1_FBAND, 0x2, OSC1_IBAND, 0x52, OSC1_CALI, 0x40); + + /* ULPOSC1_CON1 */ + SET32_BITFIELDS(&mtk_apmixed->ulposc1_con1, OSC1_DIV2_EN, 0, OSC1_MOD, 0, + OSC1_RSV2, 0, OSC1_RSV1, 0x29, OSC1_32KCALI, 0); + + /* ULPOSC1_CON2 */ + SET32_BITFIELDS(&mtk_apmixed->ulposc1_con2, OSC1_BIAS, 0x40); +} + +static u32 pmif_get_ulposc_freq_mhz(u32 cali_val) +{ + u32 result = 0; + + /* set calibration value */ + SET32_BITFIELDS(&mtk_apmixed->ulposc1_con0, OSC1_CALI, cali_val); + udelay(50); + result = mt_fmeter_get_freq_khz(FMETER_ABIST, FREQ_METER_ABIST_AD_OSC_CK); + + return result / 1000; +} + +static int pmif_ulposc_cali(void) +{ + u32 current_val = 0, min = 0, max = CAL_MAX_VAL, middle; + int ret = 0, diff_by_min, diff_by_max, cal_result; + + do { + middle = (min + max) / 2; + if (middle == min) + break; + + current_val = pmif_get_ulposc_freq_mhz(middle); + if (current_val > FREQ_260MHZ) + max = middle; + else + min = middle; + } while (min <= max); + + diff_by_min = pmif_get_ulposc_freq_mhz(min) - FREQ_260MHZ; + diff_by_min = ABS(diff_by_min); + + diff_by_max = pmif_get_ulposc_freq_mhz(max) - FREQ_260MHZ; + diff_by_max = ABS(diff_by_max); + + if (diff_by_min < diff_by_max) { + cal_result = min; + current_val = pmif_get_ulposc_freq_mhz(min); + } else { + cal_result = max; + current_val = pmif_get_ulposc_freq_mhz(max); + } + + /* check if calibrated value is in the range of target value +- 15% */ + if (current_val < (FREQ_260MHZ * (1000 - CAL_TOL_RATE) / 1000) || + current_val > (FREQ_260MHZ * (1000 + CAL_TOL_RATE) / 1000)) { + printk(BIOS_ERR, "[%s] calibration fail: %dM\n", __func__, current_val); + ret = 1; + } + + return ret; +} + +static int pmif_init_ulposc(void) +{ + /* calibrate ULPOSC1 */ + pmif_ulposc_config(); + + /* enable spm swinf */ + if (!READ32_BITFIELD(&mtk_spm->poweron_config_en, BCLK_CG_EN)) + SET32_BITFIELDS(&mtk_spm->poweron_config_en, BCLK_CG_EN, 1, + PROJECT_CODE, 0xb16); + + /* turn on ulposc */ + SET32_BITFIELDS(&mtk_spm->ulposc_con, ULPOSC_EN, 1); + udelay(100); + SET32_BITFIELDS(&mtk_spm->ulposc_con, ULPOSC_CG_EN, 1); + + return pmif_ulposc_cali(); +} + +int pmif_clk_init(void) +{ + if (pmif_init_ulposc()) + return E_NODEV; + + /* turn off pmic_cg_tmr, cg_ap, cg_md, cg_conn clock */ + SET32_BITFIELDS(&mt8192_infracfg->module_sw_cg_0_set, PMIC_CG_TMR, 1, PMIC_CG_AP, 1, + PMIC_CG_MD, 1, PMIC_CG_CONN, 1); + + SET32_BITFIELDS(&mtk_topckgen->clk_cfg_8, PDN_PWRAP_ULPOSC, 0, CLK_PWRAP_ULPOSC_INV, + 0, CLK_PWRAP_ULPOSC_SET, 0); + SET32_BITFIELDS(&mtk_topckgen->clk_cfg_update1, CLK_CFG_UPDATE1, 1); + + /* use ULPOSC1 clock */ + SET32_BITFIELDS(&mt8192_infracfg->pmicw_clock_ctrl_clr, PMIC_SYSCK_26M_SEL, 0xf); + + /* toggle SPI/SPMI sw reset */ + SET32_BITFIELDS(&mt8192_infracfg->infra_globalcon_rst2_set, PMICSPMI_SWRST, 1, + PMIC_WRAP_SWRST, 1); + SET32_BITFIELDS(&mt8192_infracfg->infra_globalcon_rst2_clr, PMICSPMI_SWRST, 1, + PMIC_WRAP_SWRST, 1); + + /* turn on pmic_cg_tmr, cg_ap, cg_md, cg_conn clock */ + SET32_BITFIELDS(&mt8192_infracfg->module_sw_cg_0_clr, PMIC_CG_TMR, 1, PMIC_CG_AP, 1, + PMIC_CG_MD, 1, PMIC_CG_CONN, 1); + + return 0; +} -- cgit v1.2.3