xref: /rk3399_ARM-atf/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c (revision 1818c029252914b7d5c93915789c7cef32ffcfd7)
1 /*
2  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * ZynqMP system level PM-API functions for ioctl.
9  */
10 
11 #include <arch_helpers.h>
12 #include <delay_timer.h>
13 #include <mmio.h>
14 #include <platform.h>
15 #include "pm_api_ioctl.h"
16 #include "pm_api_sys.h"
17 #include "pm_client.h"
18 #include "pm_common.h"
19 #include "pm_ipi.h"
20 #include "../zynqmp_def.h"
21 
22 /**
23  * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode
24  * @mode	Buffer to store value of oper mode(Split/Lock-step)
25  *
26  * This function provides current configured RPU operational mode.
27  *
28  * @return	Returns status, either success or error+reason
29  */
30 static enum pm_ret_status pm_ioctl_get_rpu_oper_mode(unsigned int *mode)
31 {
32 	unsigned int val;
33 
34 	val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
35 	val &= ZYNQMP_SLSPLIT_MASK;
36 	if (val)
37 		*mode = PM_RPU_MODE_SPLIT;
38 	else
39 		*mode = PM_RPU_MODE_LOCKSTEP;
40 
41 	return PM_RET_SUCCESS;
42 }
43 
44 /**
45  * pm_ioctl_set_rpu_oper_mode () - Configure RPU operation mode
46  * @mode	Value to set for oper mode(Split/Lock-step)
47  *
48  * This function configures RPU operational mode(Split/Lock-step).
49  * It also sets TCM combined mode in RPU lock-step and TCM non-combined
50  * mode for RPU split mode. In case of Lock step mode, RPU1's output is
51  * clamped.
52  *
53  * @return	Returns status, either success or error+reason
54  */
55 static enum pm_ret_status pm_ioctl_set_rpu_oper_mode(unsigned int mode)
56 {
57 	unsigned int val;
58 
59 	if (mmio_read_32(CRL_APB_RST_LPD_TOP) && CRL_APB_RPU_AMBA_RESET)
60 		return PM_RET_ERROR_ACCESS;
61 
62 	val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
63 
64 	if (mode == PM_RPU_MODE_SPLIT) {
65 		val |= ZYNQMP_SLSPLIT_MASK;
66 		val &= ~ZYNQMP_TCM_COMB_MASK;
67 		val &= ~ZYNQMP_SLCLAMP_MASK;
68 	} else if (mode == PM_RPU_MODE_LOCKSTEP) {
69 		val &= ~ZYNQMP_SLSPLIT_MASK;
70 		val |= ZYNQMP_TCM_COMB_MASK;
71 		val |= ZYNQMP_SLCLAMP_MASK;
72 	} else {
73 		return PM_RET_ERROR_ARGS;
74 	}
75 
76 	mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
77 
78 	return PM_RET_SUCCESS;
79 }
80 
81 /**
82  * pm_ioctl_config_boot_addr() - Configure RPU boot address
83  * @nid		Node ID of RPU
84  * @value	Value to set for boot address (TCM/OCM)
85  *
86  * This function configures RPU boot address(memory).
87  *
88  * @return	Returns status, either success or error+reason
89  */
90 static enum pm_ret_status pm_ioctl_config_boot_addr(enum pm_node_id nid,
91 						    unsigned int value)
92 {
93 	unsigned int rpu_cfg_addr, val;
94 
95 	if (nid == NODE_RPU_0)
96 		rpu_cfg_addr = ZYNQMP_RPU0_CFG;
97 	else if (nid == NODE_RPU_1)
98 		rpu_cfg_addr = ZYNQMP_RPU1_CFG;
99 	else
100 		return PM_RET_ERROR_ARGS;
101 
102 	val = mmio_read_32(rpu_cfg_addr);
103 
104 	if (value == PM_RPU_BOOTMEM_LOVEC)
105 		val &= ~ZYNQMP_VINITHI_MASK;
106 	else if (value == PM_RPU_BOOTMEM_HIVEC)
107 		val |= ZYNQMP_VINITHI_MASK;
108 	else
109 		return PM_RET_ERROR_ARGS;
110 
111 	mmio_write_32(rpu_cfg_addr, val);
112 
113 	return PM_RET_SUCCESS;
114 }
115 
116 /**
117  * pm_ioctl_config_tcm_comb() - Configure TCM combined mode
118  * @value	Value to set (Split/Combined)
119  *
120  * This function configures TCM to be in split mode or combined
121  * mode.
122  *
123  * @return	Returns status, either success or error+reason
124  */
125 static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value)
126 {
127 	unsigned int val;
128 
129 	val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
130 
131 	if (value == PM_RPU_TCM_SPLIT)
132 		val &= ~ZYNQMP_TCM_COMB_MASK;
133 	else if (value == PM_RPU_TCM_COMB)
134 		val |= ZYNQMP_TCM_COMB_MASK;
135 	else
136 		return PM_RET_ERROR_ARGS;
137 
138 	mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
139 
140 	return PM_RET_SUCCESS;
141 }
142 
143 /**
144  * pm_ioctl_set_tapdelay_bypass() -  Enable/Disable tap delay bypass
145  * @type	Type of tap delay to enable/disable (e.g. QSPI)
146  * @value	Enable/Disable
147  *
148  * This function enable/disable tap delay bypass.
149  *
150  * @return	Returns status, either success or error+reason
151  */
152 static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(unsigned int type,
153 						       unsigned int value)
154 {
155 	if ((value != PM_TAPDELAY_BYPASS_ENABLE &&
156 	     value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX)
157 		return PM_RET_ERROR_ARGS;
158 
159 	return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type);
160 }
161 
162 /**
163  * pm_ioctl_set_sgmii_mode() -  Set SGMII mode for the GEM device
164  * @nid		Node ID of the device
165  * @value	Enable/Disable
166  *
167  * This function enable/disable SGMII mode for the GEM device.
168  * While enabling SGMII mode, it also ties the GEM PCS Signal
169  * Detect to 1 and selects EMIO for RX clock generation.
170  *
171  * @return	Returns status, either success or error+reason
172  */
173 static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid,
174 						  unsigned int value)
175 {
176 	unsigned int val, mask, shift;
177 	int ret;
178 
179 	if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE)
180 		return PM_RET_ERROR_ARGS;
181 
182 	switch (nid) {
183 	case NODE_ETH_0:
184 		shift = 0;
185 		break;
186 	case NODE_ETH_1:
187 		shift = 1;
188 		break;
189 	case NODE_ETH_2:
190 		shift = 2;
191 		break;
192 	case NODE_ETH_3:
193 		shift = 3;
194 		break;
195 	default:
196 		return PM_RET_ERROR_ARGS;
197 	}
198 
199 	if (value == PM_SGMII_DISABLE) {
200 		mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift;
201 		ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0);
202 	} else {
203 		/* Tie the GEM PCS Signal Detect to 1 */
204 		mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift;
205 		val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift;
206 		ret = pm_mmio_write(IOU_GEM_CTRL, mask, val);
207 		if (ret)
208 			return ret;
209 
210 		/* Set the GEM to SGMII mode */
211 		mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift;
212 		val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE;
213 		val <<= GEM_CLK_CTRL_OFFSET * shift;
214 		ret =  pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val);
215 	}
216 
217 	return ret;
218 }
219 
220 /**
221  * pm_ioctl_sd_dll_reset() -  Reset DLL logic
222  * @nid		Node ID of the device
223  * @type	Reset type
224  *
225  * This function resets DLL logic for the SD device.
226  *
227  * @return	Returns status, either success or error+reason
228  */
229 static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid,
230 						unsigned int type)
231 {
232 	unsigned int mask, val;
233 	int ret;
234 
235 	if (nid == NODE_SD_0) {
236 		mask = ZYNQMP_SD0_DLL_RST_MASK;
237 		val = ZYNQMP_SD0_DLL_RST;
238 	} else if (nid == NODE_SD_1) {
239 		mask = ZYNQMP_SD1_DLL_RST_MASK;
240 		val = ZYNQMP_SD1_DLL_RST;
241 	} else {
242 		return PM_RET_ERROR_ARGS;
243 	}
244 
245 	switch (type) {
246 	case PM_DLL_RESET_ASSERT:
247 	case PM_DLL_RESET_PULSE:
248 		ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val);
249 		if (ret)
250 			return ret;
251 
252 		if (type == PM_DLL_RESET_ASSERT)
253 			break;
254 		mdelay(1);
255 	case PM_DLL_RESET_RELEASE:
256 		ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0);
257 		break;
258 	default:
259 		ret = PM_RET_ERROR_ARGS;
260 	}
261 
262 	return ret;
263 }
264 
265 /**
266  * pm_ioctl_sd_set_tapdelay() -  Set tap delay for the SD device
267  * @nid		Node ID of the device
268  * @type	Type of tap delay to set (input/output)
269  * @value	Value to set fot the tap delay
270  *
271  * This function sets input/output tap delay for the SD device.
272  *
273  * @return	Returns status, either success or error+reason
274  */
275 static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid,
276 						   enum tap_delay_type type,
277 						   unsigned int value)
278 {
279 	unsigned int shift;
280 	int ret;
281 
282 	if (nid == NODE_SD_0)
283 		shift = 0;
284 	else if (nid == NODE_SD_1)
285 		shift = ZYNQMP_SD_TAP_OFFSET;
286 	else
287 		return PM_RET_ERROR_ARGS;
288 
289 	ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT);
290 	if (ret)
291 		return ret;
292 
293 	if (type == PM_TAPDELAY_INPUT) {
294 		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
295 				    ZYNQMP_SD_ITAPCHGWIN_MASK << shift,
296 				    ZYNQMP_SD_ITAPCHGWIN << shift);
297 		if (ret)
298 			goto reset_release;
299 		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
300 				    ZYNQMP_SD_ITAPDLYENA_MASK << shift,
301 				    ZYNQMP_SD_ITAPDLYENA << shift);
302 		if (ret)
303 			goto reset_release;
304 		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
305 				    ZYNQMP_SD_ITAPDLYSEL_MASK << shift,
306 				    value << shift);
307 		if (ret)
308 			goto reset_release;
309 		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
310 				    ZYNQMP_SD_ITAPCHGWIN_MASK << shift, 0);
311 	} else if (type == PM_TAPDELAY_OUTPUT) {
312 		ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
313 				    ZYNQMP_SD_OTAPDLYENA_MASK << shift,
314 				    ZYNQMP_SD_OTAPDLYENA << shift);
315 		if (ret)
316 			goto reset_release;
317 		ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
318 				    ZYNQMP_SD_OTAPDLYSEL_MASK << shift,
319 				    value << shift);
320 	} else {
321 		ret = PM_RET_ERROR_ARGS;
322 	}
323 
324 reset_release:
325 	ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE);
326 	if (ret)
327 		return ret;
328 
329 	return ret;
330 }
331 
332 /**
333  * pm_api_ioctl() -  PM IOCTL API for device control and configs
334  * @node_id	Node ID of the device
335  * @ioctl_id	ID of the requested IOCTL
336  * @arg1	Argument 1 to requested IOCTL call
337  * @arg2	Argument 2 to requested IOCTL call
338  * @value	Returned output value
339  *
340  * This function calls IOCTL to firmware for device control and configuration.
341  *
342  * @return	Returns status, either success or error+reason
343  */
344 enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
345 				unsigned int ioctl_id,
346 				unsigned int arg1,
347 				unsigned int arg2,
348 				unsigned int *value)
349 {
350 	int ret;
351 
352 	switch (ioctl_id) {
353 	case IOCTL_GET_RPU_OPER_MODE:
354 		ret = pm_ioctl_get_rpu_oper_mode(value);
355 		break;
356 	case IOCTL_SET_RPU_OPER_MODE:
357 		ret = pm_ioctl_set_rpu_oper_mode(arg1);
358 		break;
359 	case IOCTL_RPU_BOOT_ADDR_CONFIG:
360 		ret = pm_ioctl_config_boot_addr(nid, arg1);
361 		break;
362 	case IOCTL_TCM_COMB_CONFIG:
363 		ret = pm_ioctl_config_tcm_comb(arg1);
364 		break;
365 	case IOCTL_SET_TAPDELAY_BYPASS:
366 		ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2);
367 		break;
368 	case IOCTL_SET_SGMII_MODE:
369 		ret = pm_ioctl_set_sgmii_mode(nid, arg1);
370 		break;
371 	case IOCTL_SD_DLL_RESET:
372 		ret = pm_ioctl_sd_dll_reset(nid, arg1);
373 		break;
374 	case IOCTL_SET_SD_TAPDELAY:
375 		ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2);
376 		break;
377 	default:
378 		ret = PM_RET_ERROR_NOTSUPPORTED;
379 	}
380 
381 	return ret;
382 }
383