blob: a7076eead24da5b8c07df57be071cbcc140031f1 [file] [log] [blame]
Hsin-Hsiung Wang22f83702020-05-29 19:46:14 +08001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <assert.h>
4#include <console/console.h>
5#include <device/mmio.h>
6#include <soc/addressmap.h>
7#include <soc/pmif.h>
8#include <soc/pmif_spi.h>
9#include <soc/pmif_spmi.h>
10#include <soc/pmif_sw.h>
11#include <soc/spmi.h>
Hsin-Hsiung Wang22f83702020-05-29 19:46:14 +080012#include <timer.h>
13
14static int pmif_check_swinf(struct pmif *arb, long timeout_us, u32 expected_status)
15{
16 u32 reg_rdata;
17 struct stopwatch sw;
18
19 stopwatch_init_usecs_expire(&sw, timeout_us);
20 do {
21 reg_rdata = read32(&arb->ch->ch_sta);
22 if (stopwatch_expired(&sw))
23 return E_TIMEOUT;
24 } while (GET_SWINF_0_FSM(reg_rdata) != expected_status);
25
26 return 0;
27}
28
29static void pmif_send_cmd(struct pmif *arb, int write, u32 opc, u32 slvid,
30 u32 addr, u32 *rdata, u32 wdata, u32 len)
31{
32 int ret;
33 u32 data, bc = len - 1;
34
35 /* Wait for Software Interface FSM state to be IDLE. */
36 ret = pmif_check_swinf(arb, PMIF_WAIT_IDLE_US, SWINF_FSM_IDLE);
37 if (ret) {
38 printk(BIOS_ERR, "[%s] idle timeout\n", __func__);
39 return;
40 }
41
42 /* Set the write data */
43 if (write)
44 write32(&arb->ch->wdata, wdata);
45
46 /* Send the command. */
47 write32(&arb->ch->ch_send,
48 (opc << 30) | (write << 29) | (slvid << 24) | (bc << 16) | addr);
49
50 if (!write) {
51 /*
52 * Wait for Software Interface FSM state to be WFVLDCLR,
53 * read the data and clear the valid flag.
54 */
55 ret = pmif_check_swinf(arb, PMIF_READ_US, SWINF_FSM_WFVLDCLR);
56 if (ret) {
57 printk(BIOS_ERR, "[%s] read timeout\n", __func__);
58 return;
59 }
60
61 data = read32(&arb->ch->rdata);
62 *rdata = data;
63 write32(&arb->ch->ch_rdy, 0x1);
64 }
65}
66
67static void pmif_spmi_read(struct pmif *arb, u32 slvid, u32 reg, u32 *data)
68{
69 *data = 0;
70 pmif_send_cmd(arb, 0, PMIF_CMD_EXT_REG_LONG, slvid, reg, data, 0, 1);
71}
72
73static void pmif_spmi_write(struct pmif *arb, u32 slvid, u32 reg, u32 data)
74{
75 pmif_send_cmd(arb, 1, PMIF_CMD_EXT_REG_LONG, slvid, reg, NULL, data, 1);
76}
77
78static u32 pmif_spmi_read_field(struct pmif *arb, u32 slvid, u32 reg, u32 mask, u32 shift)
79{
80 u32 data;
81
82 pmif_spmi_read(arb, slvid, reg, &data);
83 data &= (mask << shift);
84 data >>= shift;
85
86 return data;
87}
88
89static void pmif_spmi_write_field(struct pmif *arb, u32 slvid, u32 reg,
90 u32 val, u32 mask, u32 shift)
91{
92 u32 old, new;
93
94 pmif_spmi_read(arb, slvid, reg, &old);
95 new = old & ~(mask << shift);
96 new |= (val << shift);
97 pmif_spmi_write(arb, slvid, reg, new);
98}
99
100static void pmif_spi_read(struct pmif *arb, u32 slvid, u32 reg, u32 *data)
101{
102 *data = 0;
103 pmif_send_cmd(arb, 0, PMIF_CMD_REG_0, slvid, reg, data, 0, 1);
104}
105
106static void pmif_spi_write(struct pmif *arb, u32 slvid, u32 reg, u32 data)
107{
108 pmif_send_cmd(arb, 1, PMIF_CMD_REG_0, slvid, reg, NULL, data, 1);
109}
110
111static u32 pmif_spi_read_field(struct pmif *arb, u32 slvid, u32 reg, u32 mask, u32 shift)
112{
113 u32 data;
114
115 pmif_spi_read(arb, slvid, reg, &data);
116 data &= (mask << shift);
117 data >>= shift;
118
119 return data;
120}
121
122static void pmif_spi_write_field(struct pmif *arb, u32 slvid, u32 reg,
123 u32 val, u32 mask, u32 shift)
124{
125 u32 old, new;
126
127 pmif_spi_read(arb, slvid, reg, &old);
128 new = old & ~(mask << shift);
129 new |= (val << shift);
130 pmif_spi_write(arb, slvid, reg, new);
131}
132
133static int is_pmif_init_done(struct pmif *arb)
134{
135 if (read32(&arb->mtk_pmif->init_done) & 0x1)
136 return 0;
137
138 return -E_NODEV;
139}
140
141static const struct pmif pmif_spmi_arb[] = {
142 {
143 .mtk_pmif = (struct mtk_pmif_regs *)PMIF_SPMI_BASE,
144 .ch = (struct chan_regs *)PMIF_SPMI_AP_CHAN,
145 .mstid = SPMI_MASTER_0,
146 .pmifid = PMIF_SPMI,
147 .write = pmif_spmi_write,
148 .read = pmif_spmi_read,
149 .write_field = pmif_spmi_write_field,
150 .read_field = pmif_spmi_read_field,
151 .is_pmif_init_done = is_pmif_init_done,
152 },
153};
154
155static const struct pmif pmif_spi_arb[] = {
156 {
157 .mtk_pmif = (struct mtk_pmif_regs *)PMIF_SPI_BASE,
158 .ch = (struct chan_regs *)PMIF_SPI_AP_CHAN,
159 .pmifid = PMIF_SPI,
160 .write = pmif_spi_write,
161 .read = pmif_spi_read,
162 .write_field = pmif_spi_write_field,
163 .read_field = pmif_spi_read_field,
164 .is_pmif_init_done = is_pmif_init_done,
165 },
166};
167
168struct pmif *get_pmif_controller(int inf, int mstid)
169{
170 if (inf == PMIF_SPMI && mstid < ARRAY_SIZE(pmif_spmi_arb))
171 return (struct pmif *)&pmif_spmi_arb[mstid];
172 else if (inf == PMIF_SPI)
173 return (struct pmif *)&pmif_spi_arb[0];
174
175 die("[%s] Failed to get pmif controller: inf = %d, mstid = %d\n", __func__, inf, mstid);
176 return NULL;
177}
178
Yuchen Huangec39cb32020-09-23 20:41:19 +0800179static void pmif_select(enum pmic_interface mode)
180{
181 unsigned int spi_spm_sleep_req, spi_scp_sleep_req,
182 spmi_spm_sleep_req, spmi_scp_sleep_req,
183 spi_md_ctl_pmif_rdy, spi_md_ctl_srclk_en, spi_md_ctl_srvol_en,
184 spmi_md_ctl_pmif_rdy, spmi_md_ctl_srclk_en, spmi_md_ctl_srvol_en,
185 spi_inf_srclken_rc_en, spi_other_inf_dcxo0_en, spi_other_inf_dcxo1_en,
186 spi_arb_srclken_rc_en, spi_arb_dcxo_conn_en, spi_arb_dcxo_nfc_en;
187
188 switch (mode) {
189 case PMIF_VLD_RDY:
190 /* spm and scp sleep request disable spi and spmi */
191 spi_spm_sleep_req = 1;
192 spi_scp_sleep_req = 1;
193 spmi_spm_sleep_req = 1;
194 spmi_scp_sleep_req = 1;
195
196 /*
197 * pmic vld/rdy control spi mode enable
198 * srclken control spi mode disable
199 * vreq control spi mode disable
200 */
201 spi_md_ctl_pmif_rdy = 1;
202 spi_md_ctl_srclk_en = 0;
203 spi_md_ctl_srvol_en = 0;
204 spmi_md_ctl_pmif_rdy = 1;
205 spmi_md_ctl_srclk_en = 0;
206 spmi_md_ctl_srvol_en = 0;
207
208 /* srclken rc interface enable */
209 spi_inf_srclken_rc_en = 1;
210
211 /* dcxo interface disable */
212 spi_other_inf_dcxo0_en = 0;
213 spi_other_inf_dcxo1_en = 0;
214
215 /* srclken enable, dcxo0,1 disable */
216 spi_arb_srclken_rc_en = 1;
217 spi_arb_dcxo_conn_en = 0;
218 spi_arb_dcxo_nfc_en = 0;
219 break;
220
221 case PMIF_SLP_REQ:
222 /* spm and scp sleep request enable spi and spmi */
223 spi_spm_sleep_req = 0;
224 spi_scp_sleep_req = 0;
225 spmi_spm_sleep_req = 0;
226 spmi_scp_sleep_req = 0;
227
228 /*
229 * pmic vld/rdy control spi mode disable
230 * srclken control spi mode enable
231 * vreq control spi mode enable
232 */
233 spi_md_ctl_pmif_rdy = 0;
234 spi_md_ctl_srclk_en = 1;
235 spi_md_ctl_srvol_en = 1;
236 spmi_md_ctl_pmif_rdy = 0;
237 spmi_md_ctl_srclk_en = 1;
238 spmi_md_ctl_srvol_en = 1;
239
240 /* srclken rc interface disable */
241 spi_inf_srclken_rc_en = 0;
242
243 /* dcxo interface enable */
244 spi_other_inf_dcxo0_en = 1;
245 spi_other_inf_dcxo1_en = 1;
246
247 /* srclken disable, dcxo0,1 enable */
248 spi_arb_srclken_rc_en = 0;
249 spi_arb_dcxo_conn_en = 1;
250 spi_arb_dcxo_nfc_en = 1;
251 break;
252
253 default:
254 die("Can't support pmif mode %d\n", mode);
255 }
256
257 SET32_BITFIELDS(&pmif_spi_arb[0].mtk_pmif->sleep_protection_ctrl,
258 PMIFSPI_SPM_SLEEP_REQ_SEL, spi_spm_sleep_req,
259 PMIFSPI_SCP_SLEEP_REQ_SEL, spi_scp_sleep_req);
260 SET32_BITFIELDS(&pmif_spmi_arb[0].mtk_pmif->sleep_protection_ctrl,
261 PMIFSPMI_SPM_SLEEP_REQ_SEL, spmi_spm_sleep_req,
262 PMIFSPMI_SCP_SLEEP_REQ_SEL, spmi_scp_sleep_req);
263 SET32_BITFIELDS(&pmif_spi_arb[0].mtk_pmif->spi_mode_ctrl,
264 PMIFSPI_MD_CTL_PMIF_RDY, spi_md_ctl_pmif_rdy,
265 PMIFSPI_MD_CTL_SRCLK_EN, spi_md_ctl_srclk_en,
266 PMIFSPI_MD_CTL_SRVOL_EN, spi_md_ctl_srvol_en);
267 SET32_BITFIELDS(&pmif_spmi_arb[0].mtk_pmif->spi_mode_ctrl,
268 PMIFSPMI_MD_CTL_PMIF_RDY, spmi_md_ctl_pmif_rdy,
269 PMIFSPMI_MD_CTL_SRCLK_EN, spmi_md_ctl_srclk_en,
270 PMIFSPMI_MD_CTL_SRVOL_EN, spmi_md_ctl_srvol_en);
271 SET32_BITFIELDS(&pmif_spi_arb[0].mtk_pmif->inf_en,
272 PMIFSPI_INF_EN_SRCLKEN_RC_HW, spi_inf_srclken_rc_en);
273 SET32_BITFIELDS(&pmif_spi_arb[0].mtk_pmif->other_inf_en,
274 PMIFSPI_OTHER_INF_DXCO0_EN, spi_other_inf_dcxo0_en,
275 PMIFSPI_OTHER_INF_DXCO1_EN, spi_other_inf_dcxo1_en);
276 SET32_BITFIELDS(&pmif_spi_arb[0].mtk_pmif->arb_en,
277 PMIFSPI_ARB_EN_SRCLKEN_RC_HW, spi_arb_srclken_rc_en,
278 PMIFSPI_ARB_EN_DCXO_CONN, spi_arb_dcxo_conn_en,
279 PMIFSPI_ARB_EN_DCXO_NFC, spi_arb_dcxo_nfc_en);
280}
281
282void pmwrap_interface_init(void)
283{
284 if (CONFIG(SRCLKEN_RC_SUPPORT)) {
285 printk(BIOS_INFO, "%s: Select PMIF_VLD_RDY\n", __func__);
286 pmif_select(PMIF_VLD_RDY);
287 } else {
288 printk(BIOS_INFO, "%s: Select PMIF_SLP_REQ\n", __func__);
289 pmif_select(PMIF_SLP_REQ);
290 }
291}
292
Hsin-Hsiung Wang22f83702020-05-29 19:46:14 +0800293int mtk_pmif_init(void)
294{
295 int ret;
296
297 ret = pmif_clk_init();
298 if (!ret)
299 ret = pmif_spmi_init(get_pmif_controller(PMIF_SPMI, SPMI_MASTER_0));
Rex-BC Chen6d449e02022-10-19 18:51:39 +0800300 if (!ret && !CONFIG(PWRAP_WITH_PMIF_SPMI))
Hsin-Hsiung Wang22f83702020-05-29 19:46:14 +0800301 ret = pmif_spi_init(get_pmif_controller(PMIF_SPI, 0));
302
303 return ret;
304}