| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de> |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | #include <linux/clk.h> |
|---|
| 14 | 6 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 29 | 21 | #include <dt-bindings/power/mt8173-power.h> |
|---|
| 30 | 22 | |
|---|
| 31 | 23 | #define MTK_POLL_DELAY_US 10 |
|---|
| 32 | | -#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ)) |
|---|
| 24 | +#define MTK_POLL_TIMEOUT USEC_PER_SEC |
|---|
| 33 | 25 | |
|---|
| 34 | 26 | #define MTK_SCPD_ACTIVE_WAKEUP BIT(0) |
|---|
| 35 | 27 | #define MTK_SCPD_FWAIT_SRAM BIT(1) |
|---|
| .. | .. |
|---|
| 116 | 108 | |
|---|
| 117 | 109 | #define MAX_CLKS 3 |
|---|
| 118 | 110 | |
|---|
| 111 | +/** |
|---|
| 112 | + * struct scp_domain_data - scp domain data for power on/off flow |
|---|
| 113 | + * @name: The domain name. |
|---|
| 114 | + * @sta_mask: The mask for power on/off status bit. |
|---|
| 115 | + * @ctl_offs: The offset for main power control register. |
|---|
| 116 | + * @sram_pdn_bits: The mask for sram power control bits. |
|---|
| 117 | + * @sram_pdn_ack_bits: The mask for sram power control acked bits. |
|---|
| 118 | + * @bus_prot_mask: The mask for single step bus protection. |
|---|
| 119 | + * @clk_id: The basic clocks required by this power domain. |
|---|
| 120 | + * @caps: The flag for active wake-up action. |
|---|
| 121 | + */ |
|---|
| 119 | 122 | struct scp_domain_data { |
|---|
| 120 | 123 | const char *name; |
|---|
| 121 | 124 | u32 sta_mask; |
|---|
| .. | .. |
|---|
| 188 | 191 | return -EINVAL; |
|---|
| 189 | 192 | } |
|---|
| 190 | 193 | |
|---|
| 194 | +static int scpsys_regulator_enable(struct scp_domain *scpd) |
|---|
| 195 | +{ |
|---|
| 196 | + if (!scpd->supply) |
|---|
| 197 | + return 0; |
|---|
| 198 | + |
|---|
| 199 | + return regulator_enable(scpd->supply); |
|---|
| 200 | +} |
|---|
| 201 | + |
|---|
| 202 | +static int scpsys_regulator_disable(struct scp_domain *scpd) |
|---|
| 203 | +{ |
|---|
| 204 | + if (!scpd->supply) |
|---|
| 205 | + return 0; |
|---|
| 206 | + |
|---|
| 207 | + return regulator_disable(scpd->supply); |
|---|
| 208 | +} |
|---|
| 209 | + |
|---|
| 210 | +static void scpsys_clk_disable(struct clk *clk[], int max_num) |
|---|
| 211 | +{ |
|---|
| 212 | + int i; |
|---|
| 213 | + |
|---|
| 214 | + for (i = max_num - 1; i >= 0; i--) |
|---|
| 215 | + clk_disable_unprepare(clk[i]); |
|---|
| 216 | +} |
|---|
| 217 | + |
|---|
| 218 | +static int scpsys_clk_enable(struct clk *clk[], int max_num) |
|---|
| 219 | +{ |
|---|
| 220 | + int i, ret = 0; |
|---|
| 221 | + |
|---|
| 222 | + for (i = 0; i < max_num && clk[i]; i++) { |
|---|
| 223 | + ret = clk_prepare_enable(clk[i]); |
|---|
| 224 | + if (ret) { |
|---|
| 225 | + scpsys_clk_disable(clk, i); |
|---|
| 226 | + break; |
|---|
| 227 | + } |
|---|
| 228 | + } |
|---|
| 229 | + |
|---|
| 230 | + return ret; |
|---|
| 231 | +} |
|---|
| 232 | + |
|---|
| 233 | +static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr) |
|---|
| 234 | +{ |
|---|
| 235 | + u32 val; |
|---|
| 236 | + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; |
|---|
| 237 | + int tmp; |
|---|
| 238 | + |
|---|
| 239 | + val = readl(ctl_addr); |
|---|
| 240 | + val &= ~scpd->data->sram_pdn_bits; |
|---|
| 241 | + writel(val, ctl_addr); |
|---|
| 242 | + |
|---|
| 243 | + /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ |
|---|
| 244 | + if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { |
|---|
| 245 | + /* |
|---|
| 246 | + * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for |
|---|
| 247 | + * MT7622_POWER_DOMAIN_WB and thus just a trivial setup |
|---|
| 248 | + * is applied here. |
|---|
| 249 | + */ |
|---|
| 250 | + usleep_range(12000, 12100); |
|---|
| 251 | + } else { |
|---|
| 252 | + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ |
|---|
| 253 | + int ret = readl_poll_timeout(ctl_addr, tmp, |
|---|
| 254 | + (tmp & pdn_ack) == 0, |
|---|
| 255 | + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); |
|---|
| 256 | + if (ret < 0) |
|---|
| 257 | + return ret; |
|---|
| 258 | + } |
|---|
| 259 | + |
|---|
| 260 | + return 0; |
|---|
| 261 | +} |
|---|
| 262 | + |
|---|
| 263 | +static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr) |
|---|
| 264 | +{ |
|---|
| 265 | + u32 val; |
|---|
| 266 | + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; |
|---|
| 267 | + int tmp; |
|---|
| 268 | + |
|---|
| 269 | + val = readl(ctl_addr); |
|---|
| 270 | + val |= scpd->data->sram_pdn_bits; |
|---|
| 271 | + writel(val, ctl_addr); |
|---|
| 272 | + |
|---|
| 273 | + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ |
|---|
| 274 | + return readl_poll_timeout(ctl_addr, tmp, |
|---|
| 275 | + (tmp & pdn_ack) == pdn_ack, |
|---|
| 276 | + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); |
|---|
| 277 | +} |
|---|
| 278 | + |
|---|
| 279 | +static int scpsys_bus_protect_enable(struct scp_domain *scpd) |
|---|
| 280 | +{ |
|---|
| 281 | + struct scp *scp = scpd->scp; |
|---|
| 282 | + |
|---|
| 283 | + if (!scpd->data->bus_prot_mask) |
|---|
| 284 | + return 0; |
|---|
| 285 | + |
|---|
| 286 | + return mtk_infracfg_set_bus_protection(scp->infracfg, |
|---|
| 287 | + scpd->data->bus_prot_mask, |
|---|
| 288 | + scp->bus_prot_reg_update); |
|---|
| 289 | +} |
|---|
| 290 | + |
|---|
| 291 | +static int scpsys_bus_protect_disable(struct scp_domain *scpd) |
|---|
| 292 | +{ |
|---|
| 293 | + struct scp *scp = scpd->scp; |
|---|
| 294 | + |
|---|
| 295 | + if (!scpd->data->bus_prot_mask) |
|---|
| 296 | + return 0; |
|---|
| 297 | + |
|---|
| 298 | + return mtk_infracfg_clear_bus_protection(scp->infracfg, |
|---|
| 299 | + scpd->data->bus_prot_mask, |
|---|
| 300 | + scp->bus_prot_reg_update); |
|---|
| 301 | +} |
|---|
| 302 | + |
|---|
| 191 | 303 | static int scpsys_power_on(struct generic_pm_domain *genpd) |
|---|
| 192 | 304 | { |
|---|
| 193 | 305 | struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); |
|---|
| 194 | 306 | struct scp *scp = scpd->scp; |
|---|
| 195 | 307 | void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; |
|---|
| 196 | | - u32 pdn_ack = scpd->data->sram_pdn_ack_bits; |
|---|
| 197 | 308 | u32 val; |
|---|
| 198 | 309 | int ret, tmp; |
|---|
| 199 | | - int i; |
|---|
| 200 | 310 | |
|---|
| 201 | | - if (scpd->supply) { |
|---|
| 202 | | - ret = regulator_enable(scpd->supply); |
|---|
| 203 | | - if (ret) |
|---|
| 204 | | - return ret; |
|---|
| 205 | | - } |
|---|
| 311 | + ret = scpsys_regulator_enable(scpd); |
|---|
| 312 | + if (ret < 0) |
|---|
| 313 | + return ret; |
|---|
| 206 | 314 | |
|---|
| 207 | | - for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) { |
|---|
| 208 | | - ret = clk_prepare_enable(scpd->clk[i]); |
|---|
| 209 | | - if (ret) { |
|---|
| 210 | | - for (--i; i >= 0; i--) |
|---|
| 211 | | - clk_disable_unprepare(scpd->clk[i]); |
|---|
| 315 | + ret = scpsys_clk_enable(scpd->clk, MAX_CLKS); |
|---|
| 316 | + if (ret) |
|---|
| 317 | + goto err_clk; |
|---|
| 212 | 318 | |
|---|
| 213 | | - goto err_clk; |
|---|
| 214 | | - } |
|---|
| 215 | | - } |
|---|
| 216 | | - |
|---|
| 319 | + /* subsys power on */ |
|---|
| 217 | 320 | val = readl(ctl_addr); |
|---|
| 218 | 321 | val |= PWR_ON_BIT; |
|---|
| 219 | 322 | writel(val, ctl_addr); |
|---|
| .. | .. |
|---|
| 235 | 338 | val |= PWR_RST_B_BIT; |
|---|
| 236 | 339 | writel(val, ctl_addr); |
|---|
| 237 | 340 | |
|---|
| 238 | | - val &= ~scpd->data->sram_pdn_bits; |
|---|
| 239 | | - writel(val, ctl_addr); |
|---|
| 341 | + ret = scpsys_sram_enable(scpd, ctl_addr); |
|---|
| 342 | + if (ret < 0) |
|---|
| 343 | + goto err_pwr_ack; |
|---|
| 240 | 344 | |
|---|
| 241 | | - /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ |
|---|
| 242 | | - if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { |
|---|
| 243 | | - /* |
|---|
| 244 | | - * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for |
|---|
| 245 | | - * MT7622_POWER_DOMAIN_WB and thus just a trivial setup is |
|---|
| 246 | | - * applied here. |
|---|
| 247 | | - */ |
|---|
| 248 | | - usleep_range(12000, 12100); |
|---|
| 249 | | - |
|---|
| 250 | | - } else { |
|---|
| 251 | | - ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0, |
|---|
| 252 | | - MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); |
|---|
| 253 | | - if (ret < 0) |
|---|
| 254 | | - goto err_pwr_ack; |
|---|
| 255 | | - } |
|---|
| 256 | | - |
|---|
| 257 | | - if (scpd->data->bus_prot_mask) { |
|---|
| 258 | | - ret = mtk_infracfg_clear_bus_protection(scp->infracfg, |
|---|
| 259 | | - scpd->data->bus_prot_mask, |
|---|
| 260 | | - scp->bus_prot_reg_update); |
|---|
| 261 | | - if (ret) |
|---|
| 262 | | - goto err_pwr_ack; |
|---|
| 263 | | - } |
|---|
| 345 | + ret = scpsys_bus_protect_disable(scpd); |
|---|
| 346 | + if (ret < 0) |
|---|
| 347 | + goto err_pwr_ack; |
|---|
| 264 | 348 | |
|---|
| 265 | 349 | return 0; |
|---|
| 266 | 350 | |
|---|
| 267 | 351 | err_pwr_ack: |
|---|
| 268 | | - for (i = MAX_CLKS - 1; i >= 0; i--) { |
|---|
| 269 | | - if (scpd->clk[i]) |
|---|
| 270 | | - clk_disable_unprepare(scpd->clk[i]); |
|---|
| 271 | | - } |
|---|
| 352 | + scpsys_clk_disable(scpd->clk, MAX_CLKS); |
|---|
| 272 | 353 | err_clk: |
|---|
| 273 | | - if (scpd->supply) |
|---|
| 274 | | - regulator_disable(scpd->supply); |
|---|
| 354 | + scpsys_regulator_disable(scpd); |
|---|
| 275 | 355 | |
|---|
| 276 | 356 | dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); |
|---|
| 277 | 357 | |
|---|
| .. | .. |
|---|
| 283 | 363 | struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); |
|---|
| 284 | 364 | struct scp *scp = scpd->scp; |
|---|
| 285 | 365 | void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; |
|---|
| 286 | | - u32 pdn_ack = scpd->data->sram_pdn_ack_bits; |
|---|
| 287 | 366 | u32 val; |
|---|
| 288 | 367 | int ret, tmp; |
|---|
| 289 | | - int i; |
|---|
| 290 | 368 | |
|---|
| 291 | | - if (scpd->data->bus_prot_mask) { |
|---|
| 292 | | - ret = mtk_infracfg_set_bus_protection(scp->infracfg, |
|---|
| 293 | | - scpd->data->bus_prot_mask, |
|---|
| 294 | | - scp->bus_prot_reg_update); |
|---|
| 295 | | - if (ret) |
|---|
| 296 | | - goto out; |
|---|
| 297 | | - } |
|---|
| 298 | | - |
|---|
| 299 | | - val = readl(ctl_addr); |
|---|
| 300 | | - val |= scpd->data->sram_pdn_bits; |
|---|
| 301 | | - writel(val, ctl_addr); |
|---|
| 302 | | - |
|---|
| 303 | | - /* wait until SRAM_PDN_ACK all 1 */ |
|---|
| 304 | | - ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack, |
|---|
| 305 | | - MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); |
|---|
| 369 | + ret = scpsys_bus_protect_enable(scpd); |
|---|
| 306 | 370 | if (ret < 0) |
|---|
| 307 | 371 | goto out; |
|---|
| 308 | 372 | |
|---|
| 373 | + ret = scpsys_sram_disable(scpd, ctl_addr); |
|---|
| 374 | + if (ret < 0) |
|---|
| 375 | + goto out; |
|---|
| 376 | + |
|---|
| 377 | + /* subsys power off */ |
|---|
| 378 | + val = readl(ctl_addr); |
|---|
| 309 | 379 | val |= PWR_ISO_BIT; |
|---|
| 310 | 380 | writel(val, ctl_addr); |
|---|
| 311 | 381 | |
|---|
| .. | .. |
|---|
| 327 | 397 | if (ret < 0) |
|---|
| 328 | 398 | goto out; |
|---|
| 329 | 399 | |
|---|
| 330 | | - for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) |
|---|
| 331 | | - clk_disable_unprepare(scpd->clk[i]); |
|---|
| 400 | + scpsys_clk_disable(scpd->clk, MAX_CLKS); |
|---|
| 332 | 401 | |
|---|
| 333 | | - if (scpd->supply) |
|---|
| 334 | | - regulator_disable(scpd->supply); |
|---|
| 402 | + ret = scpsys_regulator_disable(scpd); |
|---|
| 403 | + if (ret < 0) |
|---|
| 404 | + goto out; |
|---|
| 335 | 405 | |
|---|
| 336 | 406 | return 0; |
|---|
| 337 | 407 | |
|---|