1 /*
2  * Copyright (c) 2020, 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