brintos

brintos / linux-shallow public Read only

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