1 /*
2  * Copyright (c) 2019, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <common/debug.h>
8 #include <drivers/delay_timer.h>
9 #include <lib/mmio.h>
10 #include <platform_def.h>
11 #include <pmic_wrap_init.h>
12 
13 /* pmic wrap module wait_idle and read polling interval (in microseconds) */
14 enum {
15 	WAIT_IDLE_POLLING_DELAY_US	= 1,
16 	READ_POLLING_DELAY_US		= 2
17 };
18 
wait_for_state_idle(uint32_t timeout_us,void * wacs_register,void * wacs_vldclr_register,uint32_t * read_reg)19 static inline uint32_t wait_for_state_idle(uint32_t timeout_us,
20 					   void *wacs_register,
21 					   void *wacs_vldclr_register,
22 					   uint32_t *read_reg)
23 {
24 	uint32_t reg_rdata;
25 	uint32_t retry;
26 
27 	retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
28 		WAIT_IDLE_POLLING_DELAY_US;
29 
30 	do {
31 		udelay(WAIT_IDLE_POLLING_DELAY_US);
32 		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
33 		/* if last read command timeout,clear vldclr bit
34 		 * read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
35 		 * write:FSM_REQ-->idle
36 		 */
37 		switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) &
38 			RDATA_WACS_FSM_MASK)) {
39 		case WACS_FSM_WFVLDCLR:
40 			mmio_write_32((uintptr_t)wacs_vldclr_register, 1);
41 			ERROR("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n");
42 			break;
43 		case WACS_FSM_WFDLE:
44 			ERROR("WACS_FSM = WACS_FSM_WFDLE\n");
45 			break;
46 		case WACS_FSM_REQ:
47 			ERROR("WACS_FSM = WACS_FSM_REQ\n");
48 			break;
49 		case WACS_FSM_IDLE:
50 			goto done;
51 		default:
52 			break;
53 		}
54 
55 		retry--;
56 	} while (retry);
57 
58 done:
59 	if (!retry)	/* timeout */
60 		return E_PWR_WAIT_IDLE_TIMEOUT;
61 
62 	if (read_reg)
63 		*read_reg = reg_rdata;
64 	return 0;
65 }
66 
wait_for_state_ready(uint32_t timeout_us,void * wacs_register,uint32_t * read_reg)67 static inline uint32_t wait_for_state_ready(uint32_t timeout_us,
68 					    void *wacs_register,
69 					    uint32_t *read_reg)
70 {
71 	uint32_t reg_rdata;
72 	uint32_t retry;
73 
74 	retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
75 
76 	do {
77 		udelay(READ_POLLING_DELAY_US);
78 		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
79 
80 		if (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK)
81 		    == WACS_FSM_WFVLDCLR)
82 			break;
83 
84 		retry--;
85 	} while (retry);
86 
87 	if (!retry) {	/* timeout */
88 		ERROR("timeout when waiting for idle\n");
89 		return E_PWR_WAIT_IDLE_TIMEOUT_READ;
90 	}
91 
92 	if (read_reg)
93 		*read_reg = reg_rdata;
94 	return 0;
95 }
96 
pwrap_wacs2(uint32_t write,uint32_t adr,uint32_t wdata,uint32_t * rdata,uint32_t init_check)97 static int32_t pwrap_wacs2(uint32_t write,
98 		    uint32_t adr,
99 		    uint32_t wdata,
100 		    uint32_t *rdata,
101 		    uint32_t init_check)
102 {
103 	uint32_t reg_rdata = 0;
104 	uint32_t wacs_write = 0;
105 	uint32_t wacs_adr = 0;
106 	uint32_t wacs_cmd = 0;
107 	uint32_t return_value = 0;
108 
109 	if (init_check) {
110 		reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
111 		/* Prevent someone to used pwrap before pwrap init */
112 		if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
113 		    RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
114 			ERROR("initialization isn't finished\n");
115 			return E_PWR_NOT_INIT_DONE;
116 		}
117 	}
118 	reg_rdata = 0;
119 	/* Check IDLE in advance */
120 	return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE,
121 				&mtk_pwrap->wacs2_rdata,
122 				&mtk_pwrap->wacs2_vldclr,
123 				0);
124 	if (return_value != 0) {
125 		ERROR("wait_for_fsm_idle fail,return_value=%d\n", return_value);
126 		goto FAIL;
127 	}
128 	wacs_write = write << 31;
129 	wacs_adr = (adr >> 1) << 16;
130 	wacs_cmd = wacs_write | wacs_adr | wdata;
131 
132 	mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, wacs_cmd);
133 	if (write == 0) {
134 		if (rdata == NULL) {
135 			ERROR("rdata is a NULL pointer\n");
136 			return_value = E_PWR_INVALID_ARG;
137 			goto FAIL;
138 		}
139 		return_value = wait_for_state_ready(TIMEOUT_READ,
140 					&mtk_pwrap->wacs2_rdata,
141 					&reg_rdata);
142 		if (return_value != 0) {
143 			ERROR("wait_for_fsm_vldclr fail,return_value=%d\n",
144 				 return_value);
145 			goto FAIL;
146 		}
147 		*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
148 			  & RDATA_WACS_RDATA_MASK);
149 		mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 1);
150 	}
151 FAIL:
152 	return return_value;
153 }
154 
155 /* external API for pmic_wrap user */
156 
pwrap_read(uint32_t adr,uint32_t * rdata)157 int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
158 {
159 	return pwrap_wacs2(0, adr, 0, rdata, 1);
160 }
161 
pwrap_write(uint32_t adr,uint32_t wdata)162 int32_t pwrap_write(uint32_t adr, uint32_t wdata)
163 {
164 	return pwrap_wacs2(1, adr, wdata, 0, 1);
165 }
166