diff options
Diffstat (limited to 'drivers/soc/imx/imx8mp-blk-ctrl.c')
| -rw-r--r-- | drivers/soc/imx/imx8mp-blk-ctrl.c | 89 | 
1 files changed, 75 insertions, 14 deletions
| diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 4ca2ede6871b..0e3b6ba22f94 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -6,6 +6,7 @@  #include <linux/clk.h>  #include <linux/device.h> +#include <linux/interconnect.h>  #include <linux/module.h>  #include <linux/of_device.h>  #include <linux/platform_device.h> @@ -18,6 +19,8 @@  #define GPR_REG0		0x0  #define  PCIE_CLOCK_MODULE_EN	BIT(0)  #define  USB_CLOCK_MODULE_EN	BIT(1) +#define  PCIE_PHY_APB_RST	BIT(4) +#define  PCIE_PHY_INIT_RST	BIT(5)  struct imx8mp_blk_ctrl_domain; @@ -36,17 +39,22 @@ struct imx8mp_blk_ctrl_domain_data {  	const char *name;  	const char * const *clk_names;  	int num_clks; +	const char * const *path_names; +	int num_paths;  	const char *gpc_name;  };  #define DOMAIN_MAX_CLKS 2 +#define DOMAIN_MAX_PATHS 3  struct imx8mp_blk_ctrl_domain {  	struct generic_pm_domain genpd;  	const struct imx8mp_blk_ctrl_domain_data *data;  	struct clk_bulk_data clks[DOMAIN_MAX_CLKS]; +	struct icc_bulk_data paths[DOMAIN_MAX_PATHS];  	struct device *power_dev;  	struct imx8mp_blk_ctrl *bc; +	int num_paths;  	int id;  }; @@ -75,6 +83,10 @@ static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,  	case IMX8MP_HSIOBLK_PD_PCIE:  		regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);  		break; +	case IMX8MP_HSIOBLK_PD_PCIE_PHY: +		regmap_set_bits(bc->regmap, GPR_REG0, +				PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST); +		break;  	default:  		break;  	} @@ -90,6 +102,10 @@ static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,  	case IMX8MP_HSIOBLK_PD_PCIE:  		regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);  		break; +	case IMX8MP_HSIOBLK_PD_PCIE_PHY: +		regmap_clear_bits(bc->regmap, GPR_REG0, +				  PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST); +		break;  	default:  		break;  	} @@ -144,6 +160,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {  		.clk_names = (const char *[]){ "usb" },  		.num_clks = 1,  		.gpc_name = "usb", +		.path_names = (const char *[]){"usb1", "usb2"}, +		.num_paths = 2,  	},  	[IMX8MP_HSIOBLK_PD_USB_PHY1] = {  		.name = "hsioblk-usb-phy1", @@ -158,6 +176,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {  		.clk_names = (const char *[]){ "pcie" },  		.num_clks = 1,  		.gpc_name = "pcie", +		.path_names = (const char *[]){"noc-pcie", "pcie"}, +		.num_paths = 2,  	},  	[IMX8MP_HSIOBLK_PD_PCIE_PHY] = {  		.name = "hsioblk-pcie-phy", @@ -225,6 +245,13 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,  		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));  		regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));  		break; +	case IMX8MP_HDMIBLK_PD_HDCP: +		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11)); +		break; +	case IMX8MP_HDMIBLK_PD_HRV: +		regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5)); +		regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15)); +		break;  	default:  		break;  	} @@ -273,6 +300,13 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,  		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));  		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));  		break; +	case IMX8MP_HDMIBLK_PD_HDCP: +		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11)); +		break; +	case IMX8MP_HDMIBLK_PD_HRV: +		regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15)); +		regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5)); +		break;  	default:  		break;  	} @@ -322,6 +356,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {  		.clk_names = (const char *[]){ "axi", "apb" },  		.num_clks = 2,  		.gpc_name = "lcdif", +		.path_names = (const char *[]){"lcdif-hdmi"}, +		.num_paths = 1,  	},  	[IMX8MP_HDMIBLK_PD_PAI] = {  		.name = "hdmiblk-pai", @@ -353,6 +389,22 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {  		.num_clks = 2,  		.gpc_name = "hdmi-tx-phy",  	}, +	[IMX8MP_HDMIBLK_PD_HRV] = { +		.name = "hdmiblk-hrv", +		.clk_names = (const char *[]){ "axi", "apb" }, +		.num_clks = 2, +		.gpc_name = "hrv", +		.path_names = (const char *[]){"hrv"}, +		.num_paths = 1, +	}, +	[IMX8MP_HDMIBLK_PD_HDCP] = { +		.name = "hdmiblk-hdcp", +		.clk_names = (const char *[]){ "axi", "apb" }, +		.num_clks = 2, +		.gpc_name = "hdcp", +		.path_names = (const char *[]){"hdcp"}, +		.num_paths = 1, +	},  };  static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = { @@ -395,6 +447,10 @@ static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)  		goto clk_disable;  	} +	ret = icc_bulk_set_bw(domain->num_paths, domain->paths); +	if (ret) +		dev_err(bc->dev, "failed to set icc bw\n"); +  	clk_bulk_disable_unprepare(data->num_clks, domain->clks);  	return 0; @@ -434,19 +490,6 @@ static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)  	return 0;  } -static struct generic_pm_domain * -imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data) -{ -	struct genpd_onecell_data *onecell_data = data; -	unsigned int index = args->args[0]; - -	if (args->args_count != 1 || -	    index >= onecell_data->num_domains) -		return ERR_PTR(-EINVAL); - -	return onecell_data->domains[index]; -} -  static struct lock_class_key blk_ctrl_genpd_lock_class;  static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) @@ -489,7 +532,6 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)  		return -ENOMEM;  	bc->onecell_data.num_domains = num_domains; -	bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;  	bc->onecell_data.domains =  		devm_kcalloc(dev, num_domains,  			     sizeof(struct generic_pm_domain *), GFP_KERNEL); @@ -510,10 +552,29 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)  		int j;  		domain->data = data; +		domain->num_paths = data->num_paths;  		for (j = 0; j < data->num_clks; j++)  			domain->clks[j].id = data->clk_names[j]; +		for (j = 0; j < data->num_paths; j++) { +			domain->paths[j].name = data->path_names[j]; +			/* Fake value for now, just let ICC could configure NoC mode/priority */ +			domain->paths[j].avg_bw = 1; +			domain->paths[j].peak_bw = 1; +		} + +		ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths); +		if (ret) { +			if (ret != -EPROBE_DEFER) { +				dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n"); +				domain->num_paths = 0; +			} else { +				dev_err_probe(dev, ret, "failed to get noc entries\n"); +				goto cleanup_pds; +			} +		} +  		ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);  		if (ret) {  			dev_err_probe(dev, ret, "failed to get clock\n"); |