1 /* 2 * Copyright 2021-2024 NXP 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 #include <inttypes.h> 7 #include <lib/libc/errno.h> 8 #include <stdint.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include <common/debug.h> 13 #include <drivers/scmi.h> 14 #include <lib/mmio.h> 15 #include <lib/utils_def.h> 16 #include <platform_def.h> 17 #include <scmi.h> 18 19 #include <upower_api.h> 20 21 #define POWER_STATE_ON (0 << 30) 22 #define POWER_STATE_OFF (1 << 30) 23 24 extern bool is_lpav_owned_by_apd(void); 25 26 enum { 27 PS0 = 0, 28 PS1 = 1, 29 PS2 = 2, 30 PS3 = 3, 31 PS4 = 4, 32 PS5 = 5, 33 PS6 = 6, 34 PS7 = 7, 35 PS8 = 8, 36 PS9 = 9, 37 PS10 = 10, 38 PS11 = 11, 39 PS12 = 12, 40 PS13 = 13, 41 PS14 = 14, 42 PS15 = 15, 43 PS16 = 16, 44 PS17 = 17, 45 PS18 = 18, 46 PS19 = 19, 47 }; 48 49 #define SRAM_DMA1 BIT(6) 50 #define SRAM_FLEXSPI2 BIT(7) 51 #define SRAM_USB0 BIT(10) 52 #define SRAM_USDHC0 BIT(11) 53 #define SRAM_USDHC1 BIT(12) 54 #define SRAM_USDHC2_USB1 BIT(13) 55 #define SRAM_DCNANO GENMASK_32(18, 17) 56 #define SRAM_EPDC GENMASK_32(20, 19) 57 #define SRAM_DMA2 BIT(21) 58 #define SRAM_GPU2D GENMASK_32(23, 22) 59 #define SRAM_GPU3D GENMASK_32(25, 24) 60 #define SRAM_HIFI4 BIT(26) 61 #define SRAM_ISI_BUFFER BIT(27) 62 #define SRAM_MIPI_CSI_FIFO BIT(28) 63 #define SRAM_MIPI_DSI_FIFO BIT(29) 64 #define SRAM_PXP BIT(30) 65 66 #define SRAM_DMA0 BIT_64(33) 67 #define SRAM_FLEXCAN BIT_64(34) 68 #define SRAM_FLEXSPI0 BIT_64(35) 69 #define SRAM_FLEXSPI1 BIT_64(36) 70 71 struct psw { 72 char *name; 73 uint32_t reg; 74 int power_state; 75 uint32_t count; 76 int flags; 77 }; 78 79 #define ALWAYS_ON BIT(0) 80 81 static struct psw imx8ulp_psw[] = { 82 [PS6] = { .name = "PS6", .reg = PS6, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON }, 83 [PS7] = { .name = "PS7", .reg = PS7, .power_state = POWER_STATE_OFF }, 84 [PS8] = { .name = "PS8", .reg = PS8, .power_state = POWER_STATE_OFF }, 85 [PS13] = { .name = "PS13", .reg = PS13, .power_state = POWER_STATE_OFF }, 86 [PS14] = { .name = "PS14", .reg = PS14, .flags = ALWAYS_ON, .power_state = POWER_STATE_OFF }, 87 [PS15] = { .name = "PS15", .reg = PS15, .power_state = POWER_STATE_OFF }, 88 [PS16] = { .name = "PS16", .reg = PS16, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON }, 89 }; 90 91 struct power_domain { 92 char *name; 93 uint32_t reg; 94 uint32_t psw_parent; 95 uint32_t sram_parent; 96 uint64_t bits; 97 uint32_t power_state; 98 bool lpav; /* belong to lpav domain */ 99 uint32_t sw_rst_reg; /* pcc sw reset reg offset */ 100 }; 101 102 /* The Rich OS need flow the macro */ 103 #define IMX8ULP_PD_DMA1 0 104 #define IMX8ULP_PD_FLEXSPI2 1 105 #define IMX8ULP_PD_USB0 2 106 #define IMX8ULP_PD_USDHC0 3 107 #define IMX8ULP_PD_USDHC1 4 108 #define IMX8ULP_PD_USDHC2_USB1 5 109 #define IMX8ULP_PD_DCNANO 6 110 #define IMX8ULP_PD_EPDC 7 111 #define IMX8ULP_PD_DMA2 8 112 #define IMX8ULP_PD_GPU2D 9 113 #define IMX8ULP_PD_GPU3D 10 114 #define IMX8ULP_PD_HIFI4 11 115 #define IMX8ULP_PD_ISI 12 116 #define IMX8ULP_PD_MIPI_CSI 13 117 #define IMX8ULP_PD_MIPI_DSI 14 118 #define IMX8ULP_PD_PXP 15 119 120 #define IMX8ULP_PD_PS6 16 121 #define IMX8ULP_PD_PS7 17 122 #define IMX8ULP_PD_PS8 18 123 #define IMX8ULP_PD_PS13 19 124 #define IMX8ULP_PD_PS14 20 125 #define IMX8ULP_PD_PS15 21 126 #define IMX8ULP_PD_PS16 22 127 #define IMX8ULP_PD_MAX 23 128 129 /* LPAV peripheral PCC */ 130 #define PCC_GPU2D (IMX_PCC5_BASE + 0xf0) 131 #define PCC_GPU3D (IMX_PCC5_BASE + 0xf4) 132 #define PCC_EPDC (IMX_PCC5_BASE + 0xcc) 133 #define PCC_CSI (IMX_PCC5_BASE + 0xbc) 134 #define PCC_PXP (IMX_PCC5_BASE + 0xd0) 135 136 #define PCC_SW_RST BIT(28) 137 138 #define PWR_DOMAIN(_name, _reg, _psw_parent, _sram_parent, \ 139 _bits, _state, _lpav, _rst_reg) \ 140 { \ 141 .name = _name, \ 142 .reg = _reg, \ 143 .psw_parent = _psw_parent, \ 144 .sram_parent = _sram_parent, \ 145 .bits = _bits, \ 146 .power_state = _state, \ 147 .lpav = _lpav, \ 148 .sw_rst_reg = _rst_reg, \ 149 } 150 151 static struct power_domain scmi_power_domains[] = { 152 PWR_DOMAIN("DMA1", IMX8ULP_PD_DMA1, PS6, PS6, SRAM_DMA1, POWER_STATE_OFF, false, 0U), 153 PWR_DOMAIN("FLEXSPI2", IMX8ULP_PD_FLEXSPI2, PS6, PS6, SRAM_FLEXSPI2, POWER_STATE_OFF, false, 0U), 154 PWR_DOMAIN("USB0", IMX8ULP_PD_USB0, PS6, PS6, SRAM_USB0, POWER_STATE_OFF, false, 0U), 155 PWR_DOMAIN("USDHC0", IMX8ULP_PD_USDHC0, PS6, PS6, SRAM_USDHC0, POWER_STATE_OFF, false, 0U), 156 PWR_DOMAIN("USDHC1", IMX8ULP_PD_USDHC1, PS6, PS6, SRAM_USDHC1, POWER_STATE_OFF, false, 0U), 157 PWR_DOMAIN("USDHC2_USB1", IMX8ULP_PD_USDHC2_USB1, PS6, PS6, SRAM_USDHC2_USB1, POWER_STATE_OFF, false, 0U), 158 PWR_DOMAIN("DCNano", IMX8ULP_PD_DCNANO, PS16, PS16, SRAM_DCNANO, POWER_STATE_OFF, true, 0U), 159 PWR_DOMAIN("EPDC", IMX8ULP_PD_EPDC, PS13, PS13, SRAM_EPDC, POWER_STATE_OFF, true, PCC_EPDC), 160 PWR_DOMAIN("DMA2", IMX8ULP_PD_DMA2, PS16, PS16, SRAM_DMA2, POWER_STATE_OFF, true, 0U), 161 PWR_DOMAIN("GPU2D", IMX8ULP_PD_GPU2D, PS16, PS16, SRAM_GPU2D, POWER_STATE_OFF, true, PCC_GPU2D), 162 PWR_DOMAIN("GPU3D", IMX8ULP_PD_GPU3D, PS7, PS7, SRAM_GPU3D, POWER_STATE_OFF, true, PCC_GPU3D), 163 PWR_DOMAIN("HIFI4", IMX8ULP_PD_HIFI4, PS8, PS8, SRAM_HIFI4, POWER_STATE_OFF, true, 0U), 164 PWR_DOMAIN("ISI", IMX8ULP_PD_ISI, PS16, PS16, SRAM_ISI_BUFFER, POWER_STATE_OFF, true, 0U), 165 PWR_DOMAIN("MIPI_CSI", IMX8ULP_PD_MIPI_CSI, PS15, PS16, SRAM_MIPI_CSI_FIFO, POWER_STATE_OFF, true, PCC_CSI), 166 PWR_DOMAIN("MIPI_DSI", IMX8ULP_PD_MIPI_DSI, PS14, PS16, SRAM_MIPI_DSI_FIFO, POWER_STATE_OFF, true, 0U), 167 PWR_DOMAIN("PXP", IMX8ULP_PD_PXP, PS13, PS13, SRAM_PXP | SRAM_EPDC, POWER_STATE_OFF, true, PCC_PXP) 168 }; 169 170 size_t plat_scmi_pd_count(unsigned int agent_id __unused) 171 { 172 return ARRAY_SIZE(scmi_power_domains); 173 } 174 175 const char *plat_scmi_pd_get_name(unsigned int agent_id __unused, 176 unsigned int pd_id) 177 { 178 if (pd_id >= IMX8ULP_PD_PS6) { 179 return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].name; 180 } 181 182 return scmi_power_domains[pd_id].name; 183 } 184 185 unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused, 186 unsigned int pd_id __unused) 187 { 188 if (pd_id >= IMX8ULP_PD_PS6) { 189 return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].power_state; 190 } 191 192 return scmi_power_domains[pd_id].power_state; 193 } 194 195 extern void upower_wait_resp(void); 196 int upwr_pwm_power(const uint32_t swton[], const uint32_t memon[], bool on) 197 { 198 int ret_val; 199 int ret; 200 201 if (on == true) { 202 ret = upwr_pwm_power_on(swton, memon, NULL); 203 } else { 204 ret = upwr_pwm_power_off(swton, memon, NULL); 205 } 206 207 if (ret != 0U) { 208 WARN("%s failed: ret: %d, state: %x\n", __func__, ret, on); 209 return ret; 210 } 211 212 upower_wait_resp(); 213 214 ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000); 215 if (ret != UPWR_REQ_OK) { 216 WARN("Failure %d, %s\n", ret, __func__); 217 if (ret == UPWR_REQ_BUSY) { 218 return -EBUSY; 219 } else { 220 return -EINVAL; 221 } 222 } 223 224 return 0; 225 } 226 227 int32_t plat_scmi_pd_psw(unsigned int index, unsigned int state) 228 { 229 uint32_t psw_parent = scmi_power_domains[index].psw_parent; 230 uint32_t sram_parent = scmi_power_domains[index].sram_parent; 231 uint64_t swt; 232 bool on; 233 int ret = 0; 234 235 if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) != 0U && 236 (imx8ulp_psw[sram_parent].flags & ALWAYS_ON) != 0U) { 237 return 0; 238 } 239 240 on = (state == POWER_STATE_ON) ? true : false; 241 242 if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) == 0U) { 243 swt = 1 << imx8ulp_psw[psw_parent].reg; 244 if (imx8ulp_psw[psw_parent].count == 0U) { 245 if (on == false) { 246 WARN("off PSW[%d] that already in off state\n", psw_parent); 247 ret = -EACCES; 248 } else { 249 ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on); 250 imx8ulp_psw[psw_parent].count++; 251 } 252 } else { 253 if (on == true) { 254 imx8ulp_psw[psw_parent].count++; 255 } else { 256 imx8ulp_psw[psw_parent].count--; 257 } 258 259 if (imx8ulp_psw[psw_parent].count == 0U) { 260 ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on); 261 } 262 } 263 } 264 265 if (!(imx8ulp_psw[sram_parent].flags & ALWAYS_ON) && (psw_parent != sram_parent)) { 266 swt = 1 << imx8ulp_psw[sram_parent].reg; 267 if (imx8ulp_psw[sram_parent].count == 0U) { 268 if (on == false) { 269 WARN("off PSW[%d] that already in off state\n", sram_parent); 270 ret = -EACCES; 271 } else { 272 ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on); 273 imx8ulp_psw[sram_parent].count++; 274 } 275 } else { 276 if (on == true) { 277 imx8ulp_psw[sram_parent].count++; 278 } else { 279 imx8ulp_psw[sram_parent].count--; 280 } 281 282 if (imx8ulp_psw[sram_parent].count == 0U) { 283 ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on); 284 } 285 } 286 } 287 288 return ret; 289 } 290 291 bool pd_allow_power_off(unsigned int pd_id) 292 { 293 if (scmi_power_domains[pd_id].lpav) { 294 if (!is_lpav_owned_by_apd()) { 295 return false; 296 } 297 } 298 299 return true; 300 } 301 302 void assert_pcc_reset(unsigned int pcc) 303 { 304 /* if sw_rst_reg is valid, assert the pcc reset */ 305 if (pcc != 0U) { 306 mmio_clrbits_32(pcc, PCC_SW_RST); 307 } 308 } 309 310 int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused, 311 unsigned int flags, 312 unsigned int pd_id, 313 unsigned int state) 314 { 315 unsigned int ps_idx; 316 uint64_t mem; 317 bool on; 318 int ret; 319 320 if (flags != 0U || pd_id >= IMX8ULP_PD_PS6) { 321 return SCMI_NOT_SUPPORTED; 322 } 323 324 ps_idx = 0; 325 while (ps_idx < IMX8ULP_PD_PS6 && scmi_power_domains[ps_idx].reg != pd_id) { 326 ps_idx++; 327 } 328 329 if (ps_idx == IMX8ULP_PD_PS6) { 330 return SCMI_NOT_FOUND; 331 } 332 333 if (state == scmi_power_domains[ps_idx].power_state) { 334 return SCMI_SUCCESS; 335 } 336 337 mem = scmi_power_domains[ps_idx].bits; 338 on = (state == POWER_STATE_ON ? true : false); 339 if (on == true) { 340 /* Assert pcc sw reset if necessary */ 341 assert_pcc_reset(scmi_power_domains[ps_idx].sw_rst_reg); 342 343 ret = plat_scmi_pd_psw(ps_idx, state); 344 if (ret != 0U) { 345 return SCMI_DENIED; 346 } 347 348 ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on); 349 if (ret != 0U) { 350 return SCMI_DENIED; 351 } 352 } else { 353 if (!pd_allow_power_off(ps_idx)) { 354 return SCMI_DENIED; 355 } 356 357 ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on); 358 if (ret != 0U) { 359 return SCMI_DENIED; 360 } 361 362 ret = plat_scmi_pd_psw(ps_idx, state); 363 if (ret != 0U) { 364 return SCMI_DENIED; 365 } 366 } 367 368 scmi_power_domains[pd_id].power_state = state; 369 370 return SCMI_SUCCESS; 371 } 372