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