blob: 3ef0272875a6e5805682c7f30f6af1c1db95e5e6 [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;
37 if (val)
38 *mode = PM_RPU_MODE_SPLIT;
39 else
40 *mode = PM_RPU_MODE_LOCKSTEP;
41
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;
178 int ret;
179
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;
202 ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0);
203 } 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);
208 if (ret)
209 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;
234 int ret;
235
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);
250 if (ret)
251 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;
261 }
262
263 return ret;
264}
265
266/**
267 * pm_ioctl_sd_set_tapdelay() - Set tap delay for the SD device
268 * @nid Node ID of the device
269 * @type Type of tap delay to set (input/output)
270 * @value Value to set fot the tap delay
271 *
272 * This function sets input/output tap delay for the SD device.
273 *
274 * @return Returns status, either success or error+reason
275 */
276static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid,
277 enum tap_delay_type type,
278 unsigned int value)
279{
280 unsigned int shift;
281 int ret;
282
283 if (nid == NODE_SD_0)
284 shift = 0;
285 else if (nid == NODE_SD_1)
286 shift = ZYNQMP_SD_TAP_OFFSET;
287 else
288 return PM_RET_ERROR_ARGS;
289
290 ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT);
291 if (ret)
292 return ret;
293
294 if (type == PM_TAPDELAY_INPUT) {
295 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
296 ZYNQMP_SD_ITAPCHGWIN_MASK << shift,
297 ZYNQMP_SD_ITAPCHGWIN << shift);
298 if (ret)
299 goto reset_release;
300 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
301 ZYNQMP_SD_ITAPDLYENA_MASK << shift,
302 ZYNQMP_SD_ITAPDLYENA << shift);
303 if (ret)
304 goto reset_release;
305 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
306 ZYNQMP_SD_ITAPDLYSEL_MASK << shift,
307 value << shift);
308 if (ret)
309 goto reset_release;
310 ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
311 ZYNQMP_SD_ITAPCHGWIN_MASK << shift, 0);
312 } else if (type == PM_TAPDELAY_OUTPUT) {
313 ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
314 ZYNQMP_SD_OTAPDLYENA_MASK << shift,
315 ZYNQMP_SD_OTAPDLYENA << shift);
316 if (ret)
317 goto reset_release;
318 ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
319 ZYNQMP_SD_OTAPDLYSEL_MASK << shift,
320 value << shift);
321 } else {
322 ret = PM_RET_ERROR_ARGS;
323 }
324
325reset_release:
326 ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE);
327 if (ret)
328 return ret;
329
330 return ret;
331}
332
333/**
Rajan Vaja35116132018-01-17 02:39:25 -0800334 * pm_ioctl_set_pll_frac_mode() - Ioctl function for
335 * setting pll mode
336 * @pll PLL id
337 * @mode Mode fraction/integar
338 *
339 * This function sets PLL mode
340 *
341 * @return Returns status, either success or error+reason
342 */
343static enum pm_ret_status pm_ioctl_set_pll_frac_mode
344 (unsigned int pll, unsigned int mode)
345{
346 return pm_api_clk_set_pll_mode(pll, mode);
347}
348
349/**
350 * pm_ioctl_get_pll_frac_mode() - Ioctl function for
351 * getting pll mode
352 * @pll PLL id
353 * @mode Mode fraction/integar
354 *
355 * This function return current PLL mode
356 *
357 * @return Returns status, either success or error+reason
358 */
359static enum pm_ret_status pm_ioctl_get_pll_frac_mode
360 (unsigned int pll, unsigned int *mode)
361{
362 return pm_api_clk_get_pll_mode(pll, mode);
363}
364
365/**
366 * pm_ioctl_set_pll_frac_data() - Ioctl function for
367 * setting pll fraction data
368 * @pll PLL id
369 * @data fraction data
370 *
371 * This function sets fraction data.
372 * It is valid for fraction mode only.
373 *
374 * @return Returns status, either success or error+reason
375 */
376static enum pm_ret_status pm_ioctl_set_pll_frac_data
377 (unsigned int pll, unsigned int data)
378{
379 return pm_api_clk_set_pll_frac_data(pll, data);
380}
381
382/**
383 * pm_ioctl_get_pll_frac_data() - Ioctl function for
384 * getting pll fraction data
385 * @pll PLL id
386 * @data fraction data
387 *
388 * This function returns fraction data value.
389 *
390 * @return Returns status, either success or error+reason
391 */
392static enum pm_ret_status pm_ioctl_get_pll_frac_data
393 (unsigned int pll, unsigned int *data)
394{
395 return pm_api_clk_get_pll_frac_data(pll, data);
396}
397
398/**
Rajan Vaja393c0a22018-01-17 02:39:27 -0800399 * pm_ioctl_write_ggs() - Ioctl function for writing
400 * global general storage (ggs)
401 * @index GGS register index
402 * @value Register value to be written
403 *
404 * This function writes value to GGS register.
405 *
406 * @return Returns status, either success or error+reason
407 */
408static enum pm_ret_status pm_ioctl_write_ggs(unsigned int index,
409 unsigned int value)
410{
411 if (index >= GGS_NUM_REGS)
412 return PM_RET_ERROR_ARGS;
413
414 return pm_mmio_write(GGS_BASEADDR + (index << 2), 0xFFFFFFFF, value);
415}
416
417/**
418 * pm_ioctl_read_ggs() - Ioctl function for reading
419 * global general storage (ggs)
420 * @index GGS register index
421 * @value Register value
422 *
423 * This function returns GGS register value.
424 *
425 * @return Returns status, either success or error+reason
426 */
427static enum pm_ret_status pm_ioctl_read_ggs(unsigned int index,
428 unsigned int *value)
429{
430 if (index >= GGS_NUM_REGS)
431 return PM_RET_ERROR_ARGS;
432
433 return pm_mmio_read(GGS_BASEADDR + (index << 2), value);
434}
435
436/**
437 * pm_ioctl_write_pggs() - Ioctl function for writing persistent
438 * global general storage (pggs)
439 * @index PGGS register index
440 * @value Register value to be written
441 *
442 * This function writes value to PGGS register.
443 *
444 * @return Returns status, either success or error+reason
445 */
446static enum pm_ret_status pm_ioctl_write_pggs(unsigned int index,
447 unsigned int value)
448{
449 if (index >= PGGS_NUM_REGS)
450 return PM_RET_ERROR_ARGS;
451
452 return pm_mmio_write(PGGS_BASEADDR + (index << 2), 0xFFFFFFFF, value);
453}
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{
492 int ret;
493
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;
545 }
546
547 return ret;
548}