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