Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 893 lines 25 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2 3/* 4 * Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de> 5 */ 6 7#include <linux/bitfield.h> 8#include <linux/clk.h> 9#include <linux/clk-provider.h> 10#include <linux/device.h> 11#include <linux/interconnect.h> 12#include <linux/module.h> 13#include <linux/of.h> 14#include <linux/platform_device.h> 15#include <linux/pm_domain.h> 16#include <linux/pm_runtime.h> 17#include <linux/regmap.h> 18 19#include <dt-bindings/power/imx8mp-power.h> 20 21#define GPR_REG0 0x0 22#define PCIE_CLOCK_MODULE_EN BIT(0) 23#define USB_CLOCK_MODULE_EN BIT(1) 24#define PCIE_PHY_APB_RST BIT(4) 25#define PCIE_PHY_INIT_RST BIT(5) 26#define GPR_REG1 0x4 27#define PLL_LOCK BIT(13) 28#define GPR_REG2 0x8 29#define P_PLL_MASK GENMASK(5, 0) 30#define M_PLL_MASK GENMASK(15, 6) 31#define S_PLL_MASK GENMASK(18, 16) 32#define GPR_REG3 0xc 33#define PLL_CKE BIT(17) 34#define PLL_RST BIT(31) 35 36struct imx8mp_blk_ctrl_domain; 37 38struct imx8mp_blk_ctrl { 39 struct device *dev; 40 struct notifier_block power_nb; 41 struct device *bus_power_dev; 42 struct regmap *regmap; 43 struct imx8mp_blk_ctrl_domain *domains; 44 struct genpd_onecell_data onecell_data; 45 void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 46 void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 47}; 48 49struct imx8mp_blk_ctrl_domain_data { 50 const char *name; 51 const char * const *clk_names; 52 int num_clks; 53 const char * const *path_names; 54 int num_paths; 55 const char *gpc_name; 56 const unsigned int flags; 57}; 58 59#define DOMAIN_MAX_CLKS 3 60#define DOMAIN_MAX_PATHS 3 61 62struct imx8mp_blk_ctrl_domain { 63 struct generic_pm_domain genpd; 64 const struct imx8mp_blk_ctrl_domain_data *data; 65 struct clk_bulk_data clks[DOMAIN_MAX_CLKS]; 66 struct icc_bulk_data paths[DOMAIN_MAX_PATHS]; 67 struct device *power_dev; 68 struct imx8mp_blk_ctrl *bc; 69 struct notifier_block power_nb; 70 int num_paths; 71 int id; 72}; 73 74struct imx8mp_blk_ctrl_data { 75 int max_reg; 76 int (*probe) (struct imx8mp_blk_ctrl *bc); 77 notifier_fn_t power_notifier_fn; 78 void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 79 void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain); 80 const struct imx8mp_blk_ctrl_domain_data *domains; 81 int num_domains; 82}; 83 84static inline struct imx8mp_blk_ctrl_domain * 85to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd) 86{ 87 return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd); 88} 89 90struct clk_hsio_pll { 91 struct clk_hw hw; 92 struct regmap *regmap; 93}; 94 95static inline struct clk_hsio_pll *to_clk_hsio_pll(struct clk_hw *hw) 96{ 97 return container_of(hw, struct clk_hsio_pll, hw); 98} 99 100static int clk_hsio_pll_prepare(struct clk_hw *hw) 101{ 102 struct clk_hsio_pll *clk = to_clk_hsio_pll(hw); 103 u32 val; 104 105 /* set the PLL configuration */ 106 regmap_update_bits(clk->regmap, GPR_REG2, 107 P_PLL_MASK | M_PLL_MASK | S_PLL_MASK, 108 FIELD_PREP(P_PLL_MASK, 12) | 109 FIELD_PREP(M_PLL_MASK, 800) | 110 FIELD_PREP(S_PLL_MASK, 4)); 111 112 /* de-assert PLL reset */ 113 regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST, PLL_RST); 114 115 /* enable PLL */ 116 regmap_update_bits(clk->regmap, GPR_REG3, PLL_CKE, PLL_CKE); 117 118 return regmap_read_poll_timeout(clk->regmap, GPR_REG1, val, 119 val & PLL_LOCK, 10, 100); 120} 121 122static void clk_hsio_pll_unprepare(struct clk_hw *hw) 123{ 124 struct clk_hsio_pll *clk = to_clk_hsio_pll(hw); 125 126 regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST | PLL_CKE, 0); 127} 128 129static int clk_hsio_pll_is_prepared(struct clk_hw *hw) 130{ 131 struct clk_hsio_pll *clk = to_clk_hsio_pll(hw); 132 133 return regmap_test_bits(clk->regmap, GPR_REG1, PLL_LOCK); 134} 135 136static unsigned long clk_hsio_pll_recalc_rate(struct clk_hw *hw, 137 unsigned long parent_rate) 138{ 139 return 100000000; 140} 141 142static const struct clk_ops clk_hsio_pll_ops = { 143 .prepare = clk_hsio_pll_prepare, 144 .unprepare = clk_hsio_pll_unprepare, 145 .is_prepared = clk_hsio_pll_is_prepared, 146 .recalc_rate = clk_hsio_pll_recalc_rate, 147}; 148 149static int imx8mp_hsio_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc) 150{ 151 struct clk_hsio_pll *clk_hsio_pll; 152 struct clk_hw *hw; 153 struct clk_init_data init = {}; 154 int ret; 155 156 clk_hsio_pll = devm_kzalloc(bc->dev, sizeof(*clk_hsio_pll), GFP_KERNEL); 157 if (!clk_hsio_pll) 158 return -ENOMEM; 159 160 init.name = "hsio_pll"; 161 init.ops = &clk_hsio_pll_ops; 162 init.parent_names = (const char *[]){"osc_24m"}; 163 init.num_parents = 1; 164 165 clk_hsio_pll->regmap = bc->regmap; 166 clk_hsio_pll->hw.init = &init; 167 168 hw = &clk_hsio_pll->hw; 169 ret = devm_clk_hw_register(bc->bus_power_dev, hw); 170 if (ret) 171 return ret; 172 173 return devm_of_clk_add_hw_provider(bc->dev, of_clk_hw_simple_get, hw); 174} 175 176static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc, 177 struct imx8mp_blk_ctrl_domain *domain) 178{ 179 switch (domain->id) { 180 case IMX8MP_HSIOBLK_PD_USB: 181 regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 182 break; 183 case IMX8MP_HSIOBLK_PD_PCIE: 184 regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN); 185 break; 186 case IMX8MP_HSIOBLK_PD_PCIE_PHY: 187 regmap_set_bits(bc->regmap, GPR_REG0, 188 PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST); 189 break; 190 default: 191 break; 192 } 193} 194 195static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc, 196 struct imx8mp_blk_ctrl_domain *domain) 197{ 198 switch (domain->id) { 199 case IMX8MP_HSIOBLK_PD_USB: 200 regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 201 break; 202 case IMX8MP_HSIOBLK_PD_PCIE: 203 regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN); 204 break; 205 case IMX8MP_HSIOBLK_PD_PCIE_PHY: 206 regmap_clear_bits(bc->regmap, GPR_REG0, 207 PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST); 208 break; 209 default: 210 break; 211 } 212} 213 214static int imx8mp_hsio_power_notifier(struct notifier_block *nb, 215 unsigned long action, void *data) 216{ 217 struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl, 218 power_nb); 219 struct clk_bulk_data *usb_clk = bc->domains[IMX8MP_HSIOBLK_PD_USB].clks; 220 int num_clks = bc->domains[IMX8MP_HSIOBLK_PD_USB].data->num_clks; 221 int ret; 222 223 switch (action) { 224 case GENPD_NOTIFY_ON: 225 /* 226 * enable USB clock for a moment for the power-on ADB handshake 227 * to proceed 228 */ 229 ret = clk_bulk_prepare_enable(num_clks, usb_clk); 230 if (ret) 231 return NOTIFY_BAD; 232 regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 233 234 udelay(5); 235 236 regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 237 clk_bulk_disable_unprepare(num_clks, usb_clk); 238 break; 239 case GENPD_NOTIFY_PRE_OFF: 240 /* enable USB clock for the power-down ADB handshake to work */ 241 ret = clk_bulk_prepare_enable(num_clks, usb_clk); 242 if (ret) 243 return NOTIFY_BAD; 244 245 regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN); 246 break; 247 case GENPD_NOTIFY_OFF: 248 clk_bulk_disable_unprepare(num_clks, usb_clk); 249 break; 250 default: 251 break; 252 } 253 254 return NOTIFY_OK; 255} 256 257static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = { 258 [IMX8MP_HSIOBLK_PD_USB] = { 259 .name = "hsioblk-usb", 260 .clk_names = (const char *[]){ "usb" }, 261 .num_clks = 1, 262 .gpc_name = "usb", 263 .path_names = (const char *[]){"usb1", "usb2"}, 264 .num_paths = 2, 265 }, 266 [IMX8MP_HSIOBLK_PD_USB_PHY1] = { 267 .name = "hsioblk-usb-phy1", 268 .gpc_name = "usb-phy1", 269 .flags = GENPD_FLAG_ACTIVE_WAKEUP, 270 }, 271 [IMX8MP_HSIOBLK_PD_USB_PHY2] = { 272 .name = "hsioblk-usb-phy2", 273 .gpc_name = "usb-phy2", 274 .flags = GENPD_FLAG_ACTIVE_WAKEUP, 275 }, 276 [IMX8MP_HSIOBLK_PD_PCIE] = { 277 .name = "hsioblk-pcie", 278 .clk_names = (const char *[]){ "pcie" }, 279 .num_clks = 1, 280 .gpc_name = "pcie", 281 .path_names = (const char *[]){"noc-pcie", "pcie"}, 282 .num_paths = 2, 283 }, 284 [IMX8MP_HSIOBLK_PD_PCIE_PHY] = { 285 .name = "hsioblk-pcie-phy", 286 .gpc_name = "pcie-phy", 287 }, 288}; 289 290static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = { 291 .max_reg = 0x24, 292 .probe = imx8mp_hsio_blk_ctrl_probe, 293 .power_on = imx8mp_hsio_blk_ctrl_power_on, 294 .power_off = imx8mp_hsio_blk_ctrl_power_off, 295 .power_notifier_fn = imx8mp_hsio_power_notifier, 296 .domains = imx8mp_hsio_domain_data, 297 .num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data), 298}; 299 300#define HDMI_RTX_RESET_CTL0 0x20 301#define HDMI_RTX_CLK_CTL0 0x40 302#define HDMI_RTX_CLK_CTL1 0x50 303#define HDMI_RTX_CLK_CTL2 0x60 304#define HDMI_RTX_CLK_CTL3 0x70 305#define HDMI_RTX_CLK_CTL4 0x80 306#define HDMI_TX_CONTROL0 0x200 307#define HDMI_LCDIF_NOC_HURRY_MASK GENMASK(14, 12) 308 309static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc, 310 struct imx8mp_blk_ctrl_domain *domain) 311{ 312 switch (domain->id) { 313 case IMX8MP_HDMIBLK_PD_IRQSTEER: 314 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9)); 315 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16)); 316 break; 317 case IMX8MP_HDMIBLK_PD_LCDIF: 318 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 319 BIT(16) | BIT(17) | BIT(18) | 320 BIT(19) | BIT(20)); 321 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11)); 322 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 323 BIT(4) | BIT(5) | BIT(6)); 324 regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, 325 FIELD_PREP(HDMI_LCDIF_NOC_HURRY_MASK, 7)); 326 break; 327 case IMX8MP_HDMIBLK_PD_PAI: 328 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17)); 329 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18)); 330 break; 331 case IMX8MP_HDMIBLK_PD_PVI: 332 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28)); 333 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22)); 334 break; 335 case IMX8MP_HDMIBLK_PD_TRNG: 336 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30)); 337 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20)); 338 break; 339 case IMX8MP_HDMIBLK_PD_HDMI_TX: 340 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 341 BIT(2) | BIT(4) | BIT(5)); 342 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, 343 BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | 344 BIT(18) | BIT(19) | BIT(20) | BIT(21)); 345 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 346 BIT(7) | BIT(10) | BIT(11)); 347 regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1)); 348 break; 349 case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY: 350 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7)); 351 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24)); 352 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12)); 353 regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3)); 354 break; 355 case IMX8MP_HDMIBLK_PD_HRV: 356 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5)); 357 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15)); 358 break; 359 default: 360 break; 361 } 362} 363 364static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc, 365 struct imx8mp_blk_ctrl_domain *domain) 366{ 367 switch (domain->id) { 368 case IMX8MP_HDMIBLK_PD_IRQSTEER: 369 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9)); 370 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16)); 371 break; 372 case IMX8MP_HDMIBLK_PD_LCDIF: 373 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 374 BIT(4) | BIT(5) | BIT(6)); 375 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11)); 376 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 377 BIT(16) | BIT(17) | BIT(18) | 378 BIT(19) | BIT(20)); 379 break; 380 case IMX8MP_HDMIBLK_PD_PAI: 381 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18)); 382 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17)); 383 break; 384 case IMX8MP_HDMIBLK_PD_PVI: 385 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22)); 386 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28)); 387 break; 388 case IMX8MP_HDMIBLK_PD_TRNG: 389 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20)); 390 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30)); 391 break; 392 case IMX8MP_HDMIBLK_PD_HDMI_TX: 393 regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1)); 394 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, 395 BIT(7) | BIT(10) | BIT(11)); 396 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, 397 BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) | 398 BIT(18) | BIT(19) | BIT(20) | BIT(21)); 399 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 400 BIT(2) | BIT(4) | BIT(5)); 401 break; 402 case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY: 403 regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3)); 404 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12)); 405 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7)); 406 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24)); 407 break; 408 case IMX8MP_HDMIBLK_PD_HRV: 409 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15)); 410 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5)); 411 break; 412 default: 413 break; 414 } 415} 416 417static int imx8mp_hdmi_power_notifier(struct notifier_block *nb, 418 unsigned long action, void *data) 419{ 420 struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl, 421 power_nb); 422 423 if (action != GENPD_NOTIFY_ON) 424 return NOTIFY_OK; 425 426 /* 427 * Contrary to other blk-ctrls the reset and clock don't clear when the 428 * power domain is powered down. To ensure the proper reset pulsing, 429 * first clear them all to asserted state, then enable the bus clocks 430 * and then release the ADB reset. 431 */ 432 regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0); 433 regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0); 434 regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0); 435 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, 436 BIT(0) | BIT(1) | BIT(10) | BIT(11)); 437 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0)); 438 439 /* 440 * On power up we have no software backchannel to the GPC to 441 * wait for the ADB handshake to happen, so we just delay for a 442 * bit. On power down the GPC driver waits for the handshake. 443 */ 444 udelay(5); 445 446 return NOTIFY_OK; 447} 448 449static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = { 450 [IMX8MP_HDMIBLK_PD_IRQSTEER] = { 451 .name = "hdmiblk-irqsteer", 452 .clk_names = (const char *[]){ "apb" }, 453 .num_clks = 1, 454 .gpc_name = "irqsteer", 455 }, 456 [IMX8MP_HDMIBLK_PD_LCDIF] = { 457 .name = "hdmiblk-lcdif", 458 .clk_names = (const char *[]){ "axi", "apb", "fdcc" }, 459 .num_clks = 3, 460 .gpc_name = "lcdif", 461 .path_names = (const char *[]){"lcdif-hdmi"}, 462 .num_paths = 1, 463 }, 464 [IMX8MP_HDMIBLK_PD_PAI] = { 465 .name = "hdmiblk-pai", 466 .clk_names = (const char *[]){ "apb" }, 467 .num_clks = 1, 468 .gpc_name = "pai", 469 }, 470 [IMX8MP_HDMIBLK_PD_PVI] = { 471 .name = "hdmiblk-pvi", 472 .clk_names = (const char *[]){ "apb" }, 473 .num_clks = 1, 474 .gpc_name = "pvi", 475 }, 476 [IMX8MP_HDMIBLK_PD_TRNG] = { 477 .name = "hdmiblk-trng", 478 .clk_names = (const char *[]){ "apb" }, 479 .num_clks = 1, 480 .gpc_name = "trng", 481 }, 482 [IMX8MP_HDMIBLK_PD_HDMI_TX] = { 483 .name = "hdmiblk-hdmi-tx", 484 .clk_names = (const char *[]){ "apb", "ref_266m", "fdcc" }, 485 .num_clks = 3, 486 .gpc_name = "hdmi-tx", 487 }, 488 [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = { 489 .name = "hdmiblk-hdmi-tx-phy", 490 .clk_names = (const char *[]){ "apb", "ref_24m" }, 491 .num_clks = 2, 492 .gpc_name = "hdmi-tx-phy", 493 }, 494 [IMX8MP_HDMIBLK_PD_HRV] = { 495 .name = "hdmiblk-hrv", 496 .clk_names = (const char *[]){ "axi", "apb" }, 497 .num_clks = 2, 498 .gpc_name = "hrv", 499 .path_names = (const char *[]){"hrv"}, 500 .num_paths = 1, 501 }, 502 [IMX8MP_HDMIBLK_PD_HDCP] = { 503 .name = "hdmiblk-hdcp", 504 .clk_names = (const char *[]){ "axi", "apb" }, 505 .num_clks = 2, 506 .gpc_name = "hdcp", 507 .path_names = (const char *[]){"hdcp"}, 508 .num_paths = 1, 509 }, 510}; 511 512static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = { 513 .max_reg = 0x23c, 514 .power_on = imx8mp_hdmi_blk_ctrl_power_on, 515 .power_off = imx8mp_hdmi_blk_ctrl_power_off, 516 .power_notifier_fn = imx8mp_hdmi_power_notifier, 517 .domains = imx8mp_hdmi_domain_data, 518 .num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data), 519}; 520 521static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd) 522{ 523 struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd); 524 const struct imx8mp_blk_ctrl_domain_data *data = domain->data; 525 struct imx8mp_blk_ctrl *bc = domain->bc; 526 int ret; 527 528 /* make sure bus domain is awake */ 529 ret = pm_runtime_resume_and_get(bc->bus_power_dev); 530 if (ret < 0) { 531 dev_err(bc->dev, "failed to power up bus domain\n"); 532 return ret; 533 } 534 535 /* enable upstream clocks */ 536 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); 537 if (ret) { 538 dev_err(bc->dev, "failed to enable clocks\n"); 539 goto bus_put; 540 } 541 542 /* domain specific blk-ctrl manipulation */ 543 bc->power_on(bc, domain); 544 545 /* power up upstream GPC domain */ 546 ret = pm_runtime_resume_and_get(domain->power_dev); 547 if (ret < 0) { 548 dev_err(bc->dev, "failed to power up peripheral domain\n"); 549 goto clk_disable; 550 } 551 552 ret = icc_bulk_set_bw(domain->num_paths, domain->paths); 553 if (ret) 554 dev_err(bc->dev, "failed to set icc bw\n"); 555 556 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 557 558 return 0; 559 560clk_disable: 561 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 562bus_put: 563 pm_runtime_put(bc->bus_power_dev); 564 565 return ret; 566} 567 568static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd) 569{ 570 struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd); 571 const struct imx8mp_blk_ctrl_domain_data *data = domain->data; 572 struct imx8mp_blk_ctrl *bc = domain->bc; 573 int ret; 574 575 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); 576 if (ret) { 577 dev_err(bc->dev, "failed to enable clocks\n"); 578 return ret; 579 } 580 581 /* domain specific blk-ctrl manipulation */ 582 bc->power_off(bc, domain); 583 584 clk_bulk_disable_unprepare(data->num_clks, domain->clks); 585 586 /* power down upstream GPC domain */ 587 pm_runtime_put(domain->power_dev); 588 589 /* allow bus domain to suspend */ 590 pm_runtime_put(bc->bus_power_dev); 591 592 return 0; 593} 594 595static int imx8mp_blk_ctrl_gpc_notifier(struct notifier_block *nb, 596 unsigned long action, void *data) 597{ 598 struct imx8mp_blk_ctrl_domain *domain = 599 container_of(nb, struct imx8mp_blk_ctrl_domain, power_nb); 600 601 if (action == GENPD_NOTIFY_PRE_OFF) { 602 if (domain->genpd.status == GENPD_STATE_ON) 603 return NOTIFY_BAD; 604 } 605 606 return NOTIFY_OK; 607} 608 609static struct lock_class_key blk_ctrl_genpd_lock_class; 610 611static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) 612{ 613 const struct imx8mp_blk_ctrl_data *bc_data; 614 struct device *dev = &pdev->dev; 615 struct imx8mp_blk_ctrl *bc; 616 void __iomem *base; 617 int num_domains, i, ret; 618 619 struct regmap_config regmap_config = { 620 .reg_bits = 32, 621 .val_bits = 32, 622 .reg_stride = 4, 623 }; 624 625 bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL); 626 if (!bc) 627 return -ENOMEM; 628 629 bc->dev = dev; 630 631 bc_data = of_device_get_match_data(dev); 632 num_domains = bc_data->num_domains; 633 634 base = devm_platform_ioremap_resource(pdev, 0); 635 if (IS_ERR(base)) 636 return PTR_ERR(base); 637 638 regmap_config.max_register = bc_data->max_reg; 639 bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config); 640 if (IS_ERR(bc->regmap)) 641 return dev_err_probe(dev, PTR_ERR(bc->regmap), 642 "failed to init regmap\n"); 643 644 bc->domains = devm_kcalloc(dev, num_domains, 645 sizeof(struct imx8mp_blk_ctrl_domain), 646 GFP_KERNEL); 647 if (!bc->domains) 648 return -ENOMEM; 649 650 bc->onecell_data.num_domains = num_domains; 651 bc->onecell_data.domains = 652 devm_kcalloc(dev, num_domains, 653 sizeof(struct generic_pm_domain *), GFP_KERNEL); 654 if (!bc->onecell_data.domains) 655 return -ENOMEM; 656 657 bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus"); 658 if (IS_ERR(bc->bus_power_dev)) 659 return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev), 660 "failed to attach bus power domain\n"); 661 662 bc->power_off = bc_data->power_off; 663 bc->power_on = bc_data->power_on; 664 665 for (i = 0; i < num_domains; i++) { 666 const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i]; 667 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i]; 668 int j; 669 670 domain->data = data; 671 domain->num_paths = data->num_paths; 672 673 for (j = 0; j < data->num_clks; j++) 674 domain->clks[j].id = data->clk_names[j]; 675 676 for (j = 0; j < data->num_paths; j++) { 677 domain->paths[j].name = data->path_names[j]; 678 /* Fake value for now, just let ICC could configure NoC mode/priority */ 679 domain->paths[j].avg_bw = 1; 680 domain->paths[j].peak_bw = 1; 681 } 682 683 ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths); 684 if (ret) { 685 if (ret != -EPROBE_DEFER) { 686 dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n"); 687 domain->num_paths = 0; 688 } else { 689 dev_err_probe(dev, ret, "failed to get noc entries\n"); 690 goto cleanup_pds; 691 } 692 } 693 694 ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); 695 if (ret) { 696 dev_err_probe(dev, ret, "failed to get clock\n"); 697 goto cleanup_pds; 698 } 699 700 domain->power_dev = 701 dev_pm_domain_attach_by_name(dev, data->gpc_name); 702 if (IS_ERR_OR_NULL(domain->power_dev)) { 703 if (!domain->power_dev) 704 ret = -ENODEV; 705 else 706 ret = PTR_ERR(domain->power_dev); 707 dev_err_probe(dev, ret, 708 "failed to attach power domain %s\n", 709 data->gpc_name); 710 goto cleanup_pds; 711 } 712 713 domain->power_nb.notifier_call = imx8mp_blk_ctrl_gpc_notifier; 714 ret = dev_pm_genpd_add_notifier(domain->power_dev, &domain->power_nb); 715 if (ret) { 716 dev_err_probe(dev, ret, "failed to add power notifier\n"); 717 dev_pm_domain_detach(domain->power_dev, true); 718 goto cleanup_pds; 719 } 720 721 domain->genpd.name = data->name; 722 domain->genpd.power_on = imx8mp_blk_ctrl_power_on; 723 domain->genpd.power_off = imx8mp_blk_ctrl_power_off; 724 domain->genpd.flags = data->flags; 725 domain->bc = bc; 726 domain->id = i; 727 728 ret = pm_genpd_init(&domain->genpd, NULL, true); 729 if (ret) { 730 dev_err_probe(dev, ret, "failed to init power domain\n"); 731 dev_pm_genpd_remove_notifier(domain->power_dev); 732 dev_pm_domain_detach(domain->power_dev, true); 733 goto cleanup_pds; 734 } 735 736 /* 737 * We use runtime PM to trigger power on/off of the upstream GPC 738 * domain, as a strict hierarchical parent/child power domain 739 * setup doesn't allow us to meet the sequencing requirements. 740 * This means we have nested locking of genpd locks, without the 741 * nesting being visible at the genpd level, so we need a 742 * separate lock class to make lockdep aware of the fact that 743 * this are separate domain locks that can be nested without a 744 * self-deadlock. 745 */ 746 lockdep_set_class(&domain->genpd.mlock, 747 &blk_ctrl_genpd_lock_class); 748 749 bc->onecell_data.domains[i] = &domain->genpd; 750 } 751 752 ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); 753 if (ret) { 754 dev_err_probe(dev, ret, "failed to add power domain provider\n"); 755 goto cleanup_pds; 756 } 757 758 bc->power_nb.notifier_call = bc_data->power_notifier_fn; 759 ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb); 760 if (ret) { 761 dev_err_probe(dev, ret, "failed to add power notifier\n"); 762 goto cleanup_provider; 763 } 764 765 if (bc_data->probe) { 766 ret = bc_data->probe(bc); 767 if (ret) 768 goto cleanup_provider; 769 } 770 771 dev_set_drvdata(dev, bc); 772 773 return 0; 774 775cleanup_provider: 776 of_genpd_del_provider(dev->of_node); 777cleanup_pds: 778 for (i--; i >= 0; i--) { 779 pm_genpd_remove(&bc->domains[i].genpd); 780 dev_pm_genpd_remove_notifier(bc->domains[i].power_dev); 781 dev_pm_domain_detach(bc->domains[i].power_dev, true); 782 } 783 784 dev_pm_domain_detach(bc->bus_power_dev, true); 785 786 return ret; 787} 788 789static void imx8mp_blk_ctrl_remove(struct platform_device *pdev) 790{ 791 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); 792 int i; 793 794 of_genpd_del_provider(pdev->dev.of_node); 795 796 for (i = 0; i < bc->onecell_data.num_domains; i++) { 797 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i]; 798 799 pm_genpd_remove(&domain->genpd); 800 dev_pm_genpd_remove_notifier(domain->power_dev); 801 dev_pm_domain_detach(domain->power_dev, true); 802 } 803 804 dev_pm_genpd_remove_notifier(bc->bus_power_dev); 805 806 dev_pm_domain_detach(bc->bus_power_dev, true); 807} 808 809#ifdef CONFIG_PM_SLEEP 810static int imx8mp_blk_ctrl_suspend(struct device *dev) 811{ 812 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev); 813 int ret, i; 814 815 /* 816 * This may look strange, but is done so the generic PM_SLEEP code 817 * can power down our domains and more importantly power them up again 818 * after resume, without tripping over our usage of runtime PM to 819 * control the upstream GPC domains. Things happen in the right order 820 * in the system suspend/resume paths due to the device parent/child 821 * hierarchy. 822 */ 823 ret = pm_runtime_get_sync(bc->bus_power_dev); 824 if (ret < 0) { 825 pm_runtime_put_noidle(bc->bus_power_dev); 826 return ret; 827 } 828 829 for (i = 0; i < bc->onecell_data.num_domains; i++) { 830 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i]; 831 832 ret = pm_runtime_get_sync(domain->power_dev); 833 if (ret < 0) { 834 pm_runtime_put_noidle(domain->power_dev); 835 goto out_fail; 836 } 837 } 838 839 return 0; 840 841out_fail: 842 for (i--; i >= 0; i--) 843 pm_runtime_put(bc->domains[i].power_dev); 844 845 pm_runtime_put(bc->bus_power_dev); 846 847 return ret; 848} 849 850static int imx8mp_blk_ctrl_resume(struct device *dev) 851{ 852 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev); 853 int i; 854 855 for (i = 0; i < bc->onecell_data.num_domains; i++) 856 pm_runtime_put(bc->domains[i].power_dev); 857 858 pm_runtime_put(bc->bus_power_dev); 859 860 return 0; 861} 862#endif 863 864static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = { 865 SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend, 866 imx8mp_blk_ctrl_resume) 867}; 868 869static const struct of_device_id imx8mp_blk_ctrl_of_match[] = { 870 { 871 .compatible = "fsl,imx8mp-hsio-blk-ctrl", 872 .data = &imx8mp_hsio_blk_ctl_dev_data, 873 }, { 874 .compatible = "fsl,imx8mp-hdmi-blk-ctrl", 875 .data = &imx8mp_hdmi_blk_ctl_dev_data, 876 }, { 877 /* Sentinel */ 878 } 879}; 880MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match); 881 882static struct platform_driver imx8mp_blk_ctrl_driver = { 883 .probe = imx8mp_blk_ctrl_probe, 884 .remove = imx8mp_blk_ctrl_remove, 885 .driver = { 886 .name = "imx8mp-blk-ctrl", 887 .pm = &imx8mp_blk_ctrl_pm_ops, 888 .of_match_table = imx8mp_blk_ctrl_of_match, 889 .suppress_bind_attrs = true, 890 }, 891}; 892module_platform_driver(imx8mp_blk_ctrl_driver); 893MODULE_LICENSE("GPL");