mediatek/mt8183: Fix RTC initialization flow

1. Fix RTC lpd settings. Rewrite powerkeys after lpd init
   to enable low power detect function.
2. Rearrange RTC initialization flow.
3. Add return status for rtc_init.
4. Add log if calling pwrap_write or pwrap_read fail.
5. Increase timeout time to resolve unexpected timeout.

BUG=b:127405695
BRANCH=none
TEST=Boots correctly on Kukui

Change-Id: I6f26edd6699c2f6d9af80c285b70742b44407136
Signed-off-by: Ran Bi <ran.bi@mediatek.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/31968
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
Ran Bi 2019-03-19 11:47:21 +08:00 committed by Patrick Georgi
parent 274613303e
commit b197808852
6 changed files with 296 additions and 162 deletions

View File

@ -22,6 +22,11 @@
#include <delay.h> #include <delay.h>
#include <rtc.h> #include <rtc.h>
#include <timer.h> #include <timer.h>
#include <soc/pmic_wrap_common.h>
#define RTCTAG "[RTC]"
#define rtc_info(fmt, arg ...) printk(BIOS_INFO, RTCTAG "%s,%d: " fmt, \
__func__, __LINE__, ## arg)
/* /*
* Default values for RTC initialization * Default values for RTC initialization
@ -93,13 +98,46 @@ enum {
RTC_STATE_INIT = 2 RTC_STATE_INIT = 2
}; };
/* RTC error code */
enum {
RTC_STATUS_OK = 0,
RTC_STATUS_POWERKEY_INIT_FAIL,
RTC_STATUS_WRITEIF_UNLOCK_FAIL,
RTC_STATUS_OSC_SETTING_FAIL,
RTC_STATUS_GPIO_INIT_FAIL,
RTC_STATUS_HW_INIT_FAIL,
RTC_STATUS_REG_INIT_FAIL,
RTC_STATUS_LPD_INIT_FAIL
};
/* external API */ /* external API */
int rtc_busy_wait(void); int rtc_busy_wait(void);
int rtc_write_trigger(void); int rtc_write_trigger(void);
int rtc_writeif_unlock(void); int rtc_writeif_unlock(void);
void rtc_xosc_write(u16 val); int rtc_xosc_write(u16 val);
int rtc_reg_init(void); int rtc_reg_init(void);
u8 rtc_check_state(void);
void rtc_boot_common(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 */ #endif /* SOC_MEDIATEK_RTC_COMMON_H */

View File

@ -26,10 +26,10 @@ int rtc_busy_wait(void)
stopwatch_init_usecs_expire(&sw, RTC_CBUSY_TIMEOUT_US); stopwatch_init_usecs_expire(&sw, RTC_CBUSY_TIMEOUT_US);
do { do {
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
/* Time > 1sec, time out and set recovery mode enable.*/ /* Time > 1sec, time out and set recovery mode enable.*/
if (stopwatch_expired(&sw)) { if (stopwatch_expired(&sw)) {
printk(BIOS_INFO, "[RTC] BBPU CBUSY time out !!\n"); rtc_info("BBPU CBUSY time out !!\n");
return 0; return 0;
} }
} while (bbpu & RTC_BBPU_CBUSY); } while (bbpu & RTC_BBPU_CBUSY);
@ -39,17 +39,17 @@ int rtc_busy_wait(void)
int rtc_write_trigger(void) int rtc_write_trigger(void)
{ {
pwrap_write(RTC_WRTGR, 1); rtc_write(RTC_WRTGR, 1);
return rtc_busy_wait(); return rtc_busy_wait();
} }
/* unlock rtc write interface */ /* unlock rtc write interface */
int rtc_writeif_unlock(void) int rtc_writeif_unlock(void)
{ {
pwrap_write(RTC_PROT, RTC_PROT_UNLOCK1); rtc_write(RTC_PROT, RTC_PROT_UNLOCK1);
if (!rtc_write_trigger()) if (!rtc_write_trigger())
return 0; return 0;
pwrap_write(RTC_PROT, RTC_PROT_UNLOCK2); rtc_write(RTC_PROT, RTC_PROT_UNLOCK2);
if (!rtc_write_trigger()) if (!rtc_write_trigger())
return 0; return 0;
@ -67,39 +67,40 @@ int rtc_get(struct rtc_time *time)
{ {
u16 value; u16 value;
pwrap_read(RTC_TC_SEC, &value); rtc_read(RTC_TC_SEC, &value);
time->sec = value; time->sec = value;
pwrap_read(RTC_TC_MIN, &value); rtc_read(RTC_TC_MIN, &value);
time->min = value; time->min = value;
pwrap_read(RTC_TC_HOU, &value); rtc_read(RTC_TC_HOU, &value);
time->hour = value; time->hour = value;
pwrap_read(RTC_TC_DOM, &value); rtc_read(RTC_TC_DOM, &value);
time->mday = value; time->mday = value;
pwrap_read(RTC_TC_MTH, &value); rtc_read(RTC_TC_MTH, &value);
time->mon = value; time->mon = value;
pwrap_read(RTC_TC_YEA, &value); rtc_read(RTC_TC_YEA, &value);
time->year = (value + RTC_MIN_YEAR_OFFSET) % 100; time->year = (value + RTC_MIN_YEAR_OFFSET) % 100;
return 0; return 0;
} }
/* set rtc xosc setting */ /* set rtc xosc setting */
void rtc_xosc_write(u16 val) int rtc_xosc_write(u16 val)
{ {
u16 bbpu; u16 bbpu;
pwrap_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1); rtc_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1);
udelay(200); udelay(200);
pwrap_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2); rtc_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2);
udelay(200); udelay(200);
pwrap_write(RTC_OSC32CON, val); rtc_write(RTC_OSC32CON, val);
udelay(200); udelay(200);
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
bbpu |= RTC_BBPU_KEY | RTC_BBPU_RELOAD; bbpu |= RTC_BBPU_KEY | RTC_BBPU_RELOAD;
pwrap_write(RTC_BBPU, bbpu); rtc_write(RTC_BBPU, bbpu);
rtc_write_trigger();
return rtc_write_trigger();
} }
/* initialize rtc related registers */ /* initialize rtc related registers */
@ -107,45 +108,47 @@ int rtc_reg_init(void)
{ {
u16 irqsta; u16 irqsta;
pwrap_write(RTC_IRQ_EN, 0); rtc_write(RTC_IRQ_EN, 0);
pwrap_write(RTC_CII_EN, 0); rtc_write(RTC_CII_EN, 0);
pwrap_write(RTC_AL_MASK, 0); rtc_write(RTC_AL_MASK, 0);
pwrap_write(RTC_AL_YEA, 1970 - RTC_MIN_YEAR); rtc_write(RTC_AL_YEA, 1970 - RTC_MIN_YEAR);
pwrap_write(RTC_AL_MTH, 1); rtc_write(RTC_AL_MTH, 1);
pwrap_write(RTC_AL_DOM, 1); rtc_write(RTC_AL_DOM, 1);
pwrap_write(RTC_AL_DOW, 4); rtc_write(RTC_AL_DOW, 4);
pwrap_write(RTC_AL_HOU, 0); rtc_write(RTC_AL_HOU, 0);
pwrap_write(RTC_AL_MIN, 0); rtc_write(RTC_AL_MIN, 0);
pwrap_write(RTC_AL_SEC, 0); rtc_write(RTC_AL_SEC, 0);
pwrap_write(RTC_DIFF, 0); rtc_write(RTC_DIFF, 0);
pwrap_write(RTC_CALI, 0); rtc_write(RTC_CALI, 0);
if (!rtc_write_trigger()) if (!rtc_write_trigger())
return 0; return 0;
pwrap_read(RTC_IRQ_STA, &irqsta); /* read clear */ rtc_read(RTC_IRQ_STA, &irqsta); /* read clear */
/* init time counters after resetting RTC_DIFF and RTC_CALI */ /* init time counters after resetting RTC_DIFF and RTC_CALI */
pwrap_write(RTC_TC_YEA, RTC_DEFAULT_YEA - RTC_MIN_YEAR); rtc_write(RTC_TC_YEA, RTC_DEFAULT_YEA - RTC_MIN_YEAR);
pwrap_write(RTC_TC_MTH, RTC_DEFAULT_MTH); rtc_write(RTC_TC_MTH, RTC_DEFAULT_MTH);
pwrap_write(RTC_TC_DOM, RTC_DEFAULT_DOM); rtc_write(RTC_TC_DOM, RTC_DEFAULT_DOM);
pwrap_write(RTC_TC_DOW, RTC_DEFAULT_DOW); rtc_write(RTC_TC_DOW, RTC_DEFAULT_DOW);
pwrap_write(RTC_TC_HOU, 0); rtc_write(RTC_TC_HOU, 0);
pwrap_write(RTC_TC_MIN, 0); rtc_write(RTC_TC_MIN, 0);
pwrap_write(RTC_TC_SEC, 0); rtc_write(RTC_TC_SEC, 0);
return rtc_write_trigger(); return rtc_write_trigger();
} }
u8 rtc_check_state(void) static u8 rtc_check_state(void)
{ {
u16 con; u16 con;
u16 pwrky1; u16 pwrky1;
u16 pwrky2; u16 pwrky2;
pwrap_read(RTC_CON, &con); rtc_read(RTC_CON, &con);
pwrap_read(RTC_POWERKEY1, &pwrky1); rtc_read(RTC_POWERKEY1, &pwrky1);
pwrap_read(RTC_POWERKEY2, &pwrky2); rtc_read(RTC_POWERKEY2, &pwrky2);
rtc_info("con=%x, pwrkey1=%x, pwrkey2=%x\n", con, pwrky1, pwrky2);
if (con & RTC_CON_LPSTA_RAW) if (con & RTC_CON_LPSTA_RAW)
return RTC_STATE_INIT; return RTC_STATE_INIT;
@ -180,15 +183,14 @@ void rtc_boot_common(void)
break; break;
case RTC_STATE_INIT: case RTC_STATE_INIT:
default: default:
if (!rtc_init(0)) if (rtc_init(0))
rtc_init(1); rtc_init(1);
break; break;
} }
pwrap_read(RTC_IRQ_STA, &irqsta); /* Read clear */ rtc_read(RTC_IRQ_STA, &irqsta); /* Read clear */
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
pwrap_read(RTC_CON, &con); rtc_read(RTC_CON, &con);
printk(BIOS_INFO, "[RTC] irqsta = %x", irqsta); rtc_info("irqsta=%x, bbpu=%x, con=%x\n", irqsta, bbpu, con);
printk(BIOS_INFO, " bbpu = %#x, con = %#x\n", bbpu, con);
} }

