blob: a930aacb87a54ae631422e4f2218b25697d6895f [file] [log] [blame]
Yuchen Huangb0ab41e2020-08-18 16:29:29 +08001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <delay.h>
4#include <halt.h>
Yuchen Huangec39cb32020-09-23 20:41:19 +08005#include <soc/clkbuf.h>
Yuchen Huangb0ab41e2020-08-18 16:29:29 +08006#include <soc/mt6359p.h>
7#include <soc/pmif.h>
8#include <soc/rtc.h>
9#include <soc/rtc_common.h>
10#include <timer.h>
11
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080012static struct pmif *pmif_arb = NULL;
13
14void rtc_read(u16 addr, u16 *rdata)
15{
16 u32 data;
17
Elyes Haouas0f1fb8a2022-09-13 09:57:30 +020018 if (!pmif_arb)
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080019 pmif_arb = get_pmif_controller(PMIF_SPI, 0);
20 pmif_arb->read(pmif_arb, 0, (u32)addr, &data);
21
22 *rdata = (u16)data;
23}
24
25void rtc_write(u16 addr, u16 wdata)
26{
Elyes Haouas0f1fb8a2022-09-13 09:57:30 +020027 if (!pmif_arb)
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080028 pmif_arb = get_pmif_controller(PMIF_SPI, 0);
29 pmif_arb->write(pmif_arb, 0, (unsigned int)addr, (unsigned int)wdata);
30}
31
32static void rtc_write_field(u16 reg, u16 val, u16 mask, u16 shift)
33{
34 u16 old, new;
35
36 rtc_read(reg, &old);
37 new = old & ~(mask << shift);
38 new |= (val << shift);
39 rtc_write(reg, new);
40}
41
42/* initialize rtc setting of using dcxo clock */
Yidi Lin54f8b9e2021-01-06 15:27:13 +080043static bool rtc_enable_dcxo(void)
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080044{
45 if (!rtc_writeif_unlock()) {
46 rtc_info("rtc_writeif_unlock() failed\n");
Yidi Lin54f8b9e2021-01-06 15:27:13 +080047 return false;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080048 }
49
50 u16 bbpu, con, osc32con, sec;
51 rtc_read(RTC_BBPU, &bbpu);
52 rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
53 rtc_write_trigger();
54 rtc_read(RTC_OSC32CON, &osc32con);
55 osc32con &= ~(RTC_EMBCK_SRC_SEL | RTC_EMBCK_SEL_MODE_MASK);
56 osc32con |= (OSC32CON_ANALOG_SETTING | RTC_REG_XOSC32_ENB);
57
58 if (!rtc_xosc_write(osc32con)) {
59 rtc_info("rtc_xosc_write() failed\n");
Yidi Lin54f8b9e2021-01-06 15:27:13 +080060 return false;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080061 }
62
63 rtc_read(RTC_CON, &con);
64 rtc_read(RTC_OSC32CON, &osc32con);
65 rtc_read(RTC_AL_SEC, &sec);
66 rtc_info("con=%#x, osc32con=%#x, sec=%#x\n", con, osc32con, sec);
Yidi Lin54f8b9e2021-01-06 15:27:13 +080067 return true;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080068}
69
70/* initialize rtc related gpio */
Yidi Lin54f8b9e2021-01-06 15:27:13 +080071bool rtc_gpio_init(void)
Yuchen Huangb0ab41e2020-08-18 16:29:29 +080072{
73 u16 con;
74
75 /* GPI mode and pull down */
76 rtc_read(RTC_CON, &con);
77 con &= (RTC_CON_LPSTA_RAW | RTC_CON_LPRST | RTC_CON_EOSC32_LPEN
78 | RTC_CON_XOSC32_LPEN);
79 con |= (RTC_CON_GPEN | RTC_CON_GOE);
80 con &= ~(RTC_CON_F32KOB);
81 con &= ~RTC_CON_GPU;
82 rtc_write(RTC_CON, con);
83
84 return rtc_write_trigger();
85}
86
87u16 rtc_get_frequency_meter(u16 val, u16 measure_src, u16 window_size)
88{
89 u16 bbpu, osc32con;
90 u16 fqmtr_busy, fqmtr_data, fqmtr_tcksel;
91 struct stopwatch sw;
92
93 if (val) {
94 rtc_read(RTC_BBPU, &bbpu);
95 rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
96 rtc_write_trigger();
97 rtc_read(RTC_OSC32CON, &osc32con);
98 rtc_xosc_write((osc32con & ~RTC_XOSCCALI_MASK) |
99 (val & RTC_XOSCCALI_MASK));
100 }
101
102 /* RG_BANK_FQMTR_RST=1, reset FQMTR*/
103 rtc_write_field(PMIC_RG_BANK_FQMTR_RST, 1, 1,
104 PMIC_RG_BANK_FQMTR_RST_SHIFT);
105 udelay(20);
106 /* RG_BANK_FQMTR_RST=0, release FQMTR*/
107 rtc_write_field(PMIC_RG_BANK_FQMTR_RST, 0, 1,
108 PMIC_RG_BANK_FQMTR_RST_SHIFT);
109
110 /* enable FQMTR clock */
111 rtc_write_field(PMIC_RG_TOP_CKPDN_CON0_CLR, 1, 1,
112 PMIC_RG_FQMTR_CK_PDN_SHIFT);
113 rtc_write_field(PMIC_RG_TOP_CKPDN_CON0_CLR, 1, 1,
114 PMIC_RG_FQMTR_32K_CK_PDN_SHIFT);
115
116
117 rtc_write_field(PMIC_RG_FQMTR_CON0, 1, 1,
118 PMIC_RG_FQMTR_DCXO26M_EN_SHIFT);
119
120 /* set frequency meter window value (0=1X32K(fixed clock)) */
121 rtc_write(PMIC_RG_FQMTR_WINSET, window_size);
122 /* enable 26M and set test clock source */
123 rtc_write(PMIC_RG_FQMTR_CON0, PMIC_FQMTR_CON0_DCXO26M_EN | measure_src);
124 /* enable 26M -> delay 100us -> enable FQMTR */
125 mdelay(1);
126 rtc_read(PMIC_RG_FQMTR_CON0, &fqmtr_tcksel);
127 /* enable FQMTR */
128 rtc_write(PMIC_RG_FQMTR_CON0, fqmtr_tcksel | PMIC_FQMTR_CON0_FQMTR_EN);
129 mdelay(1);
130 stopwatch_init_usecs_expire(&sw, FQMTR_TIMEOUT_US);
131 /* FQMTR read until ready */
132 do {
133 rtc_read(PMIC_RG_FQMTR_CON0, &fqmtr_busy);
134 if (stopwatch_expired(&sw)) {
135 rtc_info("get frequency time out!\n");
Yidi Lin54f8b9e2021-01-06 15:27:13 +0800136 return false;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800137 }
138 } while (fqmtr_busy & PMIC_FQMTR_CON0_BUSY);
139
140 /* read data should be closed to 26M/32k = 794 */
141 rtc_read(PMIC_RG_FQMTR_DATA, &fqmtr_data);
142
143 /* disable FQMTR */
144 rtc_read(PMIC_RG_FQMTR_CON0, &fqmtr_tcksel);
145 rtc_write(PMIC_RG_FQMTR_CON0, fqmtr_tcksel & ~PMIC_FQMTR_CON0_FQMTR_EN);
146 /* disable FQMTR -> delay 100us -> disable 26M */
147 mdelay(1);
148 /* disable 26M */
149 rtc_read(PMIC_RG_FQMTR_CON0, &fqmtr_tcksel);
150 rtc_write(PMIC_RG_FQMTR_CON0,
151 fqmtr_tcksel & ~PMIC_FQMTR_CON0_DCXO26M_EN);
152 rtc_info("input=%d, output=%d\n", val, fqmtr_data);
153
154 /* disable FQMTR clock */
155 rtc_write_field(PMIC_RG_TOP_CKPDN_CON0_SET, 1, 1,
156 PMIC_RG_FQMTR_CK_PDN_SHIFT);
157 rtc_write_field(PMIC_RG_TOP_CKPDN_CON0_SET, 1, 1,
158 PMIC_RG_FQMTR_32K_CK_PDN_SHIFT);
159
160 return fqmtr_data;
161}
162
163/* low power detect setting */
Yidi Lin54f8b9e2021-01-06 15:27:13 +0800164static bool rtc_lpd_init(void)
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800165{
166 u16 con, sec;
167
168 /* enable both XOSC & EOSC LPD */
169 rtc_read(RTC_AL_SEC, &sec);
170 sec &= ~RTC_LPD_OPT_F32K_CK_ALIVE;
171 rtc_write(RTC_AL_SEC, sec);
172
173 if (!rtc_write_trigger())
Yidi Lin54f8b9e2021-01-06 15:27:13 +0800174 return false;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800175
176 /* init XOSC32 to detect 32k clock stop */
177 rtc_read(RTC_CON, &con);
178 con |= RTC_CON_XOSC32_LPEN;
179
180 if (!rtc_lpen(con))
Yidi Lin54f8b9e2021-01-06 15:27:13 +0800181 return false;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800182
183 /* init EOSC32 to detect rtc low power */
184 rtc_read(RTC_CON, &con);
185 con |= RTC_CON_EOSC32_LPEN;
186
187 if (!rtc_lpen(con))
Yidi Lin54f8b9e2021-01-06 15:27:13 +0800188 return false;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800189
190 rtc_read(RTC_CON, &con);
191 rtc_info("check RTC_CON_LPSTA_RAW after LP init: %#x\n", con);
192
Yidi Lin54f8b9e2021-01-06 15:27:13 +0800193 return true;
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800194}
195
196static bool rtc_hw_init(void)
197{
198 u16 bbpu;
199
200 rtc_read(RTC_BBPU, &bbpu);
201 bbpu |= RTC_BBPU_KEY | RTC_BBPU_RESET_ALARM | RTC_BBPU_RESET_SPAR;
202 rtc_write(RTC_BBPU, bbpu & (~RTC_BBPU_SPAR_SW));
203 rtc_write_trigger();
204 udelay(500);
205
206 rtc_read(RTC_BBPU, &bbpu);
207 rtc_write(RTC_BBPU, bbpu | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
208 rtc_write_trigger();
209 rtc_read(RTC_BBPU, &bbpu);
210
211 if (bbpu & RTC_BBPU_RESET_ALARM || bbpu & RTC_BBPU_RESET_SPAR) {
212 rtc_info("timeout\n");
213 return false;
214 }
215 return true;
216}
217
218/* rtc init check */
219int rtc_init(int recover)
220{
221 int ret;
222 u16 year;
223
224 rtc_info("recovery: %d\n", recover);
225
226 /* write powerkeys to enable rtc functions */
227 if (!rtc_powerkey_init()) {
228 ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
229 goto err;
230 }
231
232 /* write interface unlock need to be set after powerkey match */
233 if (!rtc_writeif_unlock()) {
234 ret = -RTC_STATUS_WRITEIF_UNLOCK_FAIL;
235 goto err;
236 }
237
238 rtc_osc_init();
239
240 /* In recovery mode, we need 20ms delay for register setting. */
241 if (recover)
242 mdelay(20);
243
244 if (!rtc_gpio_init()) {
245 ret = -RTC_STATUS_GPIO_INIT_FAIL;
246 goto err;
247 }
248
249 if (!rtc_hw_init()) {
250 ret = -RTC_STATUS_HW_INIT_FAIL;
251 goto err;
252 }
253
254 if (!rtc_reg_init()) {
255 ret = -RTC_STATUS_REG_INIT_FAIL;
256 goto err;
257 }
258
259 /* solution1 for EOSC cali*/
260 rtc_read(RTC_AL_YEA, &year);
261 rtc_write(RTC_AL_YEA, (year | RTC_K_EOSC_RSV_0) & (~RTC_K_EOSC_RSV_1)
262 & (~RTC_K_EOSC_RSV_2));
263 rtc_write_trigger();
264
265 if (!rtc_lpd_init()) {
266 ret = -RTC_STATUS_LPD_INIT_FAIL;
267 goto err;
268 }
269
270 /*
271 * After lpd init, powerkeys need to be written again to enable
272 * low power detect function.
273 */
274 if (!rtc_powerkey_init()) {
275 ret = -RTC_STATUS_POWERKEY_INIT_FAIL;
276 goto err;
277 }
278 return RTC_STATUS_OK;
279
280err:
281 rtc_info("init failed: ret=%d\n", ret);
282 return ret;
283}
284
285/* enable rtc bbpu */
286void rtc_bbpu_power_on(void)
287{
288 u16 bbpu;
289 int ret;
290
291 /* pull powerhold high, control by pmic */
292 rtc_write_field(PMIC_PWRHOLD, 1, 0x1, 0);
293 bbpu = RTC_BBPU_KEY | RTC_BBPU_ENABLE_ALARM;
294 rtc_write(RTC_BBPU, bbpu);
295 ret = rtc_write_trigger();
296 rtc_info("rtc_write_trigger=%d\n", ret);
297 rtc_read(RTC_BBPU, &bbpu);
298 rtc_info("done BBPU=%#x\n", bbpu);
299}
300
301void poweroff(void)
302{
303 u16 bbpu;
304
305 if (!rtc_writeif_unlock())
306 rtc_info("rtc_writeif_unlock() failed\n");
307 /* pull PWRBB low */
308 bbpu = RTC_BBPU_KEY | RTC_BBPU_ENABLE_ALARM;
309 rtc_write(RTC_BBPU, bbpu);
310 rtc_write_field(PMIC_PWRHOLD, 0, 0x1, 0);
311 halt();
312}
313
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800314/* the rtc boot flow entry */
315void rtc_boot(void)
316{
317 u16 tmp;
318
Yuchen Huangb0ab41e2020-08-18 16:29:29 +0800319 /* dcxo 32k init settings */
320 rtc_write_field(PMIC_RG_DCXO_CW02, 0xF, 0xF, 0);
321 rtc_read(PMIC_RG_SCK_TOP_CON0, &tmp);
322 rtc_info("PMIC_RG_SCK_TOP_CON0,%#x:%#x\n", PMIC_RG_SCK_TOP_CON0, tmp);
323 rtc_write_field(PMIC_RG_SCK_TOP_CON0, 0x1, 0x1, 0);
324 rtc_read(PMIC_RG_SCK_TOP_CON0, &tmp);
325 rtc_info("PMIC_RG_SCK_TOP_CON0,%#x:%#x\n", PMIC_RG_SCK_TOP_CON0, tmp);
326 /* use dcxo 32K clock */
327 if (!rtc_enable_dcxo())
328 rtc_info("rtc_enable_dcxo() failed\n");
329 rtc_boot_common();
330 rtc_bbpu_power_on();
331}