blob: cdbb515b098c01b71d2970bfc7aff35c433a761e [file] [log] [blame]
Rajan Vaja5529a012018-01-17 02:39:23 -08001/*
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>
Rajan Vaja35116132018-01-17 02:39:25 -080015#include "pm_api_clock.h"
Rajan Vaja5529a012018-01-17 02:39:23 -080016#include "pm_api_ioctl.h"
17#include "pm_api_sys.h"
18#include "pm_client.h"
19#include "pm_common.h"
20#include "pm_ipi.h"
21#include "../zynqmp_def.h"
22
23/**
24 * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode
25 * @mode Buffer to store value of oper mode(Split/Lock-step)
26 *
27 * This function provides current configured RPU operational mode.
28 *
29 * @return Returns status, either success or error+reason
30 */
31static enum pm_ret_status pm_ioctl_get_rpu_oper_mode(unsigned int *mode)
32{
33 unsigned int val;
34
35 val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
36 val &= ZYNQMP_SLSPLIT_MASK;
Jolly Shah69fb5bf2018-02-07 16:25:41 -080037 if (val == 0)
Rajan Vaja5529a012018-01-17 02:39:23 -080038 *mode = PM_RPU_MODE_LOCKSTEP;
Jolly Shah69fb5bf2018-02-07 16:25:41 -080039 else
40 *mode = PM_RPU_MODE_SPLIT;
Rajan Vaja5529a012018-01-17 02:39:23 -080041
42 return PM_RET_SUCCESS;
43}
44
45/**
46 * pm_ioctl_set_rpu_oper_mode () - Configure RPU operation mode
47 * @mode Value to set for oper mode(Split/Lock-step)
48 *
49 * This function configures RPU operational mode(Split/Lock-step).
50 * It also sets TCM combined mode in RPU lock-step and TCM non-combined
51 * mode for RPU split mode. In case of Lock step mode, RPU1's output is
52 * clamped.
53 *
54 * @return Returns status, either success or error+reason
55 */
56static enum pm_ret_status pm_ioctl_set_rpu_oper_mode(unsigned int mode)
57{
58 unsigned int val;
59
60 if (mmio_read_32(CRL_APB_RST_LPD_TOP) && CRL_APB_RPU_AMBA_RESET)
61 return PM_RET_ERROR_ACCESS;
62
63 val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
64
65 if (mode == PM_RPU_MODE_SPLIT) {
66 val |= ZYNQMP_SLSPLIT_MASK;
67 val &= ~ZYNQMP_TCM_COMB_MASK;
68 val &= ~ZYNQMP_SLCLAMP_MASK;
69 } else if (mode == PM_RPU_MODE_LOCKSTEP) {
70 val &= ~ZYNQMP_SLSPLIT_MASK;
71 val |= ZYNQMP_TCM_COMB_MASK;
72 val |= ZYNQMP_SLCLAMP_MASK;
73 } else {
74 return PM_RET_ERROR_ARGS;
75 }
76
77 mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
78
79 return PM_RET_SUCCESS;
80}
81
82/**
83 * pm_ioctl_config_boot_addr() - Configure RPU boot address
84 * @nid Node ID of RPU
85 * @value Value to set for boot address (TCM/OCM)
86 *
87 * This function configures RPU boot address(memory).
88 *
89 * @return Returns status, either success or error+reason
90 */
91static enum pm_ret_status pm_ioctl_config_boot_addr(enum pm_node_id nid,
92 unsigned int value)
93{
94 unsigned int rpu_cfg_addr, val;
95
96 if (nid == NODE_RPU_0)
97 rpu_cfg_addr = ZYNQMP_RPU0_CFG;
98 else if (nid == NODE_RPU_1)
99 rpu_cfg_addr = ZYNQMP_RPU1_CFG;
100 else
101 return PM_RET_ERROR_ARGS;
102
103 val = mmio_read_32(rpu_cfg_addr);
104
105 if (value == PM_RPU_BOOTMEM_LOVEC)
106 val &= ~ZYNQMP_VINITHI_MASK;
107 else if (value == PM_RPU_BOOTMEM_HIVEC)
108 val |= ZYNQMP_VINITHI_MASK;
109 else
110 return PM_RET_ERROR_ARGS;
111
112 mmio_write_32(rpu_cfg_addr, val);
113
114 return PM_RET_SUCCESS;
115}
116
117/**
118 * pm_ioctl_config_tcm_comb() - Configure TCM combined mode
119 * @value Value to set (Split/Combined)
120 *
121 * This function configures TCM to be in split mode or combined
122 * mode.
123 *
124 * @return Returns status, either success or error+reason
125 */
126static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value)
127{
128 unsigned int val;
129
130 val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
131
132 if (value == PM_RPU_TCM_SPLIT)
133 val &= ~ZYNQMP_TCM_COMB_MASK;
134 else if (value == PM_RPU_TCM_COMB)
135 val |= ZYNQMP_TCM_COMB_MASK;
136 else
137 return PM_RET_ERROR_ARGS;
138
139 mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
140
141 return PM_RET_SUCCESS;
142}
143
144/**
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800145 * pm_ioctl_set_tapdelay_bypass() - Enable/Disable tap delay bypass
146 * @type Type of tap delay to enable/disable (e.g. QSPI)
147 * @value Enable/Disable
148 *
149 * This function enable/disable tap delay bypass.
150 *
151 * @return Returns status, either success or error+reason
152 */
153static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(unsigned int type,
154 unsigned int value)
155{
156 if ((value != PM_TAPDELAY_BYPASS_ENABLE &&
157 value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX)
158 return PM_RET_ERROR_ARGS;
159
160 return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type);
161}
162
163/**
164 * pm_ioctl_set_sgmii_mode() - Set SGMII mode for the GEM device
165 * @nid Node ID of the device
166 * @value Enable/Disable
167 *
168 * This function enable/disable SGMII mode for the GEM device.
169 * While enabling SGMII mode, it also ties the GEM PCS Signal
170 * Detect to 1 and selects EMIO for RX clock generation.
171 *
172 * @return Returns status, either success or error+reason
173 */
174static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid,
175 unsigned int value)
176{
177 unsigned int val, mask, shift;
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800178 enum pm_ret_status ret;
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800179
180 if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE)
181 return PM_RET_ERROR_ARGS;
182
183 switch (nid) {
184 case NODE_ETH_0:
185 shift = 0;
186 break;
187 case NODE_ETH_1:
188 shift = 1;
189 break;
190 case NODE_ETH_2:
191 shift = 2;
192 break;
193 case NODE_ETH_3:
194 shift = 3;
195 break;
196 default:
197 return PM_RET_ERROR_ARGS;
198 }
199
200 if (value == PM_SGMII_DISABLE) {
201 mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift;
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800202 ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0U);
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800203 } else {
204 /* Tie the GEM PCS Signal Detect to 1 */
205 mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift;
206 val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift;
207 ret = pm_mmio_write(IOU_GEM_CTRL, mask, val);
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800208 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800209 return ret;
210
211 /* Set the GEM to SGMII mode */
212 mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift;
213 val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE;
214 val <<= GEM_CLK_CTRL_OFFSET * shift;
215 ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val);
216 }
217
218 return ret;
219}
220
221/**
222 * pm_ioctl_sd_dll_reset() - Reset DLL logic
223 * @nid Node ID of the device
224 * @type Reset type
225 *
226 * This function resets DLL logic for the SD device.
227 *
228 * @return Returns status, either success or error+reason
229 */
230static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid,
231 unsigned int type)
232{
233 unsigned int mask, val;
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800234 enum pm_ret_status ret;
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800235
236 if (nid == NODE_SD_0) {
237 mask = ZYNQMP_SD0_DLL_RST_MASK;
238 val = ZYNQMP_SD0_DLL_RST;
239 } else if (nid == NODE_SD_1) {
240 mask = ZYNQMP_SD1_DLL_RST_MASK;
241 val = ZYNQMP_SD1_DLL_RST;
242 } else {
243 return PM_RET_ERROR_ARGS;
244 }
245
246 switch (type) {
247 case PM_DLL_RESET_ASSERT:
248 case PM_DLL_RESET_PULSE:
249 ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val);
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800250 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800251 return ret;
252
253 if (type == PM_DLL_RESET_ASSERT)
254 break;
255 mdelay(1);
256 case PM_DLL_RESET_RELEASE:
257 ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0);
258 break;
259 default:
260 ret = PM_RET_ERROR_ARGS;
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800261 break;
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800262 }
263
264 return ret;
265}
266
267/**
268 * pm_ioctl_sd_set_tapdelay() - Set tap delay for the SD device
269 * @nid Node ID of the device
270 * @type Type of tap delay to set (input/output)
271 * @value Value to set fot the tap delay
272 *
273 * This function sets input/output tap delay for the SD device.
274 *
275 * @return Returns status, either success or error+reason
276 */
277static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid,
278 enum tap_delay_type type,
279 unsigned int value)
280{
281 unsigned int shift;
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800282 enum pm_ret_status ret;
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800283
284 if (nid == NODE_SD_0)
285 shift = 0;
286 else if (nid == NODE_SD_1)
287 shift = ZYNQMP_SD_TAP_OFFSET;
288 else
289 return PM_RET_ERROR_ARGS;
290
291 ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT);
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800292 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800293 return ret;
294
295 if (type == PM_TAPDELAY_INPUT) {
296 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800297 (ZYNQMP_SD_ITAPCHGWIN_MASK << shift),
298 (ZYNQMP_SD_ITAPCHGWIN << shift));
299 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800300 goto reset_release;
301 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800302 (ZYNQMP_SD_ITAPDLYENA_MASK << shift),
303 (ZYNQMP_SD_ITAPDLYENA << shift));
304 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800305 goto reset_release;
306 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800307 (ZYNQMP_SD_ITAPDLYSEL_MASK << shift),
308 (value << shift));
309 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800310 goto reset_release;
311 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800312 (ZYNQMP_SD_ITAPCHGWIN_MASK << shift), 0);
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800313 } else if (type == PM_TAPDELAY_OUTPUT) {
314 ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800315 (ZYNQMP_SD_OTAPDLYENA_MASK << shift),
316 (ZYNQMP_SD_OTAPDLYENA << shift));
317 if (ret != PM_RET_SUCCESS)
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800318 goto reset_release;
319 ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800320 (ZYNQMP_SD_OTAPDLYSEL_MASK << shift),
321 (value << shift));
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800322 } else {
323 ret = PM_RET_ERROR_ARGS;
324 }
325
326reset_release:
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800327 pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE);
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800328 return ret;
329}
330
331/**
Rajan Vaja35116132018-01-17 02:39:25 -0800332 * pm_ioctl_set_pll_frac_mode() - Ioctl function for
333 * setting pll mode
334 * @pll PLL id
335 * @mode Mode fraction/integar
336 *
337 * This function sets PLL mode
338 *
339 * @return Returns status, either success or error+reason
340 */
341static enum pm_ret_status pm_ioctl_set_pll_frac_mode
342 (unsigned int pll, unsigned int mode)
343{
344 return pm_api_clk_set_pll_mode(pll, mode);
345}
346
347/**
348 * pm_ioctl_get_pll_frac_mode() - Ioctl function for
349 * getting pll mode
350 * @pll PLL id
351 * @mode Mode fraction/integar
352 *
353 * This function return current PLL mode
354 *
355 * @return Returns status, either success or error+reason
356 */
357static enum pm_ret_status pm_ioctl_get_pll_frac_mode
358 (unsigned int pll, unsigned int *mode)
359{
360 return pm_api_clk_get_pll_mode(pll, mode);
361}
362
363/**
364 * pm_ioctl_set_pll_frac_data() - Ioctl function for
365 * setting pll fraction data
366 * @pll PLL id
367 * @data fraction data
368 *
369 * This function sets fraction data.
370 * It is valid for fraction mode only.
371 *
372 * @return Returns status, either success or error+reason
373 */
374static enum pm_ret_status pm_ioctl_set_pll_frac_data
375 (unsigned int pll, unsigned int data)
376{
377 return pm_api_clk_set_pll_frac_data(pll, data);
378}
379
380/**
381 * pm_ioctl_get_pll_frac_data() - Ioctl function for
382 * getting pll fraction data
383 * @pll PLL id
384 * @data fraction data
385 *
386 * This function returns fraction data value.
387 *
388 * @return Returns status, either success or error+reason
389 */
390static enum pm_ret_status pm_ioctl_get_pll_frac_data
391 (unsigned int pll, unsigned int *data)
392{
393 return pm_api_clk_get_pll_frac_data(pll, data);
394}
395
396/**
Rajan Vaja393c0a22018-01-17 02:39:27 -0800397 * pm_ioctl_write_ggs() - Ioctl function for writing
398 * global general storage (ggs)
399 * @index GGS register index
400 * @value Register value to be written
401 *
402 * This function writes value to GGS register.
403 *
404 * @return Returns status, either success or error+reason
405 */
406static enum pm_ret_status pm_ioctl_write_ggs(unsigned int index,
407 unsigned int value)
408{
409 if (index >= GGS_NUM_REGS)
410 return PM_RET_ERROR_ARGS;
411
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800412 return pm_mmio_write(GGS_BASEADDR + (index << 2),
413 0xFFFFFFFFU, value);
Rajan Vaja393c0a22018-01-17 02:39:27 -0800414}
415
416/**
417 * pm_ioctl_read_ggs() - Ioctl function for reading
418 * global general storage (ggs)
419 * @index GGS register index
420 * @value Register value
421 *
422 * This function returns GGS register value.
423 *
424 * @return Returns status, either success or error+reason
425 */
426static enum pm_ret_status pm_ioctl_read_ggs(unsigned int index,
427 unsigned int *value)
428{
429 if (index >= GGS_NUM_REGS)
430 return PM_RET_ERROR_ARGS;
431
432 return pm_mmio_read(GGS_BASEADDR + (index << 2), value);
433}
434
435/**
436 * pm_ioctl_write_pggs() - Ioctl function for writing persistent
437 * global general storage (pggs)
438 * @index PGGS register index
439 * @value Register value to be written
440 *
441 * This function writes value to PGGS register.
442 *
443 * @return Returns status, either success or error+reason
444 */
445static enum pm_ret_status pm_ioctl_write_pggs(unsigned int index,
446 unsigned int value)
447{
448 if (index >= PGGS_NUM_REGS)
449 return PM_RET_ERROR_ARGS;
450
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800451 return pm_mmio_write(PGGS_BASEADDR + (index << 2),
452 0xFFFFFFFFU, value);
Rajan Vaja393c0a22018-01-17 02:39:27 -0800453}
454
455/**
456 * pm_ioctl_read_pggs() - Ioctl function for reading persistent
457 * global general storage (pggs)
458 * @index PGGS register index
459 * @value Register value
460 *
461 * This function returns PGGS register value.
462 *
463 * @return Returns status, either success or error+reason
464 */
465static enum pm_ret_status pm_ioctl_read_pggs(unsigned int index,
466 unsigned int *value)
467{
468 if (index >= PGGS_NUM_REGS)
469 return PM_RET_ERROR_ARGS;
470
471 return pm_mmio_read(PGGS_BASEADDR + (index << 2), value);
472}
473
474/**
Rajan Vaja5529a012018-01-17 02:39:23 -0800475 * pm_api_ioctl() - PM IOCTL API for device control and configs
476 * @node_id Node ID of the device
477 * @ioctl_id ID of the requested IOCTL
478 * @arg1 Argument 1 to requested IOCTL call
479 * @arg2 Argument 2 to requested IOCTL call
480 * @value Returned output value
481 *
482 * This function calls IOCTL to firmware for device control and configuration.
483 *
484 * @return Returns status, either success or error+reason
485 */
486enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
487 unsigned int ioctl_id,
488 unsigned int arg1,
489 unsigned int arg2,
490 unsigned int *value)
491{
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800492 enum pm_ret_status ret;
Rajan Vaja5529a012018-01-17 02:39:23 -0800493
494 switch (ioctl_id) {
495 case IOCTL_GET_RPU_OPER_MODE:
496 ret = pm_ioctl_get_rpu_oper_mode(value);
497 break;
498 case IOCTL_SET_RPU_OPER_MODE:
499 ret = pm_ioctl_set_rpu_oper_mode(arg1);
500 break;
501 case IOCTL_RPU_BOOT_ADDR_CONFIG:
502 ret = pm_ioctl_config_boot_addr(nid, arg1);
503 break;
504 case IOCTL_TCM_COMB_CONFIG:
505 ret = pm_ioctl_config_tcm_comb(arg1);
506 break;
Rajan Vajaaea41bb2018-01-17 02:39:24 -0800507 case IOCTL_SET_TAPDELAY_BYPASS:
508 ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2);
509 break;
510 case IOCTL_SET_SGMII_MODE:
511 ret = pm_ioctl_set_sgmii_mode(nid, arg1);
512 break;
513 case IOCTL_SD_DLL_RESET:
514 ret = pm_ioctl_sd_dll_reset(nid, arg1);
515 break;
516 case IOCTL_SET_SD_TAPDELAY:
517 ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2);
518 break;
Rajan Vaja35116132018-01-17 02:39:25 -0800519 case IOCTL_SET_PLL_FRAC_MODE:
520 ret = pm_ioctl_set_pll_frac_mode(arg1, arg2);
521 break;
522 case IOCTL_GET_PLL_FRAC_MODE:
523 ret = pm_ioctl_get_pll_frac_mode(arg1, value);
524 break;
525 case IOCTL_SET_PLL_FRAC_DATA:
526 ret = pm_ioctl_set_pll_frac_data(arg1, arg2);
527 break;
528 case IOCTL_GET_PLL_FRAC_DATA:
529 ret = pm_ioctl_get_pll_frac_data(arg1, value);
530 break;
Rajan Vaja393c0a22018-01-17 02:39:27 -0800531 case IOCTL_WRITE_GGS:
532 ret = pm_ioctl_write_ggs(arg1, arg2);
533 break;
534 case IOCTL_READ_GGS:
535 ret = pm_ioctl_read_ggs(arg1, value);
536 break;
537 case IOCTL_WRITE_PGGS:
538 ret = pm_ioctl_write_pggs(arg1, arg2);
539 break;
540 case IOCTL_READ_PGGS:
541 ret = pm_ioctl_read_pggs(arg1, value);
542 break;
Rajan Vaja5529a012018-01-17 02:39:23 -0800543 default:
544 ret = PM_RET_ERROR_NOTSUPPORTED;
Jolly Shah69fb5bf2018-02-07 16:25:41 -0800545 break;
Rajan Vaja5529a012018-01-17 02:39:23 -0800546 }
547
548 return ret;
549}