Re: [PATCH 4/5] soc: imx: imx8m-blk-ctrl: support i.MX8MP media blk ctrl noc settings

From: Laurent Pinchart
Date: Wed Apr 06 2022 - 10:05:08 EST


Hi Peng,

Thank you for the patch.

On Wed, Apr 06, 2022 at 04:23:29PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@xxxxxxx>
>
> The out of reset value of NoC is not a valid value, we need
> set it to a correct value. We only need to set it after power on.
>
> Signed-off-by: Peng Fan <peng.fan@xxxxxxx>
> ---
> drivers/soc/imx/imx8m-blk-ctrl.c | 109 +++++++++++++++++++++++++++++++
> 1 file changed, 109 insertions(+)
>
> diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c
> index 3a6abd70520c..5b382b4e6a64 100644
> --- a/drivers/soc/imx/imx8m-blk-ctrl.c
> +++ b/drivers/soc/imx/imx8m-blk-ctrl.c
> @@ -12,6 +12,7 @@
> #include <linux/pm_runtime.h>
> #include <linux/regmap.h>
> #include <linux/clk.h>
> +#include <linux/mfd/syscon.h>
>
> #include <dt-bindings/power/imx8mm-power.h>
> #include <dt-bindings/power/imx8mn-power.h>
> @@ -29,10 +30,19 @@ struct imx8m_blk_ctrl {
> struct notifier_block power_nb;
> struct device *bus_power_dev;
> struct regmap *regmap;
> + struct regmap *noc_regmap;
> struct imx8m_blk_ctrl_domain *domains;
> struct genpd_onecell_data onecell_data;
> };
>
> +struct imx8m_blk_ctrl_noc_data {
> + u32 off;

Maybe "offset" ?

> + u32 priority;
> + u32 mode;
> + u32 extctrl;
> +};
> +
> +#define DOMAIN_MAX_NOC 4

And a blank line here.

We have 3 NoC entries at most below, so this could be lowered, but I
wonder if it wouldn't be nicer to actually drop the macro (see below).

