From c553ca9245f4ee7db54dc48c5892be787f8458a4 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 8 Jul 2022 16:56:29 +0800 Subject: soc: imx: add icc paths for i.MX8MP media blk ctrl Add interconnect paths for i.MX8MP media blk ctrl Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8m-blk-ctrl.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c index dff7529268e4..9b0f81dc292b 100644 --- a/drivers/soc/imx/imx8m-blk-ctrl.c +++ b/drivers/soc/imx/imx8m-blk-ctrl.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -37,6 +38,8 @@ struct imx8m_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; u32 rst_mask; u32 clk_mask; @@ -52,13 +55,16 @@ struct imx8m_blk_ctrl_domain_data { }; #define DOMAIN_MAX_CLKS 4 +#define DOMAIN_MAX_PATHS 4 struct imx8m_blk_ctrl_domain { struct generic_pm_domain genpd; const struct imx8m_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 imx8m_blk_ctrl *bc; + int num_paths; }; struct imx8m_blk_ctrl_data { @@ -117,6 +123,10 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd) if (data->mipi_phy_rst_mask) regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask); + ret = icc_bulk_set_bw(domain->num_paths, domain->paths); + if (ret) + dev_err(bc->dev, "failed to set icc bw\n"); + /* disable upstream clocks */ clk_bulk_disable_unprepare(data->num_clks, domain->clks); @@ -224,10 +234,29 @@ static int imx8m_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"); @@ -650,6 +679,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[ .gpc_name = "lcdif1", .rst_mask = BIT(4) | BIT(5) | BIT(23), .clk_mask = BIT(4) | BIT(5) | BIT(23), + .path_names = (const char *[]){"lcdif-rd", "lcdif-wr"}, + .num_paths = 2, }, [IMX8MP_MEDIABLK_PD_ISI] = { .name = "mediablk-isi", @@ -658,6 +689,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[ .gpc_name = "isi", .rst_mask = BIT(6) | BIT(7), .clk_mask = BIT(6) | BIT(7), + .path_names = (const char *[]){"isi0", "isi1", "isi2"}, + .num_paths = 3, }, [IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = { .name = "mediablk-mipi-csi2-2", @@ -675,6 +708,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[ .gpc_name = "lcdif2", .rst_mask = BIT(11) | BIT(12) | BIT(24), .clk_mask = BIT(11) | BIT(12) | BIT(24), + .path_names = (const char *[]){"lcdif-rd", "lcdif-wr"}, + .num_paths = 2, }, [IMX8MP_MEDIABLK_PD_ISP] = { .name = "mediablk-isp", @@ -683,6 +718,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[ .gpc_name = "isp", .rst_mask = BIT(16) | BIT(17) | BIT(18), .clk_mask = BIT(16) | BIT(17) | BIT(18), + .path_names = (const char *[]){"isp0", "isp1"}, + .num_paths = 2, }, [IMX8MP_MEDIABLK_PD_DWE] = { .name = "mediablk-dwe", @@ -691,6 +728,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[ .gpc_name = "dwe", .rst_mask = BIT(19) | BIT(20) | BIT(21), .clk_mask = BIT(19) | BIT(20) | BIT(21), + .path_names = (const char *[]){"dwe"}, + .num_paths = 1, }, [IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = { .name = "mediablk-mipi-dsi-2", -- cgit v1.2.3 From 50299fa1f8a05fa8b545e3d64e183b525737fabb Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 8 Jul 2022 16:56:30 +0800 Subject: soc: imx: add icc paths for i.MX8MP hsio/hdmi blk ctrl Add interconnect paths for i.MX8MP hsio/hdmi blk ctrl Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8mp-blk-ctrl.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 4ca2ede6871b..6f983adcb47c 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -36,17 +37,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; }; @@ -144,6 +150,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 +166,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", @@ -322,6 +332,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", @@ -395,6 +407,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; @@ -510,10 +526,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"); -- cgit v1.2.3 From 77b0ddb42add47748c661f714e6f4b116a6e8759 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Aug 2022 14:45:33 +0800 Subject: soc: imx: add i.MX8MP HDMI blk ctrl HDCP/HRV_MWR i.MX8MP HDMI supports HDCP and HRV_MWR(HDMI RX Video Memory Write Master for RXRX validation), so add them. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8mp-blk-ctrl.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 6f983adcb47c..527d45d12a54 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -235,6 +235,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; } @@ -283,6 +290,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; } @@ -365,6 +379,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 = { -- cgit v1.2.3 From a1a5f15f7f6cb5c291f072af843305638c935be6 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Aug 2022 14:45:34 +0800 Subject: soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl i.MX8MP has a VPU blk ctrl module that could supply clk and reset to VPU, so add support for it. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8m-blk-ctrl.c | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c index 9b0f81dc292b..871a387c6b41 100644 --- a/drivers/soc/imx/imx8m-blk-ctrl.c +++ b/drivers/soc/imx/imx8m-blk-ctrl.c @@ -484,6 +484,46 @@ static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = { .num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data), }; +static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[] = { + [IMX8MP_VPUBLK_PD_G1] = { + .name = "vpublk-g1", + .clk_names = (const char *[]){ "g1", }, + .num_clks = 1, + .gpc_name = "g1", + .rst_mask = BIT(1), + .clk_mask = BIT(1), + .path_names = (const char *[]){"g1"}, + .num_paths = 1, + }, + [IMX8MP_VPUBLK_PD_G2] = { + .name = "vpublk-g2", + .clk_names = (const char *[]){ "g2", }, + .num_clks = 1, + .gpc_name = "g2", + .rst_mask = BIT(0), + .clk_mask = BIT(0), + .path_names = (const char *[]){"g2"}, + .num_paths = 1, + }, + [IMX8MP_VPUBLK_PD_VC8000E] = { + .name = "vpublk-vc8000e", + .clk_names = (const char *[]){ "vc8000e", }, + .num_clks = 1, + .gpc_name = "vc8000e", + .rst_mask = BIT(2), + .clk_mask = BIT(2), + .path_names = (const char *[]){"vc8000e"}, + .num_paths = 1, + }, +}; + +static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = { + .max_reg = 0x18, + .power_notifier_fn = imx8mm_vpu_power_notifier, + .domains = imx8mp_vpu_blk_ctl_domain_data, + .num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data), +}; + static int imx8mm_disp_power_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -827,6 +867,9 @@ static const struct of_device_id imx8m_blk_ctrl_of_match[] = { }, { .compatible = "fsl,imx8mq-vpu-blk-ctrl", .data = &imx8mq_vpu_blk_ctl_dev_data + }, { + .compatible = "fsl,imx8mp-vpu-blk-ctrl", + .data = &imx8mp_vpu_blk_ctl_dev_data }, { /* Sentinel */ } -- cgit v1.2.3 From 5506018d3dec41e6678efb92b836586e9ee1d628 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 2 Sep 2022 16:58:04 +0800 Subject: soc: imx: imx8mp-blk-ctrl: handle PCIe PHY resets Dessert the PHY reset when powering up the domain and put it back into reset when the domain is powered down. Signed-off-by: Lucas Stach Signed-off-by: Richard Zhu Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8mp-blk-ctrl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 527d45d12a54..ccb30c6cdc7e 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -19,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; @@ -81,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; } @@ -96,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; } -- cgit v1.2.3 From df5a69653586da355b9a88e7851752dc62daa5fd Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 6 Sep 2022 11:39:43 +0800 Subject: soc: imx: imx8m-blk-ctrl: Use genpd_xlate_onecell Simplify driver by using genpd_xlate_onecell instead of driver specific xlate function. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8m-blk-ctrl.c | 14 -------------- drivers/soc/imx/imx8mp-blk-ctrl.c | 14 -------------- 2 files changed, 28 deletions(-) (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c index 871a387c6b41..29e25a9ecdcb 100644 --- a/drivers/soc/imx/imx8m-blk-ctrl.c +++ b/drivers/soc/imx/imx8m-blk-ctrl.c @@ -162,19 +162,6 @@ static int imx8m_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 imx8m_blk_ctrl_probe(struct platform_device *pdev) @@ -216,7 +203,6 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev) return -ENOMEM; bc->onecell_data.num_domains = bc_data->num_domains; - bc->onecell_data.xlate = imx8m_blk_ctrl_xlate; bc->onecell_data.domains = devm_kcalloc(dev, bc_data->num_domains, sizeof(struct generic_pm_domain *), GFP_KERNEL); diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index ccb30c6cdc7e..0e3b6ba22f94 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -490,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) @@ -545,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); -- cgit v1.2.3 From 0a0f7cc25d4a525a71260cbd453a848c5c8e61c3 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 6 Sep 2022 11:28:14 +0800 Subject: soc: imx: add i.MX93 SRC power domain driver Support controlling power domain managed by System Reset Controller(SRC). Current supported power domain is mediamix power domain. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/Kconfig | 8 +++ drivers/soc/imx/Makefile | 1 + drivers/soc/imx/imx93-pd.c | 164 ++++++++++++++++++++++++++++++++++++++++++++ drivers/soc/imx/imx93-src.c | 33 +++++++++ 4 files changed, 206 insertions(+) create mode 100644 drivers/soc/imx/imx93-pd.c create mode 100644 drivers/soc/imx/imx93-src.c (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index a840494e849a..4b906791d6c7 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -20,4 +20,12 @@ config SOC_IMX8M support, it will provide the SoC info like SoC family, ID and revision etc. +config SOC_IMX9 + tristate "i.MX9 SoC family support" + depends on ARCH_MXC || COMPILE_TEST + default ARCH_MXC && ARM64 + select SOC_BUS + help + If you say yes here, you get support for the NXP i.MX9 family + endmenu diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index 63cd29f6d4d2..a0baa2a01adb 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o +obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o diff --git a/drivers/soc/imx/imx93-pd.c b/drivers/soc/imx/imx93-pd.c new file mode 100644 index 000000000000..1f3d7039c1de --- /dev/null +++ b/drivers/soc/imx/imx93-pd.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 NXP + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MIX_SLICE_SW_CTRL_OFF 0x20 +#define SLICE_SW_CTRL_PSW_CTRL_OFF_MASK BIT(4) +#define SLICE_SW_CTRL_PDN_SOFT_MASK BIT(31) + +#define MIX_FUNC_STAT_OFF 0xB4 + +#define FUNC_STAT_PSW_STAT_MASK BIT(0) +#define FUNC_STAT_RST_STAT_MASK BIT(2) +#define FUNC_STAT_ISO_STAT_MASK BIT(4) + +struct imx93_power_domain { + struct generic_pm_domain genpd; + struct device *dev; + void __iomem *addr; + struct clk_bulk_data *clks; + int num_clks; + bool init_off; +}; + +#define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd) + +static int imx93_pd_on(struct generic_pm_domain *genpd) +{ + struct imx93_power_domain *domain = to_imx93_pd(genpd); + void __iomem *addr = domain->addr; + u32 val; + int ret; + + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); + if (ret) { + dev_err(domain->dev, "failed to enable clocks for domain: %s\n", genpd->name); + return ret; + } + + val = readl(addr + MIX_SLICE_SW_CTRL_OFF); + val &= ~SLICE_SW_CTRL_PDN_SOFT_MASK; + writel(val, addr + MIX_SLICE_SW_CTRL_OFF); + + ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val, + !(val & FUNC_STAT_ISO_STAT_MASK), 1, 10000); + if (ret) { + dev_err(domain->dev, "pd_on timeout: name: %s, stat: %x\n", genpd->name, val); + return ret; + } + + return 0; +} + +static int imx93_pd_off(struct generic_pm_domain *genpd) +{ + struct imx93_power_domain *domain = to_imx93_pd(genpd); + void __iomem *addr = domain->addr; + int ret; + u32 val; + + /* Power off MIX */ + val = readl(addr + MIX_SLICE_SW_CTRL_OFF); + val |= SLICE_SW_CTRL_PDN_SOFT_MASK; + writel(val, addr + MIX_SLICE_SW_CTRL_OFF); + + ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val, + val & FUNC_STAT_PSW_STAT_MASK, 1, 1000); + if (ret) { + dev_err(domain->dev, "pd_off timeout: name: %s, stat: %x\n", genpd->name, val); + return ret; + } + + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + return 0; +}; + +static int imx93_pd_remove(struct platform_device *pdev) +{ + struct imx93_power_domain *domain = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + if (!domain->init_off) + clk_bulk_disable_unprepare(domain->num_clks, domain->clks); + + of_genpd_del_provider(np); + pm_genpd_remove(&domain->genpd); + + return 0; +} + +static int imx93_pd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct imx93_power_domain *domain; + int ret; + + domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); + if (!domain) + return -ENOMEM; + + domain->addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(domain->addr)) + return PTR_ERR(domain->addr); + + domain->num_clks = devm_clk_bulk_get_all(dev, &domain->clks); + if (domain->num_clks < 0) + return dev_err_probe(dev, domain->num_clks, "Failed to get domain's clocks\n"); + + domain->genpd.name = dev_name(dev); + domain->genpd.power_off = imx93_pd_off; + domain->genpd.power_on = imx93_pd_on; + domain->dev = dev; + + domain->init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK; + /* Just to sync the status of hardware */ + if (!domain->init_off) { + ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); + if (ret) { + dev_err(domain->dev, "failed to enable clocks for domain: %s\n", + domain->genpd.name); + return ret; + } + } + + ret = pm_genpd_init(&domain->genpd, NULL, domain->init_off); + if (ret) + return ret; + + platform_set_drvdata(pdev, domain); + + return of_genpd_add_provider_simple(np, &domain->genpd); +} + +static const struct of_device_id imx93_pd_ids[] = { + { .compatible = "fsl,imx93-src-slice" }, + { } +}; +MODULE_DEVICE_TABLE(of, imx93_pd_ids); + +static struct platform_driver imx93_power_domain_driver = { + .driver = { + .name = "imx93_power_domain", + .owner = THIS_MODULE, + .of_match_table = imx93_pd_ids, + }, + .probe = imx93_pd_probe, + .remove = imx93_pd_remove, +}; +module_platform_driver(imx93_power_domain_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("NXP i.MX93 power domain driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/imx/imx93-src.c b/drivers/soc/imx/imx93-src.c new file mode 100644 index 000000000000..4d74921cae0f --- /dev/null +++ b/drivers/soc/imx/imx93-src.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 NXP + */ + +#include +#include +#include + +static int imx93_src_probe(struct platform_device *pdev) +{ + return devm_of_platform_populate(&pdev->dev); +} + +static const struct of_device_id imx93_src_ids[] = { + { .compatible = "fsl,imx93-src" }, + { } +}; +MODULE_DEVICE_TABLE(of, imx93_src_ids); + +static struct platform_driver imx93_src_driver = { + .driver = { + .name = "imx93_src", + .owner = THIS_MODULE, + .of_match_table = imx93_src_ids, + }, + .probe = imx93_src_probe, +}; +module_platform_driver(imx93_src_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("NXP i.MX93 src driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e9aa77d413c903ba4cf7da3fe0b419cae5b97a81 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 6 Sep 2022 11:28:15 +0800 Subject: soc: imx: add i.MX93 media blk ctrl driver Add i.MX93 mediamix blk ctrl support. i.MX93 mediamix blk ctrl has registers to set QoS(priority) value. It support default QoS value and cfg QoS value. Set an initial value from i.MX design team. If LCDIF/ISI/PXP wanna a different QoS value in future, they could use interconnect to request bandwidth. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/soc/imx/Makefile | 1 + drivers/soc/imx/imx93-blk-ctrl.c | 436 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 437 insertions(+) create mode 100644 drivers/soc/imx/imx93-blk-ctrl.c (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index a0baa2a01adb..7b4099ceafd6 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o +obj-$(CONFIG_SOC_IMX9) += imx93-blk-ctrl.o diff --git a/drivers/soc/imx/imx93-blk-ctrl.c b/drivers/soc/imx/imx93-blk-ctrl.c new file mode 100644 index 000000000000..2c600329436c --- /dev/null +++ b/drivers/soc/imx/imx93-blk-ctrl.c @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 NXP, Peng Fan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define BLK_SFT_RSTN 0x0 +#define BLK_CLK_EN 0x4 +#define BLK_MAX_CLKS 4 + +#define DOMAIN_MAX_CLKS 4 + +#define LCDIF_QOS_REG 0xC +#define LCDIF_DEFAULT_QOS_OFF 12 +#define LCDIF_CFG_QOS_OFF 8 + +#define PXP_QOS_REG 0x10 +#define PXP_R_DEFAULT_QOS_OFF 28 +#define PXP_R_CFG_QOS_OFF 24 +#define PXP_W_DEFAULT_QOS_OFF 20 +#define PXP_W_CFG_QOS_OFF 16 + +#define ISI_CACHE_REG 0x14 + +#define ISI_QOS_REG 0x1C +#define ISI_V_DEFAULT_QOS_OFF 28 +#define ISI_V_CFG_QOS_OFF 24 +#define ISI_U_DEFAULT_QOS_OFF 20 +#define ISI_U_CFG_QOS_OFF 16 +#define ISI_Y_R_DEFAULT_QOS_OFF 12 +#define ISI_Y_R_CFG_QOS_OFF 8 +#define ISI_Y_W_DEFAULT_QOS_OFF 4 +#define ISI_Y_W_CFG_QOS_OFF 0 + +#define PRIO_MASK 0xF + +#define PRIO(X) (X) + +struct imx93_blk_ctrl_domain; + +struct imx93_blk_ctrl { + struct device *dev; + struct regmap *regmap; + int num_clks; + struct clk_bulk_data clks[BLK_MAX_CLKS]; + struct imx93_blk_ctrl_domain *domains; + struct genpd_onecell_data onecell_data; +}; + +#define DOMAIN_MAX_QOS 4 + +struct imx93_blk_ctrl_qos { + u32 reg; + u32 cfg_off; + u32 default_prio; + u32 cfg_prio; +}; + +struct imx93_blk_ctrl_domain_data { + const char *name; + const char * const *clk_names; + int num_clks; + u32 rst_mask; + u32 clk_mask; + int num_qos; + struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS]; +}; + +struct imx93_blk_ctrl_domain { + struct generic_pm_domain genpd; + const struct imx93_blk_ctrl_domain_data *data; + struct clk_bulk_data clks[DOMAIN_MAX_CLKS]; + struct imx93_blk_ctrl *bc; +}; + +struct imx93_blk_ctrl_data { + const struct imx93_blk_ctrl_domain_data *domains; + int num_domains; + const char * const *clk_names; + int num_clks; + const struct regmap_access_table *reg_access_table; +}; + +static inline struct imx93_blk_ctrl_domain * +to_imx93_blk_ctrl_domain(struct generic_pm_domain *genpd) +{ + return container_of(genpd, struct imx93_blk_ctrl_domain, genpd); +} + +static int imx93_blk_ctrl_set_qos(struct imx93_blk_ctrl_domain *domain) +{ + const struct imx93_blk_ctrl_domain_data *data = domain->data; + struct imx93_blk_ctrl *bc = domain->bc; + const struct imx93_blk_ctrl_qos *qos; + u32 val, mask; + int i; + + for (i = 0; i < data->num_qos; i++) { + qos = &data->qos[i]; + + mask = PRIO_MASK << qos->cfg_off; + mask |= PRIO_MASK << (qos->cfg_off + 4); + val = qos->cfg_prio << qos->cfg_off; + val |= qos->default_prio << (qos->cfg_off + 4); + + regmap_write_bits(bc->regmap, qos->reg, mask, val); + + dev_dbg(bc->dev, "data->qos[i].reg 0x%x 0x%x\n", qos->reg, val); + } + + return 0; +} + +static int imx93_blk_ctrl_power_on(struct generic_pm_domain *genpd) +{ + struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd); + const struct imx93_blk_ctrl_domain_data *data = domain->data; + struct imx93_blk_ctrl *bc = domain->bc; + int ret; + + ret = clk_bulk_prepare_enable(bc->num_clks, bc->clks); + if (ret) { + dev_err(bc->dev, "failed to enable bus clocks\n"); + return ret; + } + + ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); + if (ret) { + clk_bulk_disable_unprepare(bc->num_clks, bc->clks); + dev_err(bc->dev, "failed to enable clocks\n"); + return ret; + } + + ret = pm_runtime_get_sync(bc->dev); + if (ret < 0) { + pm_runtime_put_noidle(bc->dev); + dev_err(bc->dev, "failed to power up domain\n"); + goto disable_clk; + } + + /* ungate clk */ + regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); + + /* release reset */ + regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); + + dev_dbg(bc->dev, "pd_on: name: %s\n", genpd->name); + + return imx93_blk_ctrl_set_qos(domain); + +disable_clk: + clk_bulk_disable_unprepare(data->num_clks, domain->clks); + + clk_bulk_disable_unprepare(bc->num_clks, bc->clks); + + return ret; +} + +static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd) +{ + struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd); + const struct imx93_blk_ctrl_domain_data *data = domain->data; + struct imx93_blk_ctrl *bc = domain->bc; + + dev_dbg(bc->dev, "pd_off: name: %s\n", genpd->name); + + regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); + regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask); + + pm_runtime_put(bc->dev); + + clk_bulk_disable_unprepare(data->num_clks, domain->clks); + + clk_bulk_disable_unprepare(bc->num_clks, bc->clks); + + return 0; +} + +static int imx93_blk_ctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct imx93_blk_ctrl_data *bc_data = of_device_get_match_data(dev); + struct imx93_blk_ctrl *bc; + void __iomem *base; + int i, ret; + + struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .rd_table = bc_data->reg_access_table, + .wr_table = bc_data->reg_access_table, + .max_register = SZ_4K, + }; + + bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL); + if (!bc) + return -ENOMEM; + + bc->dev = dev; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(bc->regmap)) + return dev_err_probe(dev, PTR_ERR(bc->regmap), + "failed to init regmap\n"); + + bc->domains = devm_kcalloc(dev, bc_data->num_domains, + sizeof(struct imx93_blk_ctrl_domain), + GFP_KERNEL); + if (!bc->domains) + return -ENOMEM; + + bc->onecell_data.num_domains = bc_data->num_domains; + bc->onecell_data.domains = + devm_kcalloc(dev, bc_data->num_domains, + sizeof(struct generic_pm_domain *), GFP_KERNEL); + if (!bc->onecell_data.domains) + return -ENOMEM; + + for (i = 0; i < bc_data->num_clks; i++) + bc->clks[i].id = bc_data->clk_names[i]; + bc->num_clks = bc_data->num_clks; + + ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks); + if (ret) { + dev_err_probe(dev, ret, "failed to get bus clock\n"); + return ret; + } + + for (i = 0; i < bc_data->num_domains; i++) { + const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i]; + struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; + int j; + + domain->data = data; + + for (j = 0; j < data->num_clks; j++) + domain->clks[j].id = data->clk_names[j]; + + ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); + if (ret) { + dev_err_probe(dev, ret, "failed to get clock\n"); + goto cleanup_pds; + } + + domain->genpd.name = data->name; + domain->genpd.power_on = imx93_blk_ctrl_power_on; + domain->genpd.power_off = imx93_blk_ctrl_power_off; + domain->bc = bc; + + ret = pm_genpd_init(&domain->genpd, NULL, true); + if (ret) { + dev_err_probe(dev, ret, "failed to init power domain\n"); + goto cleanup_pds; + } + + bc->onecell_data.domains[i] = &domain->genpd; + } + + pm_runtime_enable(dev); + + ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); + if (ret) { + dev_err_probe(dev, ret, "failed to add power domain provider\n"); + goto cleanup_pds; + } + + dev_set_drvdata(dev, bc); + + return 0; + +cleanup_pds: + for (i--; i >= 0; i--) + pm_genpd_remove(&bc->domains[i].genpd); + + return ret; +} + +static int imx93_blk_ctrl_remove(struct platform_device *pdev) +{ + struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); + int i; + + of_genpd_del_provider(pdev->dev.of_node); + + for (i = 0; bc->onecell_data.num_domains; i++) { + struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; + + pm_genpd_remove(&domain->genpd); + } + + return 0; +} + +static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = { + [IMX93_MEDIABLK_PD_MIPI_DSI] = { + .name = "mediablk-mipi-dsi", + .clk_names = (const char *[]){ "dsi" }, + .num_clks = 1, + .rst_mask = BIT(11) | BIT(12), + .clk_mask = BIT(11) | BIT(12), + }, + [IMX93_MEDIABLK_PD_MIPI_CSI] = { + .name = "mediablk-mipi-csi", + .clk_names = (const char *[]){ "cam", "csi" }, + .num_clks = 2, + .rst_mask = BIT(9) | BIT(10), + .clk_mask = BIT(9) | BIT(10), + }, + [IMX93_MEDIABLK_PD_PXP] = { + .name = "mediablk-pxp", + .clk_names = (const char *[]){ "pxp" }, + .num_clks = 1, + .rst_mask = BIT(7) | BIT(8), + .clk_mask = BIT(7) | BIT(8), + .num_qos = 2, + .qos = { + { + .reg = PXP_QOS_REG, + .cfg_off = PXP_R_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(6), + }, { + .reg = PXP_QOS_REG, + .cfg_off = PXP_W_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(6), + } + } + }, + [IMX93_MEDIABLK_PD_LCDIF] = { + .name = "mediablk-lcdif", + .clk_names = (const char *[]){ "disp", "lcdif" }, + .num_clks = 2, + .rst_mask = BIT(4) | BIT(5) | BIT(6), + .clk_mask = BIT(4) | BIT(5) | BIT(6), + .num_qos = 1, + .qos = { + { + .reg = LCDIF_QOS_REG, + .cfg_off = LCDIF_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(7), + } + } + }, + [IMX93_MEDIABLK_PD_ISI] = { + .name = "mediablk-isi", + .clk_names = (const char *[]){ "isi" }, + .num_clks = 1, + .rst_mask = BIT(2) | BIT(3), + .clk_mask = BIT(2) | BIT(3), + .num_qos = 4, + .qos = { + { + .reg = ISI_QOS_REG, + .cfg_off = ISI_Y_W_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(7), + }, { + .reg = ISI_QOS_REG, + .cfg_off = ISI_Y_R_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(7), + }, { + .reg = ISI_QOS_REG, + .cfg_off = ISI_U_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(7), + }, { + .reg = ISI_QOS_REG, + .cfg_off = ISI_V_CFG_QOS_OFF, + .default_prio = PRIO(3), + .cfg_prio = PRIO(7), + } + } + }, +}; + +static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = { + regmap_reg_range(BLK_SFT_RSTN, BLK_CLK_EN), + regmap_reg_range(LCDIF_QOS_REG, ISI_CACHE_REG), + regmap_reg_range(ISI_QOS_REG, ISI_QOS_REG), +}; + +static const struct regmap_access_table imx93_media_blk_ctl_access_table = { + .yes_ranges = imx93_media_blk_ctl_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges), +}; + +static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = { + .domains = imx93_media_blk_ctl_domain_data, + .num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data), + .clk_names = (const char *[]){ "axi", "apb", "nic", }, + .num_clks = 3, + .reg_access_table = &imx93_media_blk_ctl_access_table, +}; + +static const struct of_device_id imx93_blk_ctrl_of_match[] = { + { + .compatible = "fsl,imx93-media-blk-ctrl", + .data = &imx93_media_blk_ctl_dev_data + }, { + /* Sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match); + +static struct platform_driver imx93_blk_ctrl_driver = { + .probe = imx93_blk_ctrl_probe, + .remove = imx93_blk_ctrl_remove, + .driver = { + .name = "imx93-blk-ctrl", + .of_match_table = imx93_blk_ctrl_of_match, + }, +}; +module_platform_driver(imx93_blk_ctrl_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("i.MX93 BLK CTRL driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3