View File

@ -78,7 +78,7 @@ enum {
RTC_BBPU_RELOAD = 1U << 5, RTC_BBPU_RELOAD = 1U << 5,
RTC_BBPU_CBUSY = 1U << 6, RTC_BBPU_CBUSY = 1U << 6,
RTC_CBUSY_TIMEOUT_US = 800 RTC_CBUSY_TIMEOUT_US = 8000
}; };
enum { enum {

View File

@ -30,11 +30,11 @@ static int rtc_gpio_init(void)
MT6391_GPIO_PULL_DOWN); /* RTC_32K1V8 */ MT6391_GPIO_PULL_DOWN); /* RTC_32K1V8 */
/* Export 32K clock RTC_32K2V8 */ /* Export 32K clock RTC_32K2V8 */
pwrap_read(RTC_CON, &con); rtc_read(RTC_CON, &con);
con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_LPEN); con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_LPEN);
con |= (RTC_CON_GPEN | RTC_CON_GOE); con |= (RTC_CON_GPEN | RTC_CON_GOE);
con &= ~(RTC_CON_F32KOB); con &= ~(RTC_CON_F32KOB);
pwrap_write(RTC_CON, con); rtc_write(RTC_CON, con);
return rtc_write_trigger(); return rtc_write_trigger();
} }
@ -46,8 +46,8 @@ void rtc_osc_init(void)
/* enable 32K export */ /* enable 32K export */
rtc_gpio_init(); rtc_gpio_init();
pwrap_write(PMIC_RG_TOP_CKTST2, 0x0); rtc_write(PMIC_RG_TOP_CKTST2, 0x0);
pwrap_read(RTC_OSC32CON, &con); rtc_read(RTC_OSC32CON, &con);
if ((con & 0x1f) != 0x0) /* check XOSCCALI */ if ((con & 0x1f) != 0x0) /* check XOSCCALI */
rtc_xosc_write(0x3); rtc_xosc_write(0x3);
} }
@ -73,40 +73,62 @@ static int rtc_lpd_init(void)
/* rtc init check */ /* rtc init check */
int rtc_init(u8 recover) int rtc_init(u8 recover)
{ {
printk(BIOS_INFO, "[RTC] %s recovery: %d\n", __func__, recover); int ret;
if (!rtc_writeif_unlock()) rtc_info("recovery: %d\n", recover);
return 0;
if (!rtc_gpio_init()) if (!rtc_writeif_unlock()) {
return 0; ret = -RTC_STATUS_WRITEIF_UNLOCK_FAIL;
goto err;
}
if (!rtc_gpio_init()) {
ret = -RTC_STATUS_GPIO_INIT_FAIL;
goto err;
}
/* Use SW to detect 32K mode instead of HW */ /* Use SW to detect 32K mode instead of HW */
if (recover) if (recover)
pwrap_write_field(PMIC_RG_CHRSTATUS, 0x4, 0x1, 9); pwrap_write_field(PMIC_RG_CHRSTATUS, 0x4, 0x1, 9);
rtc_xosc_write(0x3); if (!rtc_xosc_write(0x3)) {
ret = -RTC_STATUS_OSC_SETTING_FAIL;
goto err;
}
if (recover) if (recover)
mdelay(1000); mdelay(1000);
/* write powerkeys */ /* write powerkeys */
pwrap_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY); rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
pwrap_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY); rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
if (!rtc_write_trigger()) if (!rtc_write_trigger()) {
return 0; ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
goto err;
}
if (recover) if (recover)
pwrap_write_field(PMIC_RG_CHRSTATUS, 0, 0x4, 9); pwrap_write_field(PMIC_RG_CHRSTATUS, 0, 0x4, 9);
rtc_xosc_write(0); if (!rtc_xosc_write(0)) {
ret = -RTC_STATUS_OSC_SETTING_FAIL;
goto err;
}
if (!rtc_reg_init()) if (!rtc_reg_init()) {
return 0; ret = -RTC_STATUS_REG_INIT_FAIL;
if (!rtc_lpd_init()) goto err;
return 0; }
return 1; if (!rtc_lpd_init()) {
ret = -RTC_STATUS_LPD_INIT_FAIL;
goto err;
}
return RTC_STATUS_OK;
err:
rtc_info("init fail: ret=%d\n", ret);
return ret;
} }
/* enable rtc bbpu */ /* enable rtc bbpu */
@ -117,9 +139,9 @@ static void rtc_bbpu_power_on(void)
/* pull PWRBB high */ /* pull PWRBB high */
bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_BBPU | RTC_BBPU_PWREN; bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_BBPU | RTC_BBPU_PWREN;
pwrap_write(RTC_BBPU, bbpu); rtc_write(RTC_BBPU, bbpu);
ret = rtc_write_trigger(); ret = rtc_write_trigger();
printk(BIOS_INFO, "[RTC] %s rtc_write_trigger=%d\n", __func__, ret); rtc_info("rtc_write_trigger=%d\n", ret);
/* enable DCXO to transform external 32KHz clock to 26MHz clock /* enable DCXO to transform external 32KHz clock to 26MHz clock
directly sent to SoC */ directly sent to SoC */
@ -129,8 +151,8 @@ static void rtc_bbpu_power_on(void)
pwrap_write_field(PMIC_RG_DCXO_CON2, pwrap_write_field(PMIC_RG_DCXO_CON2,
BIT(1) | BIT(3) | BIT(5) | BIT(6), 0, 0); BIT(1) | BIT(3) | BIT(5) | BIT(6), 0, 0);
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
printk(BIOS_INFO, "[RTC] %s done BBPU=%#x\n", __func__, bbpu); rtc_info("done BBPU=%#x\n", bbpu);
/* detect hw clock done,close RG_RTC_75K_PDN for low power setting. */ /* detect hw clock done,close RG_RTC_75K_PDN for low power setting. */
pwrap_write_field(PMIC_RG_TOP_CKPDN2, 0x1, 0, 14); pwrap_write_field(PMIC_RG_TOP_CKPDN2, 0x1, 0, 14);
@ -139,8 +161,8 @@ static void rtc_bbpu_power_on(void)
/* the rtc boot flow entry */ /* the rtc boot flow entry */
void rtc_boot(void) void rtc_boot(void)
{ {
pwrap_write(PMIC_RG_TOP_CKPDN, 0); rtc_write(PMIC_RG_TOP_CKPDN, 0);
pwrap_write(PMIC_RG_TOP_CKPDN2, 0); rtc_write(PMIC_RG_TOP_CKPDN2, 0);
rtc_boot_common(); rtc_boot_common();
rtc_bbpu_power_on(); rtc_bbpu_power_on();

View File

@ -77,7 +77,7 @@ enum {
RTC_BBPU_RELOAD = 1U << 5, RTC_BBPU_RELOAD = 1U << 5,
RTC_BBPU_CBUSY = 1U << 6, RTC_BBPU_CBUSY = 1U << 6,
RTC_CBUSY_TIMEOUT_US = 800 RTC_CBUSY_TIMEOUT_US = 8000
}; };
enum { enum {
@ -106,6 +106,14 @@ enum {
RTC_REG_XOSC32_ENB = 1 << 15 RTC_REG_XOSC32_ENB = 1 << 15
}; };
enum {
RTC_LPD_OPT_XOSC_AND_EOSC_LPD = 0 << 13,
RTC_LPD_OPT_EOSC_LPD = 1 << 13,
RTC_LPD_OPT_XOSC_LPD = 2 << 13,
RTC_LPD_OPT_F32K_CK_ALIVE = 3 << 13,
RTC_LPD_OPT_MASK = 3 << 13
};
/* PMIC TOP Register Definition */ /* PMIC TOP Register Definition */
enum { enum {
PMIC_RG_SCK_TOP_CON0 = 0x050C PMIC_RG_SCK_TOP_CON0 = 0x050C

View File

@ -22,31 +22,37 @@
#define RTC_GPIO_USER_MASK ((1 << 13) - (1 << 8)) #define RTC_GPIO_USER_MASK ((1 << 13) - (1 << 8))
/* initialize rtc setting of using dcxo clock */ /* initialize rtc setting of using dcxo clock */
static void rtc_enable_dcxo(void) static int rtc_enable_dcxo(void)
{ {
u16 bbpu, con, osc32con, sec; u16 bbpu, con, osc32con, sec;
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
pwrap_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD); rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
rtc_write_trigger(); rtc_write_trigger();
mdelay(1); mdelay(1);
if (!rtc_writeif_unlock()) /* Unlock for reload */ if (!rtc_writeif_unlock()) { /* Unlock for reload */
printk(BIOS_INFO, rtc_info("rtc_writeif_unlock() fail\n");
"[RTC] %s rtc_writeif_unlock() fail\n", __func__); return 0;
}
pwrap_read(RTC_OSC32CON, &osc32con); rtc_read(RTC_OSC32CON, &osc32con);
rtc_xosc_write((osc32con & ~RTC_EMBCK_SRC_SEL) osc32con &= ~RTC_EMBCK_SRC_SEL;
| RTC_XOSC32_ENB | RTC_REG_XOSC32_ENB); osc32con |= RTC_XOSC32_ENB | RTC_REG_XOSC32_ENB;
pwrap_read(RTC_BBPU, &bbpu); if (!rtc_xosc_write(osc32con)) {
pwrap_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD); rtc_info("rtc_xosc_write() fail\n");
return 0;
}
rtc_read(RTC_BBPU, &bbpu);
rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
rtc_write_trigger(); rtc_write_trigger();
pwrap_read(RTC_CON, &con); rtc_read(RTC_CON, &con);
pwrap_read(RTC_OSC32CON, &osc32con); rtc_read(RTC_OSC32CON, &osc32con);
pwrap_read(RTC_AL_SEC, &sec); rtc_read(RTC_AL_SEC, &sec);
printk(BIOS_INFO, "[RTC] %s con = 0x%x, osc32con = 0x%x, sec = 0x%x\n", rtc_info("con=0x%x, osc32con=0x%x, sec=0x%x\n", con, osc32con, sec);
__func__, con, osc32con, sec);
return 1;
} }
/* initialize rtc related gpio */ /* initialize rtc related gpio */
@ -63,11 +69,13 @@ static int rtc_gpio_init(void)
pwrap_write_field(PMIC_RG_TOP_CKPDN_CON1_CLR, 0x1, 0x1, 1); pwrap_write_field(PMIC_RG_TOP_CKPDN_CON1_CLR, 0x1, 0x1, 1);
/* Export 32K clock RTC_32K2V8 */ /* Export 32K clock RTC_32K2V8 */
pwrap_read(RTC_CON, &con); rtc_read(RTC_CON, &con);
con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_EOSC32_LPEN); con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_EOSC32_LPEN
| RTC_CON_XOSC32_LPEN);
con |= (RTC_CON_GPEN | RTC_CON_GOE); con |= (RTC_CON_GPEN | RTC_CON_GOE);
con &= ~(RTC_CON_F32KOB); con &= ~(RTC_CON_F32KOB);
pwrap_write(RTC_CON, con); rtc_write(RTC_CON, con);
return rtc_write_trigger(); return rtc_write_trigger();
} }
@ -78,40 +86,60 @@ void rtc_osc_init(void)
rtc_gpio_init(); rtc_gpio_init();
} }
/* enable lpd subroutine */
static 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;
}
/* low power detect setting */ /* low power detect setting */
static int rtc_lpd_init(void) static int rtc_lpd_init(void)
{ {
u16 con; u16 con, sec;
con = pwrap_read(RTC_CON, &con) | RTC_CON_XOSC32_LPEN; /* set RTC_LPD_OPT */
con &= ~RTC_CON_LPRST; rtc_read(RTC_AL_SEC, &sec);
pwrap_write(RTC_CON, con); sec |= RTC_LPD_OPT_F32K_CK_ALIVE;
rtc_write(RTC_AL_SEC, sec);
if (!rtc_write_trigger()) if (!rtc_write_trigger())
return 0; return 0;
con |= RTC_CON_LPRST; /* init XOSC32 to detect 32k clock stop */
pwrap_write(RTC_CON, con); rtc_read(RTC_CON, &con);
if (!rtc_write_trigger()) con |= RTC_CON_XOSC32_LPEN;
if (!rtc_lpen(con))
return 0; return 0;
con &= ~RTC_CON_LPRST; /* init EOSC32 to detect rtc low power */
pwrap_write(RTC_CON, con); rtc_read(RTC_CON, &con);
if (!rtc_write_trigger()) con |= RTC_CON_EOSC32_LPEN;
if (!rtc_lpen(con))
return 0; return 0;
con = pwrap_read(RTC_CON, &con) | RTC_CON_EOSC32_LPEN; rtc_read(RTC_CON, &con);
con &= ~RTC_CON_LPRST; con &= ~RTC_CON_XOSC32_LPEN;
pwrap_write(RTC_CON, con); rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return 0;
con |= RTC_CON_LPRST; /* set RTC_LPD_OPT */
pwrap_write(RTC_CON, con); rtc_read(RTC_AL_SEC, &sec);
if (!rtc_write_trigger()) sec &= ~RTC_LPD_OPT_MASK;
return 0; sec |= RTC_LPD_OPT_EOSC_LPD;
rtc_write(RTC_AL_SEC, sec);
con &= ~RTC_CON_LPRST;
pwrap_write(RTC_CON, con);
if (!rtc_write_trigger()) if (!rtc_write_trigger())
return 0; return 0;
@ -122,56 +150,93 @@ static bool rtc_hw_init(void)
{ {
u16 bbpu; u16 bbpu;
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
pwrap_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_INIT); rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_INIT);
rtc_write_trigger(); rtc_write_trigger();
udelay(500); udelay(500);
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
pwrap_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD); rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
rtc_write_trigger(); rtc_write_trigger();
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
if (bbpu & RTC_BBPU_INIT) { if (bbpu & RTC_BBPU_INIT) {
printk(BIOS_INFO, "[RTC] %s:%d timeout\n", __func__, __LINE__); rtc_info("timeout\n");
return false; return false;
} }
return true; return true;
} }
/* write powerkeys to enable rtc functions */
static int rtc_powerkey_init(void)
{
rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
return rtc_write_trigger();
}
/* rtc init check */ /* rtc init check */
int rtc_init(u8 recover) int rtc_init(u8 recover)
{ {
printk(BIOS_INFO, "[RTC] %s recovery: %d\n", __func__, recover); int ret;
if (!rtc_writeif_unlock()) rtc_info("recovery: %d\n", recover);
return 0;
if (!rtc_gpio_init()) /* write powerkeys to enable rtc functions */
return 0; if (!rtc_powerkey_init()) {
ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
goto err;
}
/* write interface unlock need to be set after powerkey match */
if (!rtc_writeif_unlock()) {
ret = -RTC_STATUS_WRITEIF_UNLOCK_FAIL;
goto err;
}
/* using dcxo 32K clock */ /* using dcxo 32K clock */
rtc_enable_dcxo(); if (!rtc_enable_dcxo()) {
ret = -RTC_STATUS_OSC_SETTING_FAIL;
goto err;
}
if (recover) if (recover)
mdelay(20); mdelay(20);
/* write powerkeys */ if (!rtc_gpio_init()) {
pwrap_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY); ret = -RTC_STATUS_GPIO_INIT_FAIL;
pwrap_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY); goto err;
if (!rtc_write_trigger()) }
return 0;
if (!rtc_reg_init()) if (!rtc_hw_init()) {
return 0; ret = -RTC_STATUS_HW_INIT_FAIL;
if (!rtc_lpd_init()) goto err;
return 0; }
if (!rtc_hw_init())
return 0;
return 1; if (!rtc_reg_init()) {
ret = -RTC_STATUS_REG_INIT_FAIL;
goto err;
}
if (!rtc_lpd_init()) {
ret = -RTC_STATUS_LPD_INIT_FAIL;
goto err;
}
/* After lpd init, powerkeys need to be written again to enable
* low power detect function.
*/
if (!rtc_powerkey_init()) {
ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
goto err;
}
return RTC_STATUS_OK;
err:
rtc_info("init fail: ret=%d\n", ret);
return ret;
} }
/* enable rtc bbpu */ /* enable rtc bbpu */
@ -185,12 +250,12 @@ void rtc_bbpu_power_on(void)
/* pull PWRBB high */ /* pull PWRBB high */
bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_RELOAD | RTC_BBPU_PWREN; bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_RELOAD | RTC_BBPU_PWREN;
pwrap_write(RTC_BBPU, bbpu); rtc_write(RTC_BBPU, bbpu);
ret = rtc_write_trigger(); ret = rtc_write_trigger();
printk(BIOS_INFO, "[RTC] %s rtc_write_trigger=%d\n", __func__, ret); rtc_info("rtc_write_trigger=%d\n", ret);
pwrap_read(RTC_BBPU, &bbpu); rtc_read(RTC_BBPU, &bbpu);
printk(BIOS_INFO, "[RTC] %s done BBPU=%#x\n", __func__, bbpu); rtc_info("done BBPU=%#x\n", bbpu);
} }
void poweroff(void) void poweroff(void)
@ -198,11 +263,10 @@ void poweroff(void)
u16 bbpu; u16 bbpu;
if (!rtc_writeif_unlock()) if (!rtc_writeif_unlock())
printk(BIOS_INFO, rtc_info("rtc_writeif_unlock() fail\n");
"[RTC] %s rtc_writeif_unlock() fail\n", __func__);
/* pull PWRBB low */ /* pull PWRBB low */
bbpu = RTC_BBPU_KEY | RTC_BBPU_RELOAD | RTC_BBPU_PWREN; bbpu = RTC_BBPU_KEY | RTC_BBPU_RELOAD | RTC_BBPU_PWREN;
pwrap_write(RTC_BBPU, bbpu); rtc_write(RTC_BBPU, bbpu);
pmic_set_power_hold(false); pmic_set_power_hold(false);
halt(); halt();
@ -211,28 +275,28 @@ void poweroff(void)
static void dcxo_init(void) static void dcxo_init(void)
{ {
/* Buffer setting */ /* Buffer setting */
pwrap_write(PMIC_RG_DCXO_CW15, 0xA2AA); rtc_write(PMIC_RG_DCXO_CW15, 0xA2AA);
pwrap_write(PMIC_RG_DCXO_CW13, 0x98E9); rtc_write(PMIC_RG_DCXO_CW13, 0x98E9);
pwrap_write(PMIC_RG_DCXO_CW16, 0x9855); rtc_write(PMIC_RG_DCXO_CW16, 0x9855);
/* 26M enable control */ /* 26M enable control */
/* Enable clock buffer XO_SOC, XO_CEL */ /* Enable clock buffer XO_SOC, XO_CEL */
pwrap_write(PMIC_RG_DCXO_CW00, 0x4805); rtc_write(PMIC_RG_DCXO_CW00, 0x4805);
pwrap_write(PMIC_RG_DCXO_CW11, 0x8000); rtc_write(PMIC_RG_DCXO_CW11, 0x8000);
/* Load thermal coefficient */ /* Load thermal coefficient */
pwrap_write(PMIC_RG_TOP_TMA_KEY, 0x9CA7); rtc_write(PMIC_RG_TOP_TMA_KEY, 0x9CA7);
pwrap_write(PMIC_RG_DCXO_CW21, 0x12A7); rtc_write(PMIC_RG_DCXO_CW21, 0x12A7);
pwrap_write(PMIC_RG_DCXO_ELR0, 0xD004); rtc_write(PMIC_RG_DCXO_ELR0, 0xD004);
pwrap_write(PMIC_RG_TOP_TMA_KEY, 0x0000); rtc_write(PMIC_RG_TOP_TMA_KEY, 0x0000);
/* Adjust OSC FPM setting */ /* Adjust OSC FPM setting */
pwrap_write(PMIC_RG_DCXO_CW07, 0x8FFE); rtc_write(PMIC_RG_DCXO_CW07, 0x8FFE);
/* Re-Calibrate OSC current */ /* Re-Calibrate OSC current */
pwrap_write(PMIC_RG_DCXO_CW09, 0x008F); rtc_write(PMIC_RG_DCXO_CW09, 0x008F);
udelay(100); udelay(100);
pwrap_write(PMIC_RG_DCXO_CW09, 0x408F); rtc_write(PMIC_RG_DCXO_CW09, 0x408F);
mdelay(5); mdelay(5);
} }