1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * Copyright (c) 2025 Linaro Ltd 5 */ 6 7 #include <linux/iopoll.h> 8 #include <linux/reset.h> 9 10 #include "iris_instance.h" 11 #include "iris_vpu_common.h" 12 #include "iris_vpu_register_defines.h" 13 14 #define AON_WRAPPER_MVP_NOC_CORE_SW_RESET (AON_BASE_OFFS + 0x18) 15 #define SW_RESET BIT(0) 16 #define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) 17 #define NOC_HALT BIT(0) 18 #define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) 19 20 static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core) 21 { 22 u32 value, pwr_status; 23 24 value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); 25 pwr_status = value & BIT(1); 26 27 return pwr_status ? false : true; 28 } 29 30 static void iris_vpu3_power_off_hardware(struct iris_core *core) 31 { 32 u32 reg_val = 0, value, i; 33 int ret; 34 35 if (iris_vpu3x_hw_power_collapsed(core)) 36 goto disable_power; 37 38 dev_err(core->dev, "video hw is power on\n"); 39 40 value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); 41 if (value) 42 writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); 43 44 for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { 45 ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i, 46 reg_val, reg_val & 0x400000, 2000, 20000); 47 if (ret) 48 goto disable_power; 49 } 50 51 writel(VIDEO_NOC_RESET_REQ, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); 52 53 ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, 54 reg_val, reg_val & 0x3, 200, 2000); 55 if (ret) 56 goto disable_power; 57 58 writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); 59 60 ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, 61 reg_val, !(reg_val & 0x3), 200, 2000); 62 if (ret) 63 goto disable_power; 64 65 writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, 66 core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 67 writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 68 writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 69 70 disable_power: 71 iris_vpu_power_off_hw(core); 72 } 73 74 static void iris_vpu33_power_off_hardware(struct iris_core *core) 75 { 76 bool handshake_done = false, handshake_busy = false; 77 u32 reg_val = 0, value, i; 78 u32 count = 0; 79 int ret; 80 81 if (iris_vpu3x_hw_power_collapsed(core)) 82 goto disable_power; 83 84 dev_err(core->dev, "video hw is power on\n"); 85 86 value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); 87 if (value) 88 writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); 89 90 for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { 91 ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i, 92 reg_val, reg_val & 0x400000, 2000, 20000); 93 if (ret) 94 goto disable_power; 95 } 96 97 /* Retry up to 1000 times as recommended by hardware documentation */ 98 do { 99 /* set MNoC to low power */ 100 writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); 101 102 udelay(15); 103 104 value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS); 105 106 handshake_done = value & NOC_LPI_STATUS_DONE; 107 handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); 108 109 if (handshake_done || !handshake_busy) 110 break; 111 112 writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); 113 114 udelay(15); 115 116 } while (++count < 1000); 117 118 if (!handshake_done && handshake_busy) 119 dev_err(core->dev, "LPI handshake timeout\n"); 120 121 ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, 122 reg_val, reg_val & BIT(0), 200, 2000); 123 if (ret) 124 goto disable_power; 125 126 writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); 127 128 writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, 129 core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 130 writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 131 writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); 132 133 disable_power: 134 iris_vpu_power_off_hw(core); 135 } 136 137 static int iris_vpu33_power_off_controller(struct iris_core *core) 138 { 139 u32 xo_rst_tbl_size = core->iris_platform_data->controller_rst_tbl_size; 140 u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; 141 u32 val = 0; 142 int ret; 143 144 writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); 145 146 writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); 147 148 ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, 149 val, val & BIT(0), 200, 2000); 150 if (ret) 151 goto disable_power; 152 153 writel(0x0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); 154 155 ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, 156 val, val == 0, 200, 2000); 157 if (ret) 158 goto disable_power; 159 160 writel(CTL_AXI_CLK_HALT | CTL_CLK_HALT, 161 core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); 162 writel(RESET_HIGH, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET); 163 writel(0x0, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET); 164 writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); 165 166 reset_control_bulk_reset(clk_rst_tbl_size, core->resets); 167 168 /* Disable MVP NoC clock */ 169 val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); 170 val |= NOC_HALT; 171 writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); 172 173 /* enable MVP NoC reset */ 174 val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); 175 val |= SW_RESET; 176 writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); 177 178 /* poll AON spare register bit0 to become zero with 50ms timeout */ 179 ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_SPARE, 180 val, (val & BIT(0)) == 0, 1000, 50000); 181 if (ret) 182 goto disable_power; 183 184 /* enable bit(1) to avoid cvp noc xo reset */ 185 val = readl(core->reg_base + AON_WRAPPER_SPARE); 186 val |= BIT(1); 187 writel(val, core->reg_base + AON_WRAPPER_SPARE); 188 189 reset_control_bulk_assert(xo_rst_tbl_size, core->controller_resets); 190 191 /* De-assert MVP NoC reset */ 192 val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); 193 val &= ~SW_RESET; 194 writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); 195 196 usleep_range(80, 100); 197 198 reset_control_bulk_deassert(xo_rst_tbl_size, core->controller_resets); 199 200 /* reset AON spare register */ 201 writel(0, core->reg_base + AON_WRAPPER_SPARE); 202 203 /* Enable MVP NoC clock */ 204 val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); 205 val &= ~NOC_HALT; 206 writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); 207 208 iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); 209 210 disable_power: 211 iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); 212 iris_disable_unprepare_clock(core, IRIS_AXI_CLK); 213 214 return 0; 215 } 216 217 static int iris_vpu35_power_on_hw(struct iris_core *core) 218 { 219 int ret; 220 221 ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); 222 if (ret) 223 return ret; 224 225 ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK); 226 if (ret) 227 goto err_disable_power; 228 229 ret = iris_prepare_enable_clock(core, IRIS_HW_FREERUN_CLK); 230 if (ret) 231 goto err_disable_axi_clk; 232 233 ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); 234 if (ret) 235 goto err_disable_hw_free_clk; 236 237 ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); 238 if (ret) 239 goto err_disable_hw_clk; 240 241 return 0; 242 243 err_disable_hw_clk: 244 iris_disable_unprepare_clock(core, IRIS_HW_CLK); 245 err_disable_hw_free_clk: 246 iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); 247 err_disable_axi_clk: 248 iris_disable_unprepare_clock(core, IRIS_AXI_CLK); 249 err_disable_power: 250 iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); 251 252 return ret; 253 } 254 255 static void iris_vpu35_power_off_hw(struct iris_core *core) 256 { 257 iris_vpu33_power_off_hardware(core); 258 259 iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); 260 iris_disable_unprepare_clock(core, IRIS_AXI_CLK); 261 } 262 263 const struct vpu_ops iris_vpu3_ops = { 264 .power_off_hw = iris_vpu3_power_off_hardware, 265 .power_on_hw = iris_vpu_power_on_hw, 266 .power_off_controller = iris_vpu_power_off_controller, 267 .power_on_controller = iris_vpu_power_on_controller, 268 .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, 269 }; 270 271 const struct vpu_ops iris_vpu33_ops = { 272 .power_off_hw = iris_vpu33_power_off_hardware, 273 .power_on_hw = iris_vpu_power_on_hw, 274 .power_off_controller = iris_vpu33_power_off_controller, 275 .power_on_controller = iris_vpu_power_on_controller, 276 .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, 277 }; 278 279 const struct vpu_ops iris_vpu35_ops = { 280 .power_off_hw = iris_vpu35_power_off_hw, 281 .power_on_hw = iris_vpu35_power_on_hw, 282 .power_off_controller = iris_vpu35_vpu4x_power_off_controller, 283 .power_on_controller = iris_vpu35_vpu4x_power_on_controller, 284 .program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers, 285 .calc_freq = iris_vpu3x_vpu4x_calculate_frequency, 286 }; 287