> struct imx8m_blk_ctrl_domain_data {
> const char *name;
> const char * const *clk_names;
> @@ -49,6 +59,7 @@ struct imx8m_blk_ctrl_domain_data {
> * register.
> */
> u32 mipi_phy_rst_mask;
> + const struct imx8m_blk_ctrl_noc_data *noc_data[DOMAIN_MAX_NOC];

This would become just

const struct imx8m_blk_ctrl_noc_data **noc_data;

> };
>
> #define DOMAIN_MAX_CLKS 3
> @@ -66,6 +77,7 @@ struct imx8m_blk_ctrl_data {
> notifier_fn_t power_notifier_fn;
> const struct imx8m_blk_ctrl_domain_data *domains;
> int num_domains;
> + bool has_noc;
> };
>
> static inline struct imx8m_blk_ctrl_domain *
> @@ -74,6 +86,27 @@ to_imx8m_blk_ctrl_domain(struct generic_pm_domain *genpd)
> return container_of(genpd, struct imx8m_blk_ctrl_domain, genpd);
> }
>
> +static int imx8m_blk_ctrl_noc_set(struct imx8m_blk_ctrl_domain *domain)
> +{
> + const struct imx8m_blk_ctrl_domain_data *data = domain->data;
> + struct imx8m_blk_ctrl *bc = domain->bc;
> + struct regmap *regmap = bc->noc_regmap;
> + int i;

As it can never be negative, you can make i an unsigned int.

> +
> + if (!data || !regmap)
> + return 0;
> +
> + for (i = 0; i < DOMAIN_MAX_NOC; i++) {
> + if (!data->noc_data[i])
> + continue;

With

const struct imx8m_blk_ctrl_noc_data *noc_data = &data->noc_data[i];

if (!noc_data)
continue;

you could then write

regmap_write(regmap, noc_data->off + 0x8, noc_data->priority);
regmap_write(regmap, noc_data->off + 0xc, noc_data->mode);
regmap_write(regmap, noc_data->off + 0x18, noc_data->extctrl);

which is a bit nicer.

If we drop the harcoded number of NoC entries, the loop could become

const struct imx8m_blk_ctrl_noc_data *noc_data;

for (i = 0; data->noc_data[i]; i++) {
const struct imx8m_blk_ctrl_noc_data *noc_data = data->noc_data[i];

regmap_write(regmap, noc_data->off + 0x8, noc_data->priority);
regmap_write(regmap, noc_data->off + 0xc, noc_data->mode);
regmap_write(regmap, noc_data->off + 0x18, noc_data->extctrl);
}

You would then need a sentinel entry at the end of the noc_data array,
initialized to NULL.

> + regmap_write(regmap, data->noc_data[i]->off + 0x8, data->noc_data[i]->priority);
> + regmap_write(regmap, data->noc_data[i]->off + 0xc, data->noc_data[i]->mode);
> + regmap_write(regmap, data->noc_data[i]->off + 0x18, data->noc_data[i]->extctrl);
> + }
> +
> + return 0;
> +}
> +
> static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
> {
> struct imx8m_blk_ctrl_domain *domain = to_imx8m_blk_ctrl_domain(genpd);
> @@ -117,6 +150,8 @@ 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);
>
> + imx8m_blk_ctrl_noc_set(domain);
> +
> /* disable upstream clocks */
> clk_bulk_disable_unprepare(data->num_clks, domain->clks);
>
> @@ -172,6 +207,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
> const struct imx8m_blk_ctrl_data *bc_data;
> struct device *dev = &pdev->dev;
> struct imx8m_blk_ctrl *bc;
> + struct regmap *regmap;
> void __iomem *base;
> int i, ret;
>
> @@ -218,6 +254,10 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
> return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
> "failed to attach power domain\n");
>
> + regmap = syscon_regmap_lookup_by_compatible("fsl,imx8m-noc");
> + if (!IS_ERR(regmap))
> + bc->noc_regmap = regmap;
> +
> for (i = 0; i < bc_data->num_domains; i++) {
> const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
> struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
> @@ -677,6 +717,55 @@ static int imx8mp_media_power_notifier(struct notifier_block *nb,
> return NOTIFY_OK;
> }
>
> +#define IMX8MP_MEDIABLK_LCDIF_RD 0
> +#define IMX8MP_MEDIABLK_LCDIF_WR 1
> +#define IMX8MP_MEDIABLK_ISI0 2
> +#define IMX8MP_MEDIABLK_ISI1 3
> +#define IMX8MP_MEDIABLK_ISI2 4

Would these be the two AXI write and the AXI read ports of the ISI ?
Could they then be named accordingly (e.g. ISI_WR0, ISI_WR1, ISI_RD) ? I
don't know which is which though.

> +#define IMX8MP_MEDIABLK_ISP0 5
> +#define IMX8MP_MEDIABLK_ISP1 6
> +#define IMX8MP_MEDIABLK_DWE 7
> +
> +static const struct imx8m_blk_ctrl_noc_data imx8mp_media_noc_data[] = {
> + [IMX8MP_MEDIABLK_LCDIF_RD] = {
> + .off = 0x980,
> + .priority = 0x80000202,
> + .extctrl = 1,
> + },
> + [IMX8MP_MEDIABLK_LCDIF_WR] = {
> + .off = 0xa00,
> + .priority = 0x80000202,
> + .extctrl = 1,
> + },
> + [IMX8MP_MEDIABLK_ISI0] = {
> + .off = 0xa80,
> + .priority = 0x80000202,
> + .extctrl = 1,
> + },
> + [IMX8MP_MEDIABLK_ISI1] = {
> + .off = 0xb00,
> + .priority = 0x80000202,
> + .extctrl = 1,
> + },
> + [IMX8MP_MEDIABLK_ISI2] = {
> + .off = 0xb80,
> + .priority = 0x80000202,
> + .extctrl = 1,
> + },
> + [IMX8MP_MEDIABLK_ISP0] = {
> + .off = 0xc00,
> + .priority = 0x80000707,
> + },
> + [IMX8MP_MEDIABLK_ISP1] = {
> + .off = 0xc80,
> + .priority = 0x80000707,
> + },
> + [IMX8MP_MEDIABLK_DWE] = {
> + .off = 0xd00,
> + .priority = 0x80000707,
> + },

This matches the TF-A implementation.

With the above comments taken into account,

Reviewed-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>

> +};
> +
> /*
> * From i.MX 8M Plus Applications Processor Reference Manual, Rev. 1,
> * section 13.2.2, 13.2.3
> @@ -708,6 +797,10 @@ 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),
> + .noc_data = {
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_LCDIF_RD],
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_LCDIF_WR],
> + },
> },
> [IMX8MP_MEDIABLK_PD_ISI] = {
> .name = "mediablk-isi",
> @@ -716,6 +809,11 @@ 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),
> + .noc_data = {
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_ISI0],
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_ISI1],
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_ISI2],
> + },
> },
> [IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
> .name = "mediablk-mipi-csi2-2",
> @@ -733,6 +831,10 @@ 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),
> + .noc_data = {
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_LCDIF_RD],
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_LCDIF_WR],
> + },
> },
> [IMX8MP_MEDIABLK_PD_ISP2] = {
> .name = "mediablk-isp2",
> @@ -749,6 +851,10 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
> .gpc_name = "isp1",
> .rst_mask = BIT(16) | BIT(17) | BIT(18),
> .clk_mask = BIT(16) | BIT(17) | BIT(18),
> + .noc_data = {
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_ISP0],
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_ISP1],
> + },
> },
> [IMX8MP_MEDIABLK_PD_DWE] = {
> .name = "mediablk-dwe",
> @@ -757,6 +863,9 @@ 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),
> + .noc_data = {
> + &imx8mp_media_noc_data[IMX8MP_MEDIABLK_DWE],
> + },
> },
> [IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
> .name = "mediablk-mipi-dsi-2",

--
Regards,

Laurent Pinchart