diff options
Diffstat (limited to 'src/soc/mediatek/common')
-rw-r--r-- | src/soc/mediatek/common/include/soc/rtc_common.h | 26 | ||||
-rw-r--r-- | src/soc/mediatek/common/rtc.c | 40 | ||||
-rw-r--r-- | src/soc/mediatek/common/rtc_osc_init.c | 67 |
3 files changed, 107 insertions, 26 deletions
diff --git a/src/soc/mediatek/common/include/soc/rtc_common.h b/src/soc/mediatek/common/include/soc/rtc_common.h index 5159f376bf..7ddb8df0a9 100644 --- a/src/soc/mediatek/common/include/soc/rtc_common.h +++ b/src/soc/mediatek/common/include/soc/rtc_common.h @@ -6,7 +6,6 @@ #include <bcd.h> #include <console/console.h> #include <rtc.h> -#include <soc/pmic_wrap_common.h> #define RTCTAG "[RTC]" #define rtc_info(fmt, arg ...) printk(BIOS_INFO, RTCTAG "%s,%d: " fmt, \ @@ -99,29 +98,10 @@ int rtc_busy_wait(void); int rtc_write_trigger(void); int rtc_writeif_unlock(void); int rtc_xosc_write(u16 val); +int rtc_lpen(u16 con); int rtc_reg_init(void); +void rtc_osc_init(void); +int rtc_powerkey_init(void); void rtc_boot_common(void); -static inline s32 rtc_read(u16 addr, u16 *rdata) -{ - s32 ret; - - ret = pwrap_read(addr, rdata); - if (ret < 0) - rtc_info("pwrap_read fail: ret=%d\n", ret); - - return ret; -} - -static inline s32 rtc_write(u16 addr, u16 wdata) -{ - s32 ret; - - ret = pwrap_write(addr, wdata); - if (ret < 0) - rtc_info("pwrap_write fail: ret=%d\n", ret); - - return ret; -} - #endif /* SOC_MEDIATEK_RTC_COMMON_H */ diff --git a/src/soc/mediatek/common/rtc.c b/src/soc/mediatek/common/rtc.c index 0925f7f6f8..95bd13b892 100644 --- a/src/soc/mediatek/common/rtc.c +++ b/src/soc/mediatek/common/rtc.c @@ -2,7 +2,6 @@ #include <soc/rtc_common.h> #include <soc/rtc.h> -#include <soc/pmic_wrap.h> #include <timer.h> /* ensure rtc write success */ @@ -94,6 +93,30 @@ int rtc_xosc_write(u16 val) return rtc_write_trigger(); } +/* enable lpd subroutine */ +int rtc_lpen(u16 con) +{ + con &= ~RTC_CON_LPRST; + rtc_write(RTC_CON, con); + + if (!rtc_write_trigger()) + return 0; + + con |= RTC_CON_LPRST; + rtc_write(RTC_CON, con); + + if (!rtc_write_trigger()) + return 0; + + con &= ~RTC_CON_LPRST; + rtc_write(RTC_CON, con); + + if (!rtc_write_trigger()) + return 0; + + return 1; +} + /* initialize rtc related registers */ int rtc_reg_init(void) { @@ -129,6 +152,14 @@ int rtc_reg_init(void) return rtc_write_trigger(); } +/* write powerkeys to enable rtc functions */ +int rtc_powerkey_init(void) +{ + rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY); + rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY); + return rtc_write_trigger(); +} + static u8 rtc_check_state(void) { u16 con; @@ -164,18 +195,21 @@ void rtc_boot_common(void) switch (rtc_check_state()) { case RTC_STATE_REBOOT: - pwrap_write_field(RTC_BBPU, RTC_BBPU_KEY | RTC_BBPU_RELOAD, - 0xFFFF, 0); + rtc_read(RTC_BBPU, &bbpu); + rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD); rtc_write_trigger(); rtc_osc_init(); + rtc_info("RTC_STATE_REBOOT\n"); break; case RTC_STATE_RECOVER: rtc_init(1); + rtc_info("RTC_STATE_RECOVER\n"); break; case RTC_STATE_INIT: default: if (rtc_init(0)) rtc_init(1); + rtc_info("RTC_STATE_INIT\n"); break; } diff --git a/src/soc/mediatek/common/rtc_osc_init.c b/src/soc/mediatek/common/rtc_osc_init.c new file mode 100644 index 0000000000..521e7a0981 --- /dev/null +++ b/src/soc/mediatek/common/rtc_osc_init.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <soc/rtc.h> +#include <soc/rtc_common.h> + +/* 32k clock calibration */ +static int rtc_eosc_cali(void) +{ + u16 diff_left, diff_right, cksel; + u16 val = 0; + u16 middle; + u16 left = RTC_XOSCCALI_START; + u16 right = RTC_XOSCCALI_END; + + rtc_read(PMIC_RG_FQMTR_CKSEL, &cksel); + cksel &= ~PMIC_FQMTR_CKSEL_MASK; + /* select EOSC_32 as fixed clock */ + rtc_write(PMIC_RG_FQMTR_CKSEL, cksel | PMIC_FQMTR_FIX_CLK_EOSC_32K); + rtc_read(PMIC_RG_FQMTR_CKSEL, &cksel); + rtc_info("PMIC_RG_FQMTR_CKSEL=%#x\n", cksel); + + while (left <= right) { + middle = (right + left) / 2; + if (middle == left) + break; + + /* select 26M as target clock */ + val = rtc_get_frequency_meter(middle, PMIC_FQMTR_CON0_FQM26M_CK, 0); + if (val >= RTC_FQMTR_LOW_BASE && val <= RTC_FQMTR_HIGH_BASE) + break; + + if (val > RTC_FQMTR_HIGH_BASE) + right = middle; + else + left = middle; + } + + if (val >= RTC_FQMTR_LOW_BASE && val <= RTC_FQMTR_HIGH_BASE) + return middle; + + val = rtc_get_frequency_meter(left, PMIC_FQMTR_CON0_FQM26M_CK, 0); + diff_left = ABS(val - RTC_FQMTR_LOW_BASE); + + val = rtc_get_frequency_meter(right, PMIC_FQMTR_CON0_FQM26M_CK, 0); + diff_right = ABS(val - RTC_FQMTR_LOW_BASE); + + rtc_info("left: %d, middle: %d, right: %d\n", left, middle, right); + if (diff_left < diff_right) + return left; + else + return right; +} + +void rtc_osc_init(void) +{ + u16 osc32con; + + /* enable 32K export */ + rtc_gpio_init(); + /* calibrate eosc32 for powerdown clock */ + rtc_read(RTC_OSC32CON, &osc32con); + rtc_info("osc32con val = %#x\n", osc32con); + osc32con &= ~RTC_XOSCCALI_MASK; + osc32con |= rtc_eosc_cali() & RTC_XOSCCALI_MASK; + rtc_xosc_write(osc32con); + rtc_info("EOSC32 cali val = %#x\n", osc32con); +} |