xref: /rk3399_ARM-atf/plat/mediatek/drivers/pmic_wrap/pmic_wrap_init_v3.c (revision 52c47c174fadb9e1398af41e9bbf290af314e8ec)
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