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 ®_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