1*9c9324ccSZhigang Qin /*
2*9c9324ccSZhigang Qin * Copyright (c) 2025, MediaTek Inc. All rights reserved.
3*9c9324ccSZhigang Qin *
4*9c9324ccSZhigang Qin * SPDX-License-Identifier: BSD-3-Clause
5*9c9324ccSZhigang Qin */
6*9c9324ccSZhigang Qin
7*9c9324ccSZhigang Qin #include <common/debug.h>
8*9c9324ccSZhigang Qin #include <drivers/delay_timer.h>
9*9c9324ccSZhigang Qin #include <lib/mmio.h>
10*9c9324ccSZhigang Qin #include <lib/spinlock.h>
11*9c9324ccSZhigang Qin
12*9c9324ccSZhigang Qin #include <mtk_mmap_pool.h>
13*9c9324ccSZhigang Qin #include "pmic_wrap_init.h"
14*9c9324ccSZhigang Qin #include "pmic_wrap_v3.h"
15*9c9324ccSZhigang Qin
16*9c9324ccSZhigang Qin static spinlock_t wrp_lock;
17*9c9324ccSZhigang Qin
pwrap_check_idle(uintptr_t wacs_register,uintptr_t wacs_vldclr_register,uint32_t timeout_us)18*9c9324ccSZhigang Qin static uint32_t pwrap_check_idle(uintptr_t wacs_register, uintptr_t wacs_vldclr_register,
19*9c9324ccSZhigang Qin uint32_t timeout_us)
20*9c9324ccSZhigang Qin {
21*9c9324ccSZhigang Qin uint32_t reg_rdata = 0U, retry;
22*9c9324ccSZhigang Qin
23*9c9324ccSZhigang Qin retry = (timeout_us + PWRAP_POLL_STEP_US) / PWRAP_POLL_STEP_US;
24*9c9324ccSZhigang Qin while (retry != 0) {
25*9c9324ccSZhigang Qin udelay(PWRAP_POLL_STEP_US);
26*9c9324ccSZhigang Qin reg_rdata = mmio_read_32(wacs_register);
27*9c9324ccSZhigang Qin /* if last read command timeout,clear vldclr bit
28*9c9324ccSZhigang Qin * read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
29*9c9324ccSZhigang Qin * write:FSM_REQ-->idle
30*9c9324ccSZhigang Qin */
31*9c9324ccSZhigang Qin switch (GET_WACS_FSM(reg_rdata)) {
32*9c9324ccSZhigang Qin case SWINF_FSM_WFVLDCLR:
33*9c9324ccSZhigang Qin mmio_write_32(wacs_vldclr_register, 0x1);
34*9c9324ccSZhigang Qin INFO("WACS_FSM = SWINF_FSM_WFVLDCLR\n");
35*9c9324ccSZhigang Qin break;
36*9c9324ccSZhigang Qin case SWINF_FSM_WFDLE:
37*9c9324ccSZhigang Qin INFO("WACS_FSM = SWINF_FSM_WFDLE\n");
38*9c9324ccSZhigang Qin break;
39*9c9324ccSZhigang Qin case SWINF_FSM_REQ:
40*9c9324ccSZhigang Qin INFO("WACS_FSM = SWINF_FSM_REQ\n");
41*9c9324ccSZhigang Qin break;
42*9c9324ccSZhigang Qin case SWINF_FSM_IDLE:
43*9c9324ccSZhigang Qin goto done;
44*9c9324ccSZhigang Qin default:
45*9c9324ccSZhigang Qin break;
46*9c9324ccSZhigang Qin }
47*9c9324ccSZhigang Qin retry--;
48*9c9324ccSZhigang Qin }
49*9c9324ccSZhigang Qin
50*9c9324ccSZhigang Qin done:
51*9c9324ccSZhigang Qin if (retry == 0) {
52*9c9324ccSZhigang Qin /* timeout */
53*9c9324ccSZhigang Qin return E_PWR_WAIT_IDLE_TIMEOUT;
54*9c9324ccSZhigang Qin }
55*9c9324ccSZhigang Qin
56*9c9324ccSZhigang Qin return 0U;
57*9c9324ccSZhigang Qin }
58*9c9324ccSZhigang Qin
pwrap_check_vldclr(uintptr_t wacs_register,uint32_t timeout_us)59*9c9324ccSZhigang Qin static uint32_t pwrap_check_vldclr(uintptr_t wacs_register, uint32_t timeout_us)
60*9c9324ccSZhigang Qin {
61*9c9324ccSZhigang Qin uint32_t reg_rdata = 0U, retry;
62*9c9324ccSZhigang Qin
63*9c9324ccSZhigang Qin retry = (timeout_us + PWRAP_POLL_STEP_US) / PWRAP_POLL_STEP_US;
64*9c9324ccSZhigang Qin while (retry != 0) {
65*9c9324ccSZhigang Qin udelay(PWRAP_POLL_STEP_US);
66*9c9324ccSZhigang Qin reg_rdata = mmio_read_32(wacs_register);
67*9c9324ccSZhigang Qin if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_WFVLDCLR) {
68*9c9324ccSZhigang Qin break;
69*9c9324ccSZhigang Qin }
70*9c9324ccSZhigang Qin retry--;
71*9c9324ccSZhigang Qin }
72*9c9324ccSZhigang Qin
73*9c9324ccSZhigang Qin if (retry == 0) {
74*9c9324ccSZhigang Qin /* timeout */
75*9c9324ccSZhigang Qin return E_PWR_WAIT_IDLE_TIMEOUT;
76*9c9324ccSZhigang Qin }
77*9c9324ccSZhigang Qin
78*9c9324ccSZhigang Qin return 0U;
79*9c9324ccSZhigang Qin }
80*9c9324ccSZhigang Qin
pwrap_swinf_acc(uint32_t swinf_no,uint32_t cmd,uint32_t write,uint32_t pmifid,uint32_t slvid,uint32_t addr,uint32_t bytecnt,uint32_t wdata,uint32_t * rdata)81*9c9324ccSZhigang Qin static int32_t pwrap_swinf_acc(uint32_t swinf_no, uint32_t cmd, uint32_t write,
82*9c9324ccSZhigang Qin uint32_t pmifid, uint32_t slvid, uint32_t addr,
83*9c9324ccSZhigang Qin uint32_t bytecnt, uint32_t wdata, uint32_t *rdata)
84*9c9324ccSZhigang Qin {
85*9c9324ccSZhigang Qin uint32_t reg_rdata = 0x0;
86*9c9324ccSZhigang Qin int32_t ret = 0x0;
87*9c9324ccSZhigang Qin
88*9c9324ccSZhigang Qin /* Check argument validation */
89*9c9324ccSZhigang Qin if ((swinf_no & ~(0x3)) != 0)
90*9c9324ccSZhigang Qin return -E_PWR_INVALID_SWINF;
91*9c9324ccSZhigang Qin if ((cmd & ~(0x3)) != 0)
92*9c9324ccSZhigang Qin return -E_PWR_INVALID_CMD;
93*9c9324ccSZhigang Qin if ((write & ~(0x1)) != 0)
94*9c9324ccSZhigang Qin return -E_PWR_INVALID_RW;
95*9c9324ccSZhigang Qin if ((pmifid & ~(0x1)) != 0)
96*9c9324ccSZhigang Qin return -E_PWR_INVALID_PMIFID;
97*9c9324ccSZhigang Qin if ((slvid & ~(0xf)) != 0)
98*9c9324ccSZhigang Qin return -E_PWR_INVALID_SLVID;
99*9c9324ccSZhigang Qin if ((addr & ~(0xffff)) != 0)
100*9c9324ccSZhigang Qin return -E_PWR_INVALID_ADDR;
101*9c9324ccSZhigang Qin if ((bytecnt & ~(0x1)) != 0)
102*9c9324ccSZhigang Qin return -E_PWR_INVALID_BYTECNT;
103*9c9324ccSZhigang Qin if ((wdata & ~(0xffff)) != 0)
104*9c9324ccSZhigang Qin return -E_PWR_INVALID_WDAT;
105*9c9324ccSZhigang Qin
106*9c9324ccSZhigang Qin spin_lock(&wrp_lock);
107*9c9324ccSZhigang Qin /* Check whether INIT_DONE is set */
108*9c9324ccSZhigang Qin if (pmifid == 0)
109*9c9324ccSZhigang Qin reg_rdata = mmio_read_32((uintptr_t)(&mtk_pwrap->wacs[swinf_no].sta));
110*9c9324ccSZhigang Qin
111*9c9324ccSZhigang Qin if (GET_SWINF_INIT_DONE(reg_rdata) != 0x1) {
112*9c9324ccSZhigang Qin ERROR("[PWRAP] init not finish\n");
113*9c9324ccSZhigang Qin ret = -E_PWR_NOT_INIT_DONE;
114*9c9324ccSZhigang Qin goto end;
115*9c9324ccSZhigang Qin }
116*9c9324ccSZhigang Qin
117*9c9324ccSZhigang Qin /* Wait for Software Interface FSM state to be IDLE */
118*9c9324ccSZhigang Qin ret = pwrap_check_idle((uintptr_t)(&mtk_pwrap->wacs[swinf_no].sta),
119*9c9324ccSZhigang Qin (uintptr_t)(&mtk_pwrap->wacs[swinf_no].vldclr), TIMEOUT_WAIT_IDLE);
120*9c9324ccSZhigang Qin if (ret != 0) {
121*9c9324ccSZhigang Qin ERROR("[PWRAP] fsm_idle fail\n");
122*9c9324ccSZhigang Qin goto end;
123*9c9324ccSZhigang Qin }
124*9c9324ccSZhigang Qin
125*9c9324ccSZhigang Qin /* Set the write data */
126*9c9324ccSZhigang Qin if (write == 1) {
127*9c9324ccSZhigang Qin if (pmifid == 0)
128*9c9324ccSZhigang Qin mmio_write_32((uintptr_t)(&mtk_pwrap->wacs[swinf_no].wdata), wdata);
129*9c9324ccSZhigang Qin }
130*9c9324ccSZhigang Qin
131*9c9324ccSZhigang Qin /* Send the command */
132*9c9324ccSZhigang Qin if (pmifid == 0)
133*9c9324ccSZhigang Qin mmio_write_32((uintptr_t)(&mtk_pwrap->wacs[swinf_no].cmd),
134*9c9324ccSZhigang Qin (cmd << 30) | (write << 29) | (slvid << 24) | (bytecnt << 16) | addr);
135*9c9324ccSZhigang Qin
136*9c9324ccSZhigang Qin if (write == 0) {
137*9c9324ccSZhigang Qin if (rdata == NULL) {
138*9c9324ccSZhigang Qin ERROR("[PWRAP] rdata null\n");
139*9c9324ccSZhigang Qin ret = -E_PWR_INVALID_ARG;
140*9c9324ccSZhigang Qin goto end;
141*9c9324ccSZhigang Qin }
142*9c9324ccSZhigang Qin
143*9c9324ccSZhigang Qin /* Wait for Software Interface FSM to be WFVLDCLR */
144*9c9324ccSZhigang Qin /* read the data and clear the valid flag */
145*9c9324ccSZhigang Qin ret = pwrap_check_vldclr((uintptr_t)(&mtk_pwrap->wacs[swinf_no].sta), TIMEOUT_READ);
146*9c9324ccSZhigang Qin if (ret != 0) {
147*9c9324ccSZhigang Qin ERROR("[PWRAP] fsm_vldclr fail\n");
148*9c9324ccSZhigang Qin goto end;
149*9c9324ccSZhigang Qin }
150*9c9324ccSZhigang Qin
151*9c9324ccSZhigang Qin if (pmifid == 0) {
152*9c9324ccSZhigang Qin *rdata = mmio_read_32((uintptr_t)(&mtk_pwrap->wacs[swinf_no].rdata));
153*9c9324ccSZhigang Qin mmio_write_32((uintptr_t)(&mtk_pwrap->wacs[swinf_no].vldclr), 0x1);
154*9c9324ccSZhigang Qin }
155*9c9324ccSZhigang Qin }
156*9c9324ccSZhigang Qin
157*9c9324ccSZhigang Qin end:
158*9c9324ccSZhigang Qin spin_unlock(&wrp_lock);
159*9c9324ccSZhigang Qin if (ret < 0)
160*9c9324ccSZhigang Qin ERROR("%s fail, ret=%d\n", __func__, ret);
161*9c9324ccSZhigang Qin return ret;
162*9c9324ccSZhigang Qin }
163*9c9324ccSZhigang Qin
164*9c9324ccSZhigang Qin /* external API for pmic_wrap user */
165*9c9324ccSZhigang Qin
pwrap_read(uint32_t adr,uint32_t * rdata)166*9c9324ccSZhigang Qin int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
167*9c9324ccSZhigang Qin {
168*9c9324ccSZhigang Qin return pwrap_swinf_acc(PMIF_SPI_SWINF_NO, DEFAULT_CMD, 0, PMIF_SPI_PMIFID,
169*9c9324ccSZhigang Qin DEFAULT_SLVID, adr, DEFAULT_BYTECNT, 0x0, rdata);
170*9c9324ccSZhigang Qin }
171*9c9324ccSZhigang Qin
pwrap_write(uint32_t adr,uint32_t wdata)172*9c9324ccSZhigang Qin int32_t pwrap_write(uint32_t adr, uint32_t wdata)
173*9c9324ccSZhigang Qin {
174*9c9324ccSZhigang Qin return pwrap_swinf_acc(PMIF_SPI_SWINF_NO, DEFAULT_CMD, 1, PMIF_SPI_PMIFID,
175*9c9324ccSZhigang Qin DEFAULT_SLVID, adr, DEFAULT_BYTECNT, wdata, 0x0);
176*9c9324ccSZhigang Qin }
177*9c9324ccSZhigang Qin
pwrap_read_field(uint32_t reg,uint32_t * val,uint32_t mask,uint32_t shift)178*9c9324ccSZhigang Qin int32_t pwrap_read_field(uint32_t reg, uint32_t *val, uint32_t mask, uint32_t shift)
179*9c9324ccSZhigang Qin {
180*9c9324ccSZhigang Qin uint32_t rdata;
181*9c9324ccSZhigang Qin int32_t ret;
182*9c9324ccSZhigang Qin
183*9c9324ccSZhigang Qin if (!val)
184*9c9324ccSZhigang Qin return -E_PWR_INVALID_ARG;
185*9c9324ccSZhigang Qin ret = pwrap_read(reg, &rdata);
186*9c9324ccSZhigang Qin if (ret == 0x0)
187*9c9324ccSZhigang Qin *val = (rdata >> shift) & mask;
188*9c9324ccSZhigang Qin
189*9c9324ccSZhigang Qin return ret;
190*9c9324ccSZhigang Qin }
191*9c9324ccSZhigang Qin
pwrap_write_field(uint32_t reg,uint32_t val,uint32_t mask,uint32_t shift)192*9c9324ccSZhigang Qin int32_t pwrap_write_field(uint32_t reg, uint32_t val, uint32_t mask, uint32_t shift)
193*9c9324ccSZhigang Qin {
194*9c9324ccSZhigang Qin uint32_t data;
195*9c9324ccSZhigang Qin int32_t ret;
196*9c9324ccSZhigang Qin
197*9c9324ccSZhigang Qin ret = pwrap_read(reg, &data);
198*9c9324ccSZhigang Qin if (ret != 0)
199*9c9324ccSZhigang Qin return ret;
200*9c9324ccSZhigang Qin
201*9c9324ccSZhigang Qin data = data & ~(mask << shift);
202*9c9324ccSZhigang Qin data |= (val << shift);
203*9c9324ccSZhigang Qin ret = pwrap_write(reg, data);
204*9c9324ccSZhigang Qin
205*9c9324ccSZhigang Qin return ret;
206*9c9324ccSZhigang Qin }
207*9c9324ccSZhigang Qin
208*9c9324ccSZhigang Qin #if PWRAP_DEBUG
pwrap_read_test(void)209*9c9324ccSZhigang Qin static int32_t pwrap_read_test(void)
210*9c9324ccSZhigang Qin {
211*9c9324ccSZhigang Qin uint32_t rdata = 0;
212*9c9324ccSZhigang Qin int32_t ret;
213*9c9324ccSZhigang Qin
214*9c9324ccSZhigang Qin ret = pwrap_read(DEW_READ_TEST, &rdata);
215*9c9324ccSZhigang Qin if (rdata != DEFAULT_VALUE_READ_TEST) {
216*9c9324ccSZhigang Qin ERROR("[PWRAP] Read fail,rdata=0x%x,exp=0x5aa5,ret=0x%x\n", rdata, ret);
217*9c9324ccSZhigang Qin return -E_PWR_READ_TEST_FAIL;
218*9c9324ccSZhigang Qin }
219*9c9324ccSZhigang Qin INFO("[PWRAP] Read Test pass,ret=%x\n", ret);
220*9c9324ccSZhigang Qin return 0;
221*9c9324ccSZhigang Qin }
222*9c9324ccSZhigang Qin
pwrap_write_test(void)223*9c9324ccSZhigang Qin static int32_t pwrap_write_test(void)
224*9c9324ccSZhigang Qin {
225*9c9324ccSZhigang Qin uint32_t rdata = 0;
226*9c9324ccSZhigang Qin int32_t ret;
227*9c9324ccSZhigang Qin int32_t ret1;
228*9c9324ccSZhigang Qin
229*9c9324ccSZhigang Qin ret = pwrap_write(DEW_WRITE_TEST, PWRAP_WRITE_TEST_VALUE);
230*9c9324ccSZhigang Qin ret1 = pwrap_read(DEW_WRITE_TEST, &rdata);
231*9c9324ccSZhigang Qin if ((rdata != PWRAP_WRITE_TEST_VALUE) || (ret != 0) || (ret1 != 0)) {
232*9c9324ccSZhigang Qin ERROR("[PWRAP] Write fail,rdata=0x%x,exp=0xa55a,ret=0x%x,ret1=0x%x\n",
233*9c9324ccSZhigang Qin rdata, ret, ret1);
234*9c9324ccSZhigang Qin return -E_PWR_WRITE_TEST_FAIL;
235*9c9324ccSZhigang Qin }
236*9c9324ccSZhigang Qin INFO("[PWRAP] Write Test pass\n");
237*9c9324ccSZhigang Qin return 0;
238*9c9324ccSZhigang Qin }
239*9c9324ccSZhigang Qin
pmic_wrap_test(void)240*9c9324ccSZhigang Qin int32_t pmic_wrap_test(void)
241*9c9324ccSZhigang Qin {
242*9c9324ccSZhigang Qin int32_t ret;
243*9c9324ccSZhigang Qin
244*9c9324ccSZhigang Qin INFO("[PWRAP] Read/Write Test start\n");
245*9c9324ccSZhigang Qin
246*9c9324ccSZhigang Qin ret = pwrap_read_test();
247*9c9324ccSZhigang Qin if (ret != 0) {
248*9c9324ccSZhigang Qin return ret;
249*9c9324ccSZhigang Qin }
250*9c9324ccSZhigang Qin
251*9c9324ccSZhigang Qin ret = pwrap_write_test();
252*9c9324ccSZhigang Qin if (ret != 0) {
253*9c9324ccSZhigang Qin return ret;
254*9c9324ccSZhigang Qin }
255*9c9324ccSZhigang Qin INFO("[PWRAP] Read/Write Test done\n");
256*9c9324ccSZhigang Qin
257*9c9324ccSZhigang Qin return 0;
258*9c9324ccSZhigang Qin }
259*9c9324ccSZhigang Qin #endif
260