1 /*
2 * Copyright (c) 2020-2022, 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
11 #include "platform_def.h"
12 #include "pmic_wrap_init.h"
13
14 /* pmic wrap module wait_idle and read polling interval (in microseconds) */
15 enum pwrap_polling_interval {
16 WAIT_IDLE_POLLING_DELAY_US = 1,
17 READ_POLLING_DELAY_US = 2
18 };
19
pwrap_check_idle(void * wacs_register,uint32_t timeout_us)20 static uint32_t pwrap_check_idle(void *wacs_register, uint32_t timeout_us)
21 {
22 uint32_t reg_rdata = 0U, retry;
23
24 retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
25 WAIT_IDLE_POLLING_DELAY_US;
26 while (retry != 0) {
27 udelay(WAIT_IDLE_POLLING_DELAY_US);
28 reg_rdata = mmio_read_32((uintptr_t)wacs_register);
29 /* if last read command timeout,clear vldclr bit
30 * read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
31 * write:FSM_REQ-->idle
32 */
33 switch (GET_WACS_FSM(reg_rdata)) {
34 case SWINF_FSM_WFVLDCLR:
35 mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
36 INFO("WACS_FSM = SWINF_FSM_WFVLDCLR\n");
37 break;
38 case SWINF_FSM_WFDLE:
39 INFO("WACS_FSM = SWINF_FSM_WFDLE\n");
40 break;
41 case SWINF_FSM_REQ:
42 INFO("WACS_FSM = SWINF_FSM_REQ\n");
43 break;
44 case SWINF_FSM_IDLE:
45 goto done;
46 default:
47 break;
48 }
49 retry--;
50 };
51
52 done:
53 if (retry == 0) {
54 /* timeout */
55 return E_PWR_WAIT_IDLE_TIMEOUT;
56 }
57
58 return 0U;
59 }
60
pwrap_check_vldclr(void * wacs_register,uint32_t timeout_us)61 static uint32_t pwrap_check_vldclr(void *wacs_register, uint32_t timeout_us)
62 {
63 uint32_t reg_rdata = 0U, retry;
64
65 retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
66 while (retry != 0) {
67 udelay(READ_POLLING_DELAY_US);
68 reg_rdata = mmio_read_32((uintptr_t)wacs_register);
69 if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_WFVLDCLR) {
70 break;
71 }
72 retry--;
73 };
74
75 if (retry == 0) {
76 /* timeout */
77 return E_PWR_WAIT_IDLE_TIMEOUT;
78 }
79
80 return 0U;
81 }
82
pwrap_wacs2(uint32_t write,uint32_t adr,uint32_t wdata,uint32_t * rdata,uint32_t init_check)83 static int32_t pwrap_wacs2(uint32_t write, uint32_t adr, uint32_t wdata,
84 uint32_t *rdata, uint32_t init_check)
85 {
86 uint32_t reg_rdata, return_value;
87
88 if (init_check != 0) {
89 if ((mmio_read_32((uintptr_t)&mtk_pwrap->init_done) & 0x1) == 0) {
90 ERROR("initialization isn't finished\n");
91 return E_PWR_NOT_INIT_DONE;
92 }
93 }
94
95 /* Wait for Software Interface FSM state to be IDLE. */
96 return_value = pwrap_check_idle(&mtk_pwrap->wacs2_sta,
97 PWRAP_WAIT_IDLE_US);
98 if (return_value != 0) {
99 return return_value;
100 }
101
102 /* Set the write data */
103 if (write == 1) {
104 /* Set the write data. */
105 mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_wdata, wdata);
106 }
107
108 /* Send the command. */
109 mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, (write << 29) | adr);
110
111 if (write == 0) {
112 /*
113 * Wait for Software Interface FSM state to be WFVLDCLR,
114 * read the data and clear the valid flag.
115 */
116 return_value = pwrap_check_vldclr(&mtk_pwrap->wacs2_sta,
117 PWRAP_READ_US);
118 if (return_value != 0) {
119 return return_value;
120 }
121
122 if (rdata == NULL) {
123 return E_PWR_INVALID_ARG;
124 }
125
126 reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
127 *rdata = reg_rdata;
128 mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
129 }
130
131 return return_value;
132 }
133
134 /* external API for pmic_wrap user */
pwrap_read(uint32_t adr,uint32_t * rdata)135 int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
136 {
137 return pwrap_wacs2(0, adr, 0, rdata, 1);
138 }
139
pwrap_write(uint32_t adr,uint32_t wdata)140 int32_t pwrap_write(uint32_t adr, uint32_t wdata)
141 {
142 return pwrap_wacs2(1, adr, wdata, 0, 1);
143 }
144