diff mbox series

[2/6] clk: mediatek: Add mt8173-mfgtop driver

Message ID 20240530083513.4135052-3-wenst@chromium.org (mailing list archive)
State Changes Requested, archived
Headers show
Series powervr: MT8173 GPU support | expand

Commit Message

Chen-Yu Tsai May 30, 2024, 8:35 a.m. UTC
The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
in the datasheet, that contains clock gates, some power sequence signal
delays, and other unknown registers that get toggled when the GPU is
powered on.

The clock gates are exposed as clocks provided by a clock controller,
while the power sequencing bits are exposed as one singular power domain.

Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
 drivers/clk/mediatek/Kconfig             |   9 +
 drivers/clk/mediatek/Makefile            |   1 +
 drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
 3 files changed, 250 insertions(+)
 create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c

Comments

AngeloGioacchino Del Regno May 30, 2024, 9:59 a.m. UTC | #1
Il 30/05/24 10:35, Chen-Yu Tsai ha scritto:
> The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
> in the datasheet, that contains clock gates, some power sequence signal
> delays, and other unknown registers that get toggled when the GPU is
> powered on.
> 
> The clock gates are exposed as clocks provided by a clock controller,
> while the power sequencing bits are exposed as one singular power domain.
> 
> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> ---
>   drivers/clk/mediatek/Kconfig             |   9 +
>   drivers/clk/mediatek/Makefile            |   1 +
>   drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
>   3 files changed, 250 insertions(+)
>   create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c
> 
> diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
> index 70a005e7e1b1..9e279c739f1c 100644
> --- a/drivers/clk/mediatek/Kconfig
> +++ b/drivers/clk/mediatek/Kconfig
> @@ -500,6 +500,15 @@ config COMMON_CLK_MT8173_IMGSYS
>   	help
>   	  This driver supports MediaTek MT8173 imgsys clocks.
>   
> +config COMMON_CLK_MT8173_MFGTOP
> +	tristate "Clock and power driver for MediaTek MT8173 mfgtop"
> +	depends on COMMON_CLK_MT8173
> +	default COMMON_CLK_MT8173
> +	select PM_GENERIC_DOMAINS
> +	select PM_GENERIC_DOMAINS_OF
> +	help
> +	  This driver supports MediaTek MT8173 mfgtop clocks and power domain.
> +
>   config COMMON_CLK_MT8173_MMSYS
>          tristate "Clock driver for MediaTek MT8173 mmsys"
>          depends on COMMON_CLK_MT8173
> diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
> index eeccfa039896..fdd3a76e12a1 100644
> --- a/drivers/clk/mediatek/Makefile
> +++ b/drivers/clk/mediatek/Makefile
> @@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
>   obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
>   				   clk-mt8173-pericfg.o clk-mt8173-topckgen.o
>   obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
> +obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
>   obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
>   obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
>   obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
> diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> new file mode 100644
> index 000000000000..85fa7a7453ed
> --- /dev/null
> +++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> @@ -0,0 +1,240 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2024 Google LLC
> + * Author: Chen-Yu Tsai <wenst@chromium.org>
> + *
> + * Based on driver in downstream ChromeOS v5.15 kernel.
> + *
> + * Copyright (c) 2014 MediaTek Inc.
> + * Author: Chiawen Lee <chiawen.lee@mediatek.com>
> + */
> +
> +#include <dt-bindings/clock/mt8173-clk.h>
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include "clk-gate.h"
> +#include "clk-mtk.h"
> +
> +static const struct mtk_gate_regs mfg_cg_regs = {
> +	.sta_ofs = 0x0000,
> +	.clr_ofs = 0x0008,
> +	.set_ofs = 0x0004,
> +};
> +
> +#define GATE_MFG(_id, _name, _parent, _shift, _flags)	\
> +		GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)

Extra tabulation: please fix

> +
> +/* TODO: The block actually has dividers for the core and mem clocks. */
> +static const struct mtk_gate mfg_clks[] = {
> +	GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
> +	GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
> +	GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
> +	GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
> +};
> +
> +static const struct mtk_clk_desc mfg_desc = {
> +	.clks = mfg_clks,
> +	.num_clks = ARRAY_SIZE(mfg_clks),
> +};
> +
> +struct mt8173_mfgtop_data {
> +	struct clk_hw_onecell_data *clk_data;
> +	struct regmap *regmap;
> +	struct generic_pm_domain genpd;
> +	struct of_phandle_args parent_pd, child_pd;
> +	struct clk *clk_26m;
> +};
> +
> +static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
> +	{ .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);

Please move of_match_clk_mt8173_mfgtop before clk_mt8173_mfgtop_drv for consistency
with all the other clock drivers.

> +
> +/* Delay count in clock cycles */
> +#define MFG_ACTIVE_POWER_CON0	0x24
> + #define RST_B_DELAY_CNT	GENMASK(7, 0)	/* pwr_rst_b de-assert delay during power-up */
> + #define CLK_EN_DELAY_CNT	GENMASK(15, 8)	/* CLK_DIS deassert delay during power-up */
> + #define CLK_DIS_DELAY_CNT	GENMASK(23, 16)	/* CLK_DIS assert delay during power-down */

The reason why I had EVT_FORCE_ABORT and ACTIVE_PWRCTL_EN in my driver is to
document that we're keeping the event force abort disabled and, more importantly,
we are keeping the "active power control" feature disabled.

Please, add those two - or at least the ACTIVE_PWRCTL_EN - to keep that documented,
or this information will be lost for sure.
If in the future the ACTIVE_PWRCTL feature will become usable, it's going to be
just a 30 seconds change, as the info is already there.

> +
> +#define MFG_ACTIVE_POWER_CON1	0x28
> + #define PWR_ON_S_DELAY_CNT	GENMASK(7, 0)	/* pwr_on_s assert delay during power-up */
> + #define ISO_DELAY_CNT		GENMASK(15, 8)	/* ISO assert delay during power-down */
> + #define ISOOFF_DELAY_CNT	GENMASK(23, 16)	/* ISO de-assert delay during power-up */
> + #define RST__DELAY_CNT		GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
> +
> +static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
> +{
> +	struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> +
> +	/* drives internal power management */
> +	clk_prepare_enable(data->clk_26m);
> +
> +	/* Power on/off delays for various signals */
> +	regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
> +		     FIELD_PREP(RST_B_DELAY_CNT, 77) |
> +		     FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
> +		     FIELD_PREP(CLK_DIS_DELAY_CNT, 60));

I get that this is kinda odd to read, but still...

FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
FIELD_PREP(ACTIVE_PWRCTL_EN, 0));

...please :-)


> +	regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
> +		     FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
> +		     FIELD_PREP(ISO_DELAY_CNT, 68) |
> +		     FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
> +		     FIELD_PREP(RST__DELAY_CNT, 77));
> +
> +	/* Magic numbers related to core switch sequence and delays */
> +	regmap_write(data->regmap, 0xe0, 0x7a710184);
> +	regmap_write(data->regmap, 0xe4, 0x835f6856);
> +	regmap_write(data->regmap, 0xe8, 0x002b0234);
> +	regmap_write(data->regmap, 0xec, 0x80000000);
> +	regmap_write(data->regmap, 0xa0, 0x08000000);

Is there any way to retrieve information about what those registers are?

> +
> +	return 0;
> +}
> +
> +static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
> +{
> +	struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> +
> +	/* Magic numbers related to core switch sequence and delays */
> +	regmap_write(data->regmap, 0xec, 0);
> +
> +	/* drives internal power management */
> +	clk_disable_unprepare(data->clk_26m);
> +
> +	return 0;
> +}
> +
> +static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *node = dev->of_node;
> +	struct mt8173_mfgtop_data *data;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
> +	if (!data->clk_data)
> +		return -ENOMEM;
> +
> +	/* MTK clock gates also uses regmap */
> +	data->regmap = device_node_to_regmap(node);
> +	if (IS_ERR(data->regmap))
> +		return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
> +
> +	data->child_pd.np = node;
> +	data->child_pd.args_count = 0;
> +	ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
> +					 &data->parent_pd);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to parse power domain\n");
> +
> +	devm_pm_runtime_enable(dev);
> +	/*
> +	 * Do a pm_runtime_resume_and_get() to workaround a possible
> +	 * deadlock between clk_register() and the genpd framework.
> +	 */
> +	ret = pm_runtime_resume_and_get(dev);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Failed to runtime resume device\n");
> +		goto put_of_node;
> +	}
> +
> +	ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
> +				     data->clk_data);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Failed to register clock gates\n");
> +		goto put_pm_runtime;
> +	}
> +
> +	data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
> +	if (IS_ERR(data->clk_26m)) {
> +		dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
> +		goto unregister_clks;
> +	}
> +
> +	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
> +		goto put_26m_clk;
> +	}
> +
> +	data->genpd.name = "mfg_apm";

"mfg-apm" or "mfg-pwr" please!

Everything else looks good.

Thanks for taking care of that, I started this work way too much time ago and
realistically I wouldn't have been able to finish it due to time constraints.

It's great to see that *finally* we can get some GPU upstream on this old SoC.
As its CPUs are really slow, LLVMPipe is quite unusable from a UX perspective
hence its only big issue was the lack of 3D HW acceleration.

This makes machines embedding this SoC usable, and that's simply awesome.

Cheers!
Angelo
Chen-Yu Tsai May 30, 2024, 10:16 a.m. UTC | #2
On Thu, May 30, 2024 at 5:59 PM AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> wrote:
>
> Il 30/05/24 10:35, Chen-Yu Tsai ha scritto:
> > The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
> > in the datasheet, that contains clock gates, some power sequence signal
> > delays, and other unknown registers that get toggled when the GPU is
> > powered on.
> >
> > The clock gates are exposed as clocks provided by a clock controller,
> > while the power sequencing bits are exposed as one singular power domain.
> >
> > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> > ---
> >   drivers/clk/mediatek/Kconfig             |   9 +
> >   drivers/clk/mediatek/Makefile            |   1 +
> >   drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
> >   3 files changed, 250 insertions(+)
> >   create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c
> >
> > diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
> > index 70a005e7e1b1..9e279c739f1c 100644
> > --- a/drivers/clk/mediatek/Kconfig
> > +++ b/drivers/clk/mediatek/Kconfig
> > @@ -500,6 +500,15 @@ config COMMON_CLK_MT8173_IMGSYS
> >       help
> >         This driver supports MediaTek MT8173 imgsys clocks.
> >
> > +config COMMON_CLK_MT8173_MFGTOP
> > +     tristate "Clock and power driver for MediaTek MT8173 mfgtop"
> > +     depends on COMMON_CLK_MT8173
> > +     default COMMON_CLK_MT8173
> > +     select PM_GENERIC_DOMAINS
> > +     select PM_GENERIC_DOMAINS_OF
> > +     help
> > +       This driver supports MediaTek MT8173 mfgtop clocks and power domain.
> > +
> >   config COMMON_CLK_MT8173_MMSYS
> >          tristate "Clock driver for MediaTek MT8173 mmsys"
> >          depends on COMMON_CLK_MT8173
> > diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
> > index eeccfa039896..fdd3a76e12a1 100644
> > --- a/drivers/clk/mediatek/Makefile
> > +++ b/drivers/clk/mediatek/Makefile
> > @@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
> >   obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
> >                                  clk-mt8173-pericfg.o clk-mt8173-topckgen.o
> >   obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
> > +obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
> >   obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
> >   obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
> >   obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
> > diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > new file mode 100644
> > index 000000000000..85fa7a7453ed
> > --- /dev/null
> > +++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > @@ -0,0 +1,240 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) 2024 Google LLC
> > + * Author: Chen-Yu Tsai <wenst@chromium.org>
> > + *
> > + * Based on driver in downstream ChromeOS v5.15 kernel.
> > + *
> > + * Copyright (c) 2014 MediaTek Inc.
> > + * Author: Chiawen Lee <chiawen.lee@mediatek.com>
> > + */
> > +
> > +#include <dt-bindings/clock/mt8173-clk.h>
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/clk.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_domain.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> > +
> > +#include "clk-gate.h"
> > +#include "clk-mtk.h"
> > +
> > +static const struct mtk_gate_regs mfg_cg_regs = {
> > +     .sta_ofs = 0x0000,
> > +     .clr_ofs = 0x0008,
> > +     .set_ofs = 0x0004,
> > +};
> > +
> > +#define GATE_MFG(_id, _name, _parent, _shift, _flags)        \
> > +             GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
>
> Extra tabulation: please fix

One tab instead of two? OK.

> > +
> > +/* TODO: The block actually has dividers for the core and mem clocks. */
> > +static const struct mtk_gate mfg_clks[] = {
> > +     GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
> > +     GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
> > +     GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
> > +     GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
> > +};
> > +
> > +static const struct mtk_clk_desc mfg_desc = {
> > +     .clks = mfg_clks,
> > +     .num_clks = ARRAY_SIZE(mfg_clks),
> > +};
> > +
> > +struct mt8173_mfgtop_data {
> > +     struct clk_hw_onecell_data *clk_data;
> > +     struct regmap *regmap;
> > +     struct generic_pm_domain genpd;
> > +     struct of_phandle_args parent_pd, child_pd;
> > +     struct clk *clk_26m;
> > +};
> > +
> > +static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
> > +     { .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
> > +     { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
>
> Please move of_match_clk_mt8173_mfgtop before clk_mt8173_mfgtop_drv for consistency
> with all the other clock drivers.

Ack.

> > +
> > +/* Delay count in clock cycles */
> > +#define MFG_ACTIVE_POWER_CON0        0x24
> > + #define RST_B_DELAY_CNT     GENMASK(7, 0)   /* pwr_rst_b de-assert delay during power-up */
> > + #define CLK_EN_DELAY_CNT    GENMASK(15, 8)  /* CLK_DIS deassert delay during power-up */
> > + #define CLK_DIS_DELAY_CNT   GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
>
> The reason why I had EVT_FORCE_ABORT and ACTIVE_PWRCTL_EN in my driver is to
> document that we're keeping the event force abort disabled and, more importantly,
> we are keeping the "active power control" feature disabled.
>
> Please, add those two - or at least the ACTIVE_PWRCTL_EN - to keep that documented,
> or this information will be lost for sure.
> If in the future the ACTIVE_PWRCTL feature will become usable, it's going to be
> just a 30 seconds change, as the info is already there.

OK.

> > +
> > +#define MFG_ACTIVE_POWER_CON1        0x28
> > + #define PWR_ON_S_DELAY_CNT  GENMASK(7, 0)   /* pwr_on_s assert delay during power-up */
> > + #define ISO_DELAY_CNT               GENMASK(15, 8)  /* ISO assert delay during power-down */
> > + #define ISOOFF_DELAY_CNT    GENMASK(23, 16) /* ISO de-assert delay during power-up */
> > + #define RST__DELAY_CNT              GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
> > +
> > +static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
> > +{
> > +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> > +
> > +     /* drives internal power management */
> > +     clk_prepare_enable(data->clk_26m);
> > +
> > +     /* Power on/off delays for various signals */
> > +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
> > +                  FIELD_PREP(RST_B_DELAY_CNT, 77) |
> > +                  FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
> > +                  FIELD_PREP(CLK_DIS_DELAY_CNT, 60));
>
> I get that this is kinda odd to read, but still...
>
> FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
> FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
>
> ...please :-)

Sure.

> > +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
> > +                  FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
> > +                  FIELD_PREP(ISO_DELAY_CNT, 68) |
> > +                  FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
> > +                  FIELD_PREP(RST__DELAY_CNT, 77));
> > +
> > +     /* Magic numbers related to core switch sequence and delays */
> > +     regmap_write(data->regmap, 0xe0, 0x7a710184);
> > +     regmap_write(data->regmap, 0xe4, 0x835f6856);
> > +     regmap_write(data->regmap, 0xe8, 0x002b0234);
> > +     regmap_write(data->regmap, 0xec, 0x80000000);
> > +     regmap_write(data->regmap, 0xa0, 0x08000000);
>
> Is there any way to retrieve information about what those registers are?

I asked. They said the project was too long ago, and they could only
figure out that it had something to do with core switch sequencing and
delays between each core, which is what I put in the comment there.

> > +
> > +     return 0;
> > +}
> > +
> > +static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
> > +{
> > +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> > +
> > +     /* Magic numbers related to core switch sequence and delays */
> > +     regmap_write(data->regmap, 0xec, 0);
> > +
> > +     /* drives internal power management */
> > +     clk_disable_unprepare(data->clk_26m);
> > +
> > +     return 0;
> > +}
> > +
> > +static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
> > +{
> > +     struct device *dev = &pdev->dev;
> > +     struct device_node *node = dev->of_node;
> > +     struct mt8173_mfgtop_data *data;
> > +     int ret;
> > +
> > +     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> > +     if (!data)
> > +             return -ENOMEM;
> > +
> > +     platform_set_drvdata(pdev, data);
> > +
> > +     data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
> > +     if (!data->clk_data)
> > +             return -ENOMEM;
> > +
> > +     /* MTK clock gates also uses regmap */
> > +     data->regmap = device_node_to_regmap(node);
> > +     if (IS_ERR(data->regmap))
> > +             return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
> > +
> > +     data->child_pd.np = node;
> > +     data->child_pd.args_count = 0;
> > +     ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
> > +                                      &data->parent_pd);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "Failed to parse power domain\n");
> > +
> > +     devm_pm_runtime_enable(dev);
> > +     /*
> > +      * Do a pm_runtime_resume_and_get() to workaround a possible
> > +      * deadlock between clk_register() and the genpd framework.
> > +      */
> > +     ret = pm_runtime_resume_and_get(dev);
> > +     if (ret) {
> > +             dev_err_probe(dev, ret, "Failed to runtime resume device\n");
> > +             goto put_of_node;
> > +     }
> > +
> > +     ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
> > +                                  data->clk_data);
> > +     if (ret) {
> > +             dev_err_probe(dev, ret, "Failed to register clock gates\n");
> > +             goto put_pm_runtime;
> > +     }
> > +
> > +     data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
> > +     if (IS_ERR(data->clk_26m)) {
> > +             dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
> > +             goto unregister_clks;
> > +     }
> > +
> > +     ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
> > +     if (ret) {
> > +             dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
> > +             goto put_26m_clk;
> > +     }
> > +
> > +     data->genpd.name = "mfg_apm";
>
> "mfg-apm" or "mfg-pwr" please!

Ack.

> Everything else looks good.
>
> Thanks for taking care of that, I started this work way too much time ago and
> realistically I wouldn't have been able to finish it due to time constraints.
>
> It's great to see that *finally* we can get some GPU upstream on this old SoC.
> As its CPUs are really slow, LLVMPipe is quite unusable from a UX perspective
> hence its only big issue was the lack of 3D HW acceleration.

I think there's still more work on the GPU driver side. I was digging
through the mailing list to find ways to get it running, and evidently
it doesn't fully support zink yet.

> This makes machines embedding this SoC usable, and that's simply awesome.

I'll give the patches a week to simmer while I go work on some
other stuff.

ChenYu
AngeloGioacchino Del Regno May 30, 2024, 12:48 p.m. UTC | #3
Il 30/05/24 12:16, Chen-Yu Tsai ha scritto:
> On Thu, May 30, 2024 at 5:59 PM AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com> wrote:
>>
>> Il 30/05/24 10:35, Chen-Yu Tsai ha scritto:
>>> The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
>>> in the datasheet, that contains clock gates, some power sequence signal
>>> delays, and other unknown registers that get toggled when the GPU is
>>> powered on.
>>>
>>> The clock gates are exposed as clocks provided by a clock controller,
>>> while the power sequencing bits are exposed as one singular power domain.
>>>
>>> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
>>> ---
>>>    drivers/clk/mediatek/Kconfig             |   9 +
>>>    drivers/clk/mediatek/Makefile            |   1 +
>>>    drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
>>>    3 files changed, 250 insertions(+)
>>>    create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c
>>>
>>> diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
>>> index 70a005e7e1b1..9e279c739f1c 100644
>>> --- a/drivers/clk/mediatek/Kconfig
>>> +++ b/drivers/clk/mediatek/Kconfig
>>> @@ -500,6 +500,15 @@ config COMMON_CLK_MT8173_IMGSYS
>>>        help
>>>          This driver supports MediaTek MT8173 imgsys clocks.
>>>
>>> +config COMMON_CLK_MT8173_MFGTOP
>>> +     tristate "Clock and power driver for MediaTek MT8173 mfgtop"
>>> +     depends on COMMON_CLK_MT8173
>>> +     default COMMON_CLK_MT8173
>>> +     select PM_GENERIC_DOMAINS
>>> +     select PM_GENERIC_DOMAINS_OF
>>> +     help
>>> +       This driver supports MediaTek MT8173 mfgtop clocks and power domain.
>>> +
>>>    config COMMON_CLK_MT8173_MMSYS
>>>           tristate "Clock driver for MediaTek MT8173 mmsys"
>>>           depends on COMMON_CLK_MT8173
>>> diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
>>> index eeccfa039896..fdd3a76e12a1 100644
>>> --- a/drivers/clk/mediatek/Makefile
>>> +++ b/drivers/clk/mediatek/Makefile
>>> @@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
>>>    obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
>>>                                   clk-mt8173-pericfg.o clk-mt8173-topckgen.o
>>>    obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
>>> +obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
>>>    obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
>>>    obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
>>>    obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
>>> diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
>>> new file mode 100644
>>> index 000000000000..85fa7a7453ed
>>> --- /dev/null
>>> +++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
>>> @@ -0,0 +1,240 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * Copyright (c) 2024 Google LLC
>>> + * Author: Chen-Yu Tsai <wenst@chromium.org>
>>> + *
>>> + * Based on driver in downstream ChromeOS v5.15 kernel.
>>> + *
>>> + * Copyright (c) 2014 MediaTek Inc.
>>> + * Author: Chiawen Lee <chiawen.lee@mediatek.com>
>>> + */
>>> +
>>> +#include <dt-bindings/clock/mt8173-clk.h>
>>> +
>>> +#include <linux/bitfield.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/mfd/syscon.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/pm_domain.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/regmap.h>
>>> +
>>> +#include "clk-gate.h"
>>> +#include "clk-mtk.h"
>>> +
>>> +static const struct mtk_gate_regs mfg_cg_regs = {
>>> +     .sta_ofs = 0x0000,
>>> +     .clr_ofs = 0x0008,
>>> +     .set_ofs = 0x0004,
>>> +};
>>> +
>>> +#define GATE_MFG(_id, _name, _parent, _shift, _flags)        \
>>> +             GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
>>
>> Extra tabulation: please fix
> 
> One tab instead of two? OK.
> 

Yeah.

>>> +
>>> +/* TODO: The block actually has dividers for the core and mem clocks. */
>>> +static const struct mtk_gate mfg_clks[] = {
>>> +     GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
>>> +     GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
>>> +     GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
>>> +     GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
>>> +};
>>> +
>>> +static const struct mtk_clk_desc mfg_desc = {
>>> +     .clks = mfg_clks,
>>> +     .num_clks = ARRAY_SIZE(mfg_clks),
>>> +};
>>> +
>>> +struct mt8173_mfgtop_data {
>>> +     struct clk_hw_onecell_data *clk_data;
>>> +     struct regmap *regmap;
>>> +     struct generic_pm_domain genpd;
>>> +     struct of_phandle_args parent_pd, child_pd;
>>> +     struct clk *clk_26m;
>>> +};
>>> +
>>> +static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
>>> +     { .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
>>> +     { /* sentinel */ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
>>
>> Please move of_match_clk_mt8173_mfgtop before clk_mt8173_mfgtop_drv for consistency
>> with all the other clock drivers.
> 
> Ack.
> 
>>> +
>>> +/* Delay count in clock cycles */
>>> +#define MFG_ACTIVE_POWER_CON0        0x24
>>> + #define RST_B_DELAY_CNT     GENMASK(7, 0)   /* pwr_rst_b de-assert delay during power-up */
>>> + #define CLK_EN_DELAY_CNT    GENMASK(15, 8)  /* CLK_DIS deassert delay during power-up */
>>> + #define CLK_DIS_DELAY_CNT   GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
>>
>> The reason why I had EVT_FORCE_ABORT and ACTIVE_PWRCTL_EN in my driver is to
>> document that we're keeping the event force abort disabled and, more importantly,
>> we are keeping the "active power control" feature disabled.
>>
>> Please, add those two - or at least the ACTIVE_PWRCTL_EN - to keep that documented,
>> or this information will be lost for sure.
>> If in the future the ACTIVE_PWRCTL feature will become usable, it's going to be
>> just a 30 seconds change, as the info is already there.
> 
> OK.
> 
>>> +
>>> +#define MFG_ACTIVE_POWER_CON1        0x28
>>> + #define PWR_ON_S_DELAY_CNT  GENMASK(7, 0)   /* pwr_on_s assert delay during power-up */
>>> + #define ISO_DELAY_CNT               GENMASK(15, 8)  /* ISO assert delay during power-down */
>>> + #define ISOOFF_DELAY_CNT    GENMASK(23, 16) /* ISO de-assert delay during power-up */
>>> + #define RST__DELAY_CNT              GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
>>> +
>>> +static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
>>> +{
>>> +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
>>> +
>>> +     /* drives internal power management */
>>> +     clk_prepare_enable(data->clk_26m);
>>> +
>>> +     /* Power on/off delays for various signals */
>>> +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
>>> +                  FIELD_PREP(RST_B_DELAY_CNT, 77) |
>>> +                  FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
>>> +                  FIELD_PREP(CLK_DIS_DELAY_CNT, 60));
>>
>> I get that this is kinda odd to read, but still...
>>
>> FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
>> FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
>>
>> ...please :-)
> 
> Sure.
> 
>>> +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
>>> +                  FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
>>> +                  FIELD_PREP(ISO_DELAY_CNT, 68) |
>>> +                  FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
>>> +                  FIELD_PREP(RST__DELAY_CNT, 77));
>>> +
>>> +     /* Magic numbers related to core switch sequence and delays */
>>> +     regmap_write(data->regmap, 0xe0, 0x7a710184);
>>> +     regmap_write(data->regmap, 0xe4, 0x835f6856);
>>> +     regmap_write(data->regmap, 0xe8, 0x002b0234);
>>> +     regmap_write(data->regmap, 0xec, 0x80000000);
>>> +     regmap_write(data->regmap, 0xa0, 0x08000000);
>>
>> Is there any way to retrieve information about what those registers are?
> 
> I asked. They said the project was too long ago, and they could only
> figure out that it had something to do with core switch sequencing and
> delays between each core, which is what I put in the comment there.
> 

That's a bit sad to read, but okay, I guess we'll call it a day and keep the
magic numbers around, as that's the only option. :-(

>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
>>> +{
>>> +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
>>> +
>>> +     /* Magic numbers related to core switch sequence and delays */
>>> +     regmap_write(data->regmap, 0xec, 0);
>>> +
>>> +     /* drives internal power management */
>>> +     clk_disable_unprepare(data->clk_26m);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
>>> +{
>>> +     struct device *dev = &pdev->dev;
>>> +     struct device_node *node = dev->of_node;
>>> +     struct mt8173_mfgtop_data *data;
>>> +     int ret;
>>> +
>>> +     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
>>> +     if (!data)
>>> +             return -ENOMEM;
>>> +
>>> +     platform_set_drvdata(pdev, data);
>>> +
>>> +     data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
>>> +     if (!data->clk_data)
>>> +             return -ENOMEM;
>>> +
>>> +     /* MTK clock gates also uses regmap */
>>> +     data->regmap = device_node_to_regmap(node);
>>> +     if (IS_ERR(data->regmap))
>>> +             return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
>>> +
>>> +     data->child_pd.np = node;
>>> +     data->child_pd.args_count = 0;
>>> +     ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
>>> +                                      &data->parent_pd);
>>> +     if (ret)
>>> +             return dev_err_probe(dev, ret, "Failed to parse power domain\n");
>>> +
>>> +     devm_pm_runtime_enable(dev);
>>> +     /*
>>> +      * Do a pm_runtime_resume_and_get() to workaround a possible
>>> +      * deadlock between clk_register() and the genpd framework.
>>> +      */
>>> +     ret = pm_runtime_resume_and_get(dev);
>>> +     if (ret) {
>>> +             dev_err_probe(dev, ret, "Failed to runtime resume device\n");
>>> +             goto put_of_node;
>>> +     }
>>> +
>>> +     ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
>>> +                                  data->clk_data);
>>> +     if (ret) {
>>> +             dev_err_probe(dev, ret, "Failed to register clock gates\n");
>>> +             goto put_pm_runtime;
>>> +     }
>>> +
>>> +     data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
>>> +     if (IS_ERR(data->clk_26m)) {
>>> +             dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
>>> +             goto unregister_clks;
>>> +     }
>>> +
>>> +     ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
>>> +     if (ret) {
>>> +             dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
>>> +             goto put_26m_clk;
>>> +     }
>>> +
>>> +     data->genpd.name = "mfg_apm";
>>
>> "mfg-apm" or "mfg-pwr" please!
> 
> Ack.
> 
>> Everything else looks good.
>>
>> Thanks for taking care of that, I started this work way too much time ago and
>> realistically I wouldn't have been able to finish it due to time constraints.
>>
>> It's great to see that *finally* we can get some GPU upstream on this old SoC.
>> As its CPUs are really slow, LLVMPipe is quite unusable from a UX perspective
>> hence its only big issue was the lack of 3D HW acceleration.
> 
> I think there's still more work on the GPU driver side. I was digging
> through the mailing list to find ways to get it running, and evidently
> it doesn't fully support zink yet.
> 

There's still more work to do, yes, but it's still a great advancement.

>> This makes machines embedding this SoC usable, and that's simply awesome.
> 
> I'll give the patches a week to simmer while I go work on some
> other stuff.
> 

Sure, no worries.

Cheers!
Angelo

> ChenYu
kernel test robot May 30, 2024, 4:15 p.m. UTC | #4
Hi Chen-Yu,

kernel test robot noticed the following build errors:

[auto build test ERROR on 1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Yu-Tsai/dt-bindings-clock-mediatek-Add-mt8173-mfgtop/20240530-163739
base:   1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0
patch link:    https://lore.kernel.org/r/20240530083513.4135052-3-wenst%40chromium.org
patch subject: [PATCH 2/6] clk: mediatek: Add mt8173-mfgtop driver
config: arc-randconfig-001-20240530 (https://download.01.org/0day-ci/archive/20240531/202405310018.2eeqgDyV-lkp@intel.com/config)
compiler: arc-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240531/202405310018.2eeqgDyV-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405310018.2eeqgDyV-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/pmdomain/core.c: In function 'genpd_queue_power_off_work':
   drivers/pmdomain/core.c:701:20: error: 'pm_wq' undeclared (first use in this function)
     701 |         queue_work(pm_wq, &genpd->power_off_work);
         |                    ^~~~~
   drivers/pmdomain/core.c:701:20: note: each undeclared identifier is reported only once for each function it appears in
   drivers/pmdomain/core.c: In function 'genpd_dev_pm_qos_notifier':
   drivers/pmdomain/core.c:900:39: error: 'struct dev_pm_info' has no member named 'ignore_children'
     900 |                 if (!dev || dev->power.ignore_children)
         |                                       ^
   drivers/pmdomain/core.c: In function 'rtpm_status_str':
>> drivers/pmdomain/core.c:3111:23: error: 'struct dev_pm_info' has no member named 'runtime_error'
    3111 |         if (dev->power.runtime_error)
         |                       ^
>> drivers/pmdomain/core.c:3113:28: error: 'struct dev_pm_info' has no member named 'disable_depth'
    3113 |         else if (dev->power.disable_depth)
         |                            ^
>> drivers/pmdomain/core.c:3115:28: error: 'struct dev_pm_info' has no member named 'runtime_status'
    3115 |         else if (dev->power.runtime_status < ARRAY_SIZE(status_lookup))
         |                            ^
   drivers/pmdomain/core.c:3116:45: error: 'struct dev_pm_info' has no member named 'runtime_status'
    3116 |                 p = status_lookup[dev->power.runtime_status];
         |                                             ^

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for PM_GENERIC_DOMAINS
   Depends on [n]: PM [=n]
   Selected by [m]:
   - COMMON_CLK_MT8173_MFGTOP [=m] && COMMON_CLK [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && COMMON_CLK_MT8173 [=m]


vim +3111 drivers/pmdomain/core.c

2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3095  
8b0510b52478a4e drivers/base/power/domain.c Jon Hunter        2016-08-11  3096  #ifdef CONFIG_DEBUG_FS
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3097  /*
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3098   * TODO: This function is a slightly modified version of rtpm_status_show
d30d819dc831078 drivers/base/power/domain.c Rafael J. Wysocki 2014-11-27  3099   * from sysfs.c, so generalize it.
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3100   */
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3101  static void rtpm_status_str(struct seq_file *s, struct device *dev)
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3102  {
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3103  	static const char * const status_lookup[] = {
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3104  		[RPM_ACTIVE] = "active",
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3105  		[RPM_RESUMING] = "resuming",
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3106  		[RPM_SUSPENDED] = "suspended",
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3107  		[RPM_SUSPENDING] = "suspending"
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3108  	};
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3109  	const char *p = "";
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3110  
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15 @3111  	if (dev->power.runtime_error)
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3112  		p = "error";
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15 @3113  	else if (dev->power.disable_depth)
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3114  		p = "unsupported";
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15 @3115  	else if (dev->power.runtime_status < ARRAY_SIZE(status_lookup))
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3116  		p = status_lookup[dev->power.runtime_status];
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3117  	else
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3118  		WARN_ON(1);
2bd5306a8764d94 drivers/base/power/domain.c Maciej Matraszek  2014-09-15  3119  
45fbc464b047b3f drivers/base/power/domain.c Dmitry Osipenko   2021-01-21  3120  	seq_printf(s, "%-25s  ", p);
45fbc464b047b3f drivers/base/power/domain.c Dmitry Osipenko   2021-01-21  3121  }
45fbc464b047b3f drivers/base/power/domain.c Dmitry Osipenko   2021-01-21  3122
kernel test robot May 30, 2024, 4:26 p.m. UTC | #5
Hi Chen-Yu,

kernel test robot noticed the following build errors:

[auto build test ERROR on 1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Yu-Tsai/dt-bindings-clock-mediatek-Add-mt8173-mfgtop/20240530-163739
base:   1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0
patch link:    https://lore.kernel.org/r/20240530083513.4135052-3-wenst%40chromium.org
patch subject: [PATCH 2/6] clk: mediatek: Add mt8173-mfgtop driver
config: arc-randconfig-002-20240530 (https://download.01.org/0day-ci/archive/20240531/202405310025.nOseddVa-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240531/202405310025.nOseddVa-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405310025.nOseddVa-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/pmdomain/core.c: In function 'genpd_queue_power_off_work':
>> drivers/pmdomain/core.c:701:20: error: 'pm_wq' undeclared (first use in this function)
     701 |         queue_work(pm_wq, &genpd->power_off_work);
         |                    ^~~~~
   drivers/pmdomain/core.c:701:20: note: each undeclared identifier is reported only once for each function it appears in
   drivers/pmdomain/core.c: In function 'genpd_dev_pm_qos_notifier':
>> drivers/pmdomain/core.c:900:39: error: 'struct dev_pm_info' has no member named 'ignore_children'
     900 |                 if (!dev || dev->power.ignore_children)
         |                                       ^
--
   drivers/pmdomain/governor.c: In function 'default_suspend_ok':
>> drivers/pmdomain/governor.c:87:24: error: 'struct dev_pm_info' has no member named 'ignore_children'
      87 |         if (!dev->power.ignore_children)
         |                        ^

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for PM_GENERIC_DOMAINS
   Depends on [n]: PM [=n]
   Selected by [y]:
   - COMMON_CLK_MT8173_MFGTOP [=y] && COMMON_CLK [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && COMMON_CLK_MT8173 [=y]


vim +/pm_wq +701 drivers/pmdomain/core.c

c8f0ea45169c57 drivers/base/power/domain.c Geert Uytterhoeven 2014-11-10  691  
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  692  /**
86e12eac1f7f84 drivers/base/power/domain.c Ulf Hansson        2016-12-08  693   * genpd_queue_power_off_work - Queue up the execution of genpd_power_off().
a3d09c73492e57 drivers/base/power/domain.c Moritz Fischer     2016-01-27  694   * @genpd: PM domain to power off.
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  695   *
86e12eac1f7f84 drivers/base/power/domain.c Ulf Hansson        2016-12-08  696   * Queue up the execution of genpd_power_off() unless it's already been done
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  697   * before.
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  698   */
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  699  static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  700  {
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02 @701  	queue_work(pm_wq, &genpd->power_off_work);
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  702  }
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  703  
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  704  /**
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  705   * genpd_power_off - Remove power from a given PM domain.
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  706   * @genpd: PM domain to power down.
3c64649d1cf9f3 drivers/base/power/domain.c Ulf Hansson        2017-02-17  707   * @one_dev_on: If invoked from genpd's ->runtime_suspend|resume() callback, the
3c64649d1cf9f3 drivers/base/power/domain.c Ulf Hansson        2017-02-17  708   * RPM status of the releated device is in an intermediate state, not yet turned
3c64649d1cf9f3 drivers/base/power/domain.c Ulf Hansson        2017-02-17  709   * into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not
3c64649d1cf9f3 drivers/base/power/domain.c Ulf Hansson        2017-02-17  710   * be RPM_SUSPENDED, while it tries to power off the PM domain.
763663c9715f5f drivers/base/power/domain.c Yang Yingliang     2021-05-12  711   * @depth: nesting count for lockdep.
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  712   *
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  713   * If all of the @genpd's devices have been suspended and all of its subdomains
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  714   * have been powered down, remove power from @genpd.
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  715   */
2da835452a0875 drivers/base/power/domain.c Ulf Hansson        2017-02-17  716  static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
2da835452a0875 drivers/base/power/domain.c Ulf Hansson        2017-02-17  717  			   unsigned int depth)
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  718  {
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  719  	struct pm_domain_data *pdd;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  720  	struct gpd_link *link;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  721  	unsigned int not_suspended = 0;
f63816e43d9044 drivers/base/power/domain.c Ulf Hansson        2020-09-24  722  	int ret;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  723  
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  724  	/*
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  725  	 * Do not try to power off the domain in the following situations:
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  726  	 * (1) The domain is already in the "power off" state.
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  727  	 * (2) System suspend is in progress.
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  728  	 */
41e2c8e0060db2 drivers/base/power/domain.c Ulf Hansson        2017-03-20  729  	if (!genpd_status_on(genpd) || genpd->prepared_count > 0)
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  730  		return 0;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  731  
ffaa42e8a40b7f drivers/base/power/domain.c Ulf Hansson        2017-03-20  732  	/*
ffaa42e8a40b7f drivers/base/power/domain.c Ulf Hansson        2017-03-20  733  	 * Abort power off for the PM domain in the following situations:
ffaa42e8a40b7f drivers/base/power/domain.c Ulf Hansson        2017-03-20  734  	 * (1) The domain is configured as always on.
ffaa42e8a40b7f drivers/base/power/domain.c Ulf Hansson        2017-03-20  735  	 * (2) When the domain has a subdomain being powered on.
ffaa42e8a40b7f drivers/base/power/domain.c Ulf Hansson        2017-03-20  736  	 */
ed61e18a4b4e44 drivers/base/power/domain.c Leonard Crestez    2019-04-30  737  	if (genpd_is_always_on(genpd) ||
ed61e18a4b4e44 drivers/base/power/domain.c Leonard Crestez    2019-04-30  738  			genpd_is_rpm_always_on(genpd) ||
ed61e18a4b4e44 drivers/base/power/domain.c Leonard Crestez    2019-04-30  739  			atomic_read(&genpd->sd_count) > 0)
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  740  		return -EBUSY;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  741  
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  742  	/*
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  743  	 * The children must be in their deepest (powered-off) states to allow
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  744  	 * the parent to be powered off. Note that, there's no need for
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  745  	 * additional locking, as powering on a child, requires the parent's
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  746  	 * lock to be acquired first.
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  747  	 */
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  748  	list_for_each_entry(link, &genpd->parent_links, parent_node) {
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  749  		struct generic_pm_domain *child = link->child;
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  750  		if (child->state_idx < child->state_count - 1)
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  751  			return -EBUSY;
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  752  	}
e7d90cfac5510f drivers/base/power/domain.c Ulf Hansson        2022-02-17  753  
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  754  	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  755  		/*
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  756  		 * Do not allow PM domain to be powered off, when an IRQ safe
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  757  		 * device is part of a non-IRQ safe domain.
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  758  		 */
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  759  		if (!pm_runtime_suspended(pdd->dev) ||
7a02444b8fc25a drivers/base/power/domain.c Ulf Hansson        2022-05-11  760  			irq_safe_dev_in_sleep_domain(pdd->dev, genpd))
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  761  			not_suspended++;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  762  	}
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  763  
3c64649d1cf9f3 drivers/base/power/domain.c Ulf Hansson        2017-02-17  764  	if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on))
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  765  		return -EBUSY;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  766  
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  767  	if (genpd->gov && genpd->gov->power_down_ok) {
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  768  		if (!genpd->gov->power_down_ok(&genpd->domain))
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  769  			return -EAGAIN;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  770  	}
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  771  
2c9b7f8772033c drivers/base/power/domain.c Ulf Hansson        2018-10-03  772  	/* Default to shallowest state. */
2c9b7f8772033c drivers/base/power/domain.c Ulf Hansson        2018-10-03  773  	if (!genpd->gov)
2c9b7f8772033c drivers/base/power/domain.c Ulf Hansson        2018-10-03  774  		genpd->state_idx = 0;
2c9b7f8772033c drivers/base/power/domain.c Ulf Hansson        2018-10-03  775  
f63816e43d9044 drivers/base/power/domain.c Ulf Hansson        2020-09-24  776  	/* Don't power off, if a child domain is waiting to power on. */
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  777  	if (atomic_read(&genpd->sd_count) > 0)
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  778  		return -EBUSY;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  779  
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  780  	ret = _genpd_power_off(genpd, true);
c6a113b52302ad drivers/base/power/domain.c Lina Iyer          2020-10-15  781  	if (ret) {
c6a113b52302ad drivers/base/power/domain.c Lina Iyer          2020-10-15  782  		genpd->states[genpd->state_idx].rejected++;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  783  		return ret;
c6a113b52302ad drivers/base/power/domain.c Lina Iyer          2020-10-15  784  	}
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  785  
49f618e1b669ef drivers/base/power/domain.c Ulf Hansson        2020-09-24  786  	genpd->status = GENPD_STATE_OFF;
afece3ab9a3640 drivers/base/power/domain.c Thara Gopinath     2017-07-14  787  	genpd_update_accounting(genpd);
c6a113b52302ad drivers/base/power/domain.c Lina Iyer          2020-10-15  788  	genpd->states[genpd->state_idx].usage++;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  789  
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  790  	list_for_each_entry(link, &genpd->child_links, child_node) {
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  791  		genpd_sd_counter_dec(link->parent);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  792  		genpd_lock_nested(link->parent, depth + 1);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  793  		genpd_power_off(link->parent, false, depth + 1);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  794  		genpd_unlock(link->parent);
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  795  	}
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  796  
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  797  	return 0;
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  798  }
1f8728b7adc4c2 drivers/base/power/domain.c Ulf Hansson        2017-02-17  799  
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  800  /**
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  801   * genpd_power_on - Restore power to a given PM domain and its parents.
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  802   * @genpd: PM domain to power up.
0106ef5146f9e8 drivers/base/power/domain.c Marek Szyprowski   2016-01-20  803   * @depth: nesting count for lockdep.
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  804   *
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  805   * Restore power to @genpd and all of its parents so that it is possible to
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  806   * resume a device belonging to it.
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  807   */
86e12eac1f7f84 drivers/base/power/domain.c Ulf Hansson        2016-12-08  808  static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  809  {
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  810  	struct gpd_link *link;
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  811  	int ret = 0;
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  812  
41e2c8e0060db2 drivers/base/power/domain.c Ulf Hansson        2017-03-20  813  	if (genpd_status_on(genpd))
3f241775c30365 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  814  		return 0;
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  815  
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  816  	/*
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  817  	 * The list is guaranteed not to change while the loop below is being
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  818  	 * executed, unless one of the parents' .power_on() callbacks fiddles
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  819  	 * with it.
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  820  	 */
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  821  	list_for_each_entry(link, &genpd->child_links, child_node) {
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  822  		struct generic_pm_domain *parent = link->parent;
0106ef5146f9e8 drivers/base/power/domain.c Marek Szyprowski   2016-01-20  823  
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  824  		genpd_sd_counter_inc(parent);
0106ef5146f9e8 drivers/base/power/domain.c Marek Szyprowski   2016-01-20  825  
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  826  		genpd_lock_nested(parent, depth + 1);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  827  		ret = genpd_power_on(parent, depth + 1);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  828  		genpd_unlock(parent);
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  829  
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  830  		if (ret) {
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  831  			genpd_sd_counter_dec(parent);
9e08cf42969709 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  832  			goto err;
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  833  		}
5063ce1571b738 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  834  	}
5248051b9afb66 drivers/base/power/domain.c Rafael J. Wysocki  2011-07-01  835  
86e12eac1f7f84 drivers/base/power/domain.c Ulf Hansson        2016-12-08  836  	ret = _genpd_power_on(genpd, true);
9e08cf42969709 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  837  	if (ret)
9e08cf42969709 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  838  		goto err;
0140d8bd47f798 drivers/base/power/domain.c Rafael J. Wysocki  2011-12-01  839  
49f618e1b669ef drivers/base/power/domain.c Ulf Hansson        2020-09-24  840  	genpd->status = GENPD_STATE_ON;
afece3ab9a3640 drivers/base/power/domain.c Thara Gopinath     2017-07-14  841  	genpd_update_accounting(genpd);
afece3ab9a3640 drivers/base/power/domain.c Thara Gopinath     2017-07-14  842  
3f241775c30365 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  843  	return 0;
9e08cf42969709 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  844  
9e08cf42969709 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  845   err:
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  846  	list_for_each_entry_continue_reverse(link,
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  847  					&genpd->child_links,
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  848  					child_node) {
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  849  		genpd_sd_counter_dec(link->parent);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  850  		genpd_lock_nested(link->parent, depth + 1);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  851  		genpd_power_off(link->parent, false, depth + 1);
8d87ae48ced2df drivers/base/power/domain.c Kees Cook          2020-07-08  852  		genpd_unlock(link->parent);
29e47e2173349e drivers/base/power/domain.c Ulf Hansson        2015-09-02  853  	}
9e08cf42969709 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  854  
3f241775c30365 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  855  	return ret;
3f241775c30365 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  856  }
3f241775c30365 drivers/base/power/domain.c Rafael J. Wysocki  2011-08-08  857  
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  858  static int genpd_dev_pm_start(struct device *dev)
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  859  {
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  860  	struct generic_pm_domain *genpd = dev_to_genpd(dev);
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  861  
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  862  	return genpd_start_dev(genpd, dev);
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  863  }
ea71c59669f17d drivers/base/power/domain.c Ulf Hansson        2019-10-16  864  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  865  static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  866  				     unsigned long val, void *ptr)
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  867  {
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  868  	struct generic_pm_domain_data *gpd_data;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  869  	struct device *dev;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  870  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  871  	gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  872  	dev = gpd_data->base.dev;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  873  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  874  	for (;;) {
f38d1a6d002526 drivers/base/power/domain.c Ulf Hansson        2022-05-11  875  		struct generic_pm_domain *genpd = ERR_PTR(-ENODATA);
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  876  		struct pm_domain_data *pdd;
66d29d802ef3bf drivers/base/power/domain.c Ulf Hansson        2022-05-11  877  		struct gpd_timing_data *td;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  878  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  879  		spin_lock_irq(&dev->power.lock);
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  880  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  881  		pdd = dev->power.subsys_data ?
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  882  				dev->power.subsys_data->domain_data : NULL;
b4883ca449473e drivers/base/power/domain.c Viresh Kumar       2017-05-16  883  		if (pdd) {
66d29d802ef3bf drivers/base/power/domain.c Ulf Hansson        2022-05-11  884  			td = to_gpd_data(pdd)->td;
f38d1a6d002526 drivers/base/power/domain.c Ulf Hansson        2022-05-11  885  			if (td) {
66d29d802ef3bf drivers/base/power/domain.c Ulf Hansson        2022-05-11  886  				td->constraint_changed = true;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  887  				genpd = dev_to_genpd(dev);
f38d1a6d002526 drivers/base/power/domain.c Ulf Hansson        2022-05-11  888  			}
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  889  		}
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  890  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  891  		spin_unlock_irq(&dev->power.lock);
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  892  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  893  		if (!IS_ERR(genpd)) {
35241d12f750d2 drivers/base/power/domain.c Lina Iyer          2016-10-14  894  			genpd_lock(genpd);
f38d1a6d002526 drivers/base/power/domain.c Ulf Hansson        2022-05-11  895  			genpd->gd->max_off_time_changed = true;
35241d12f750d2 drivers/base/power/domain.c Lina Iyer          2016-10-14  896  			genpd_unlock(genpd);
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  897  		}
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  898  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  899  		dev = dev->parent;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01 @900  		if (!dev || dev->power.ignore_children)
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  901  			break;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  902  	}
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  903  
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  904  	return NOTIFY_DONE;
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  905  }
6ff7bb0d02f829 drivers/base/power/domain.c Rafael J. Wysocki  2012-05-01  906
kernel test robot May 30, 2024, 6:03 p.m. UTC | #6
Hi Chen-Yu,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Yu-Tsai/dt-bindings-clock-mediatek-Add-mt8173-mfgtop/20240530-163739
base:   1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0
patch link:    https://lore.kernel.org/r/20240530083513.4135052-3-wenst%40chromium.org
patch subject: [PATCH 2/6] clk: mediatek: Add mt8173-mfgtop driver
config: x86_64-buildonly-randconfig-002-20240531 (https://download.01.org/0day-ci/archive/20240531/202405310123.KWoPspRr-lkp@intel.com/config)
compiler: gcc-13 (Ubuntu 13.2.0-4ubuntu3) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240531/202405310123.KWoPspRr-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405310123.KWoPspRr-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/pmdomain/core.c:2965:34: warning: 'idle_state_match' defined but not used [-Wunused-const-variable=]
    2965 | static const struct of_device_id idle_state_match[] = {
         |                                  ^~~~~~~~~~~~~~~~

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for PM_GENERIC_DOMAINS_OF
   Depends on [n]: PM_GENERIC_DOMAINS [=y] && OF [=n]
   Selected by [y]:
   - COMMON_CLK_MT8173_MFGTOP [=y] && COMMON_CLK [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && COMMON_CLK_MT8173 [=y]


vim +/idle_state_match +2965 drivers/pmdomain/core.c

5d6be70add65e3 drivers/base/power/domain.c Ulf Hansson 2018-06-29  2964  
30f604283e05d3 drivers/base/power/domain.c Lina Iyer   2016-10-14 @2965  static const struct of_device_id idle_state_match[] = {
598da548ef7892 drivers/base/power/domain.c Lina Iyer   2016-11-03  2966  	{ .compatible = "domain-idle-state", },
30f604283e05d3 drivers/base/power/domain.c Lina Iyer   2016-10-14  2967  	{ }
30f604283e05d3 drivers/base/power/domain.c Lina Iyer   2016-10-14  2968  };
30f604283e05d3 drivers/base/power/domain.c Lina Iyer   2016-10-14  2969
Frank Binns May 31, 2024, 11:17 a.m. UTC | #7
On Thu, 2024-05-30 at 18:16 +0800, Chen-Yu Tsai wrote:
> On Thu, May 30, 2024 at 5:59 PM AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com> wrote:
> > Il 30/05/24 10:35, Chen-Yu Tsai ha scritto:
> > > The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
> > > in the datasheet, that contains clock gates, some power sequence signal
> > > delays, and other unknown registers that get toggled when the GPU is
> > > powered on.
> > > 
> > > The clock gates are exposed as clocks provided by a clock controller,
> > > while the power sequencing bits are exposed as one singular power domain.
> > > 
> > > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> > > ---
> > >   drivers/clk/mediatek/Kconfig             |   9 +
> > >   drivers/clk/mediatek/Makefile            |   1 +
> > >   drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
> > >   3 files changed, 250 insertions(+)
> > >   create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > > 
> > > diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
> > > index 70a005e7e1b1..9e279c739f1c 100644
> > > --- a/drivers/clk/mediatek/Kconfig
> > > +++ b/drivers/clk/mediatek/Kconfig
> > > @@ -500,6 +500,15 @@ config COMMON_CLK_MT8173_IMGSYS
> > >       help
> > >         This driver supports MediaTek MT8173 imgsys clocks.
> > > 
> > > +config COMMON_CLK_MT8173_MFGTOP
> > > +     tristate "Clock and power driver for MediaTek MT8173 mfgtop"
> > > +     depends on COMMON_CLK_MT8173
> > > +     default COMMON_CLK_MT8173
> > > +     select PM_GENERIC_DOMAINS
> > > +     select PM_GENERIC_DOMAINS_OF
> > > +     help
> > > +       This driver supports MediaTek MT8173 mfgtop clocks and power domain.
> > > +
> > >   config COMMON_CLK_MT8173_MMSYS
> > >          tristate "Clock driver for MediaTek MT8173 mmsys"
> > >          depends on COMMON_CLK_MT8173
> > > diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
> > > index eeccfa039896..fdd3a76e12a1 100644
> > > --- a/drivers/clk/mediatek/Makefile
> > > +++ b/drivers/clk/mediatek/Makefile
> > > @@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
> > >                                  clk-mt8173-pericfg.o clk-mt8173-topckgen.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
> > > +obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
> > > diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > > new file mode 100644
> > > index 000000000000..85fa7a7453ed
> > > --- /dev/null
> > > +++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > > @@ -0,0 +1,240 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Copyright (c) 2024 Google LLC
> > > + * Author: Chen-Yu Tsai <wenst@chromium.org>
> > > + *
> > > + * Based on driver in downstream ChromeOS v5.15 kernel.
> > > + *
> > > + * Copyright (c) 2014 MediaTek Inc.
> > > + * Author: Chiawen Lee <chiawen.lee@mediatek.com>
> > > + */
> > > +
> > > +#include <dt-bindings/clock/mt8173-clk.h>
> > > +
> > > +#include <linux/bitfield.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/mfd/syscon.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/pm_domain.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include <linux/regmap.h>
> > > +
> > > +#include "clk-gate.h"
> > > +#include "clk-mtk.h"
> > > +
> > > +static const struct mtk_gate_regs mfg_cg_regs = {
> > > +     .sta_ofs = 0x0000,
> > > +     .clr_ofs = 0x0008,
> > > +     .set_ofs = 0x0004,
> > > +};
> > > +
> > > +#define GATE_MFG(_id, _name, _parent, _shift, _flags)        \
> > > +             GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
> > 
> > Extra tabulation: please fix
> 
> One tab instead of two? OK.
> 
> > > +
> > > +/* TODO: The block actually has dividers for the core and mem clocks. */
> > > +static const struct mtk_gate mfg_clks[] = {
> > > +     GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
> > > +     GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
> > > +     GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
> > > +     GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
> > > +};
> > > +
> > > +static const struct mtk_clk_desc mfg_desc = {
> > > +     .clks = mfg_clks,
> > > +     .num_clks = ARRAY_SIZE(mfg_clks),
> > > +};
> > > +
> > > +struct mt8173_mfgtop_data {
> > > +     struct clk_hw_onecell_data *clk_data;
> > > +     struct regmap *regmap;
> > > +     struct generic_pm_domain genpd;
> > > +     struct of_phandle_args parent_pd, child_pd;
> > > +     struct clk *clk_26m;
> > > +};
> > > +
> > > +static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
> > > +     { .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
> > > +     { /* sentinel */ }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
> > 
> > Please move of_match_clk_mt8173_mfgtop before clk_mt8173_mfgtop_drv for consistency
> > with all the other clock drivers.
> 
> Ack.
> 
> > > +
> > > +/* Delay count in clock cycles */
> > > +#define MFG_ACTIVE_POWER_CON0        0x24
> > > + #define RST_B_DELAY_CNT     GENMASK(7, 0)   /* pwr_rst_b de-assert delay during power-up */
> > > + #define CLK_EN_DELAY_CNT    GENMASK(15, 8)  /* CLK_DIS deassert delay during power-up */
> > > + #define CLK_DIS_DELAY_CNT   GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
> > 
> > The reason why I had EVT_FORCE_ABORT and ACTIVE_PWRCTL_EN in my driver is to
> > document that we're keeping the event force abort disabled and, more importantly,
> > we are keeping the "active power control" feature disabled.
> > 
> > Please, add those two - or at least the ACTIVE_PWRCTL_EN - to keep that documented,
> > or this information will be lost for sure.
> > If in the future the ACTIVE_PWRCTL feature will become usable, it's going to be
> > just a 30 seconds change, as the info is already there.
> 
> OK.
> 
> > > +
> > > +#define MFG_ACTIVE_POWER_CON1        0x28
> > > + #define PWR_ON_S_DELAY_CNT  GENMASK(7, 0)   /* pwr_on_s assert delay during power-up */
> > > + #define ISO_DELAY_CNT               GENMASK(15, 8)  /* ISO assert delay during power-down */
> > > + #define ISOOFF_DELAY_CNT    GENMASK(23, 16) /* ISO de-assert delay during power-up */
> > > + #define RST__DELAY_CNT              GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
> > > +
> > > +static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
> > > +{
> > > +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> > > +
> > > +     /* drives internal power management */
> > > +     clk_prepare_enable(data->clk_26m);
> > > +
> > > +     /* Power on/off delays for various signals */
> > > +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
> > > +                  FIELD_PREP(RST_B_DELAY_CNT, 77) |
> > > +                  FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
> > > +                  FIELD_PREP(CLK_DIS_DELAY_CNT, 60));
> > 
> > I get that this is kinda odd to read, but still...
> > 
> > FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
> > FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
> > 
> > ...please :-)
> 
> Sure.
> 
> > > +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
> > > +                  FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
> > > +                  FIELD_PREP(ISO_DELAY_CNT, 68) |
> > > +                  FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
> > > +                  FIELD_PREP(RST__DELAY_CNT, 77));
> > > +
> > > +     /* Magic numbers related to core switch sequence and delays */
> > > +     regmap_write(data->regmap, 0xe0, 0x7a710184);
> > > +     regmap_write(data->regmap, 0xe4, 0x835f6856);
> > > +     regmap_write(data->regmap, 0xe8, 0x002b0234);
> > > +     regmap_write(data->regmap, 0xec, 0x80000000);
> > > +     regmap_write(data->regmap, 0xa0, 0x08000000);
> > 
> > Is there any way to retrieve information about what those registers are?
> 
> I asked. They said the project was too long ago, and they could only
> figure out that it had something to do with core switch sequencing and
> delays between each core, which is what I put in the comment there.
> 
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
> > > +{
> > > +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> > > +
> > > +     /* Magic numbers related to core switch sequence and delays */
> > > +     regmap_write(data->regmap, 0xec, 0);
> > > +
> > > +     /* drives internal power management */
> > > +     clk_disable_unprepare(data->clk_26m);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
> > > +{
> > > +     struct device *dev = &pdev->dev;
> > > +     struct device_node *node = dev->of_node;
> > > +     struct mt8173_mfgtop_data *data;
> > > +     int ret;
> > > +
> > > +     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> > > +     if (!data)
> > > +             return -ENOMEM;
> > > +
> > > +     platform_set_drvdata(pdev, data);
> > > +
> > > +     data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
> > > +     if (!data->clk_data)
> > > +             return -ENOMEM;
> > > +
> > > +     /* MTK clock gates also uses regmap */
> > > +     data->regmap = device_node_to_regmap(node);
> > > +     if (IS_ERR(data->regmap))
> > > +             return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
> > > +
> > > +     data->child_pd.np = node;
> > > +     data->child_pd.args_count = 0;
> > > +     ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
> > > +                                      &data->parent_pd);
> > > +     if (ret)
> > > +             return dev_err_probe(dev, ret, "Failed to parse power domain\n");
> > > +
> > > +     devm_pm_runtime_enable(dev);
> > > +     /*
> > > +      * Do a pm_runtime_resume_and_get() to workaround a possible
> > > +      * deadlock between clk_register() and the genpd framework.
> > > +      */
> > > +     ret = pm_runtime_resume_and_get(dev);
> > > +     if (ret) {
> > > +             dev_err_probe(dev, ret, "Failed to runtime resume device\n");
> > > +             goto put_of_node;
> > > +     }
> > > +
> > > +     ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
> > > +                                  data->clk_data);
> > > +     if (ret) {
> > > +             dev_err_probe(dev, ret, "Failed to register clock gates\n");
> > > +             goto put_pm_runtime;
> > > +     }
> > > +
> > > +     data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
> > > +     if (IS_ERR(data->clk_26m)) {
> > > +             dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
> > > +             goto unregister_clks;
> > > +     }
> > > +
> > > +     ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
> > > +     if (ret) {
> > > +             dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
> > > +             goto put_26m_clk;
> > > +     }
> > > +
> > > +     data->genpd.name = "mfg_apm";
> > 
> > "mfg-apm" or "mfg-pwr" please!
> 
> Ack.
> 
> > Everything else looks good.
> > 
> > Thanks for taking care of that, I started this work way too much time ago and
> > realistically I wouldn't have been able to finish it due to time constraints.
> > 
> > It's great to see that *finally* we can get some GPU upstream on this old SoC.
> > As its CPUs are really slow, LLVMPipe is quite unusable from a UX perspective
> > hence its only big issue was the lack of 3D HW acceleration.
> 
> I think there's still more work on the GPU driver side. I was digging
> through the mailing list to find ways to get it running, and evidently
> it doesn't fully support zink yet.

Upstream Mesa is still missing a lot of changes taking the driver up to Vulkan
1.0 on AXE-1-16M, which is the GPU we've mainly been focusing on. This work can
be found in our Mesa repo on FDO GitLab [1]. Support for GX6250 (Series 6XT) and
BXS-4-64 is currently incomplete (these are the other GPUs we've been adding
support for [2]).

The changes haven't made it upstream yet as we're in the process of reworking
the compiler and compiler/driver interface side of things to address the
inevitable comments we'd get as part of upstreaming. This work should be
complete soon and will go a long way towards improving support for / making it
easier to support more GPUs on the compiler side.

In parallel to this, we've implemented the Vulkan extensions, optional features,
etc needed by Zink [2] and we're currently fixing GLES conformance issues.
Again, we've been focusing on AXE-1-16M. Once we've got GLES conformance passing
we'll be switching our focus to completing support for the BXS-4-64.

Thanks
Frank

[1] https://gitlab.freedesktop.org/imagination/mesa/-/tree/powervr-mesa-next
[2] https://docs.mesa3d.org/drivers/powervr.html
[3] https://gitlab.freedesktop.org/imagination/mesa/-/tree/dev/zink

> 
> > This makes machines embedding this SoC usable, and that's simply awesome.
> 
> I'll give the patches a week to simmer while I go work on some
> other stuff.
> 
> ChenYu
Chen-Yu Tsai June 5, 2024, 8:39 a.m. UTC | #8
On Thu, May 30, 2024 at 6:16 PM Chen-Yu Tsai <wenst@chromium.org> wrote:
>
> On Thu, May 30, 2024 at 5:59 PM AngeloGioacchino Del Regno
> <angelogioacchino.delregno@collabora.com> wrote:
> >
> > Il 30/05/24 10:35, Chen-Yu Tsai ha scritto:
> > > The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
> > > in the datasheet, that contains clock gates, some power sequence signal
> > > delays, and other unknown registers that get toggled when the GPU is
> > > powered on.
> > >
> > > The clock gates are exposed as clocks provided by a clock controller,
> > > while the power sequencing bits are exposed as one singular power domain.
> > >
> > > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> > > ---
> > >   drivers/clk/mediatek/Kconfig             |   9 +
> > >   drivers/clk/mediatek/Makefile            |   1 +
> > >   drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
> > >   3 files changed, 250 insertions(+)
> > >   create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > >
> > > diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
> > > index 70a005e7e1b1..9e279c739f1c 100644
> > > --- a/drivers/clk/mediatek/Kconfig
> > > +++ b/drivers/clk/mediatek/Kconfig
> > > @@ -500,6 +500,15 @@ config COMMON_CLK_MT8173_IMGSYS
> > >       help
> > >         This driver supports MediaTek MT8173 imgsys clocks.
> > >
> > > +config COMMON_CLK_MT8173_MFGTOP
> > > +     tristate "Clock and power driver for MediaTek MT8173 mfgtop"
> > > +     depends on COMMON_CLK_MT8173
> > > +     default COMMON_CLK_MT8173
> > > +     select PM_GENERIC_DOMAINS
> > > +     select PM_GENERIC_DOMAINS_OF
> > > +     help
> > > +       This driver supports MediaTek MT8173 mfgtop clocks and power domain.
> > > +
> > >   config COMMON_CLK_MT8173_MMSYS
> > >          tristate "Clock driver for MediaTek MT8173 mmsys"
> > >          depends on COMMON_CLK_MT8173
> > > diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
> > > index eeccfa039896..fdd3a76e12a1 100644
> > > --- a/drivers/clk/mediatek/Makefile
> > > +++ b/drivers/clk/mediatek/Makefile
> > > @@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
> > >                                  clk-mt8173-pericfg.o clk-mt8173-topckgen.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
> > > +obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
> > >   obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
> > > diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > > new file mode 100644
> > > index 000000000000..85fa7a7453ed
> > > --- /dev/null
> > > +++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
> > > @@ -0,0 +1,240 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Copyright (c) 2024 Google LLC
> > > + * Author: Chen-Yu Tsai <wenst@chromium.org>
> > > + *
> > > + * Based on driver in downstream ChromeOS v5.15 kernel.
> > > + *
> > > + * Copyright (c) 2014 MediaTek Inc.
> > > + * Author: Chiawen Lee <chiawen.lee@mediatek.com>
> > > + */
> > > +
> > > +#include <dt-bindings/clock/mt8173-clk.h>
> > > +
> > > +#include <linux/bitfield.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/mfd/syscon.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/pm_domain.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include <linux/regmap.h>
> > > +
> > > +#include "clk-gate.h"
> > > +#include "clk-mtk.h"
> > > +
> > > +static const struct mtk_gate_regs mfg_cg_regs = {
> > > +     .sta_ofs = 0x0000,
> > > +     .clr_ofs = 0x0008,
> > > +     .set_ofs = 0x0004,
> > > +};
> > > +
> > > +#define GATE_MFG(_id, _name, _parent, _shift, _flags)        \
> > > +             GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
> >
> > Extra tabulation: please fix
>
> One tab instead of two? OK.
>
> > > +
> > > +/* TODO: The block actually has dividers for the core and mem clocks. */
> > > +static const struct mtk_gate mfg_clks[] = {
> > > +     GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
> > > +     GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
> > > +     GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
> > > +     GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
> > > +};
> > > +
> > > +static const struct mtk_clk_desc mfg_desc = {
> > > +     .clks = mfg_clks,
> > > +     .num_clks = ARRAY_SIZE(mfg_clks),
> > > +};
> > > +
> > > +struct mt8173_mfgtop_data {
> > > +     struct clk_hw_onecell_data *clk_data;
> > > +     struct regmap *regmap;
> > > +     struct generic_pm_domain genpd;
> > > +     struct of_phandle_args parent_pd, child_pd;
> > > +     struct clk *clk_26m;
> > > +};
> > > +
> > > +static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
> > > +     { .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
> > > +     { /* sentinel */ }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
> >
> > Please move of_match_clk_mt8173_mfgtop before clk_mt8173_mfgtop_drv for consistency
> > with all the other clock drivers.
>
> Ack.
>
> > > +
> > > +/* Delay count in clock cycles */
> > > +#define MFG_ACTIVE_POWER_CON0        0x24
> > > + #define RST_B_DELAY_CNT     GENMASK(7, 0)   /* pwr_rst_b de-assert delay during power-up */
> > > + #define CLK_EN_DELAY_CNT    GENMASK(15, 8)  /* CLK_DIS deassert delay during power-up */
> > > + #define CLK_DIS_DELAY_CNT   GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
> >
> > The reason why I had EVT_FORCE_ABORT and ACTIVE_PWRCTL_EN in my driver is to
> > document that we're keeping the event force abort disabled and, more importantly,
> > we are keeping the "active power control" feature disabled.
> >
> > Please, add those two - or at least the ACTIVE_PWRCTL_EN - to keep that documented,
> > or this information will be lost for sure.
> > If in the future the ACTIVE_PWRCTL feature will become usable, it's going to be
> > just a 30 seconds change, as the info is already there.
>
> OK.
>
> > > +
> > > +#define MFG_ACTIVE_POWER_CON1        0x28
> > > + #define PWR_ON_S_DELAY_CNT  GENMASK(7, 0)   /* pwr_on_s assert delay during power-up */
> > > + #define ISO_DELAY_CNT               GENMASK(15, 8)  /* ISO assert delay during power-down */
> > > + #define ISOOFF_DELAY_CNT    GENMASK(23, 16) /* ISO de-assert delay during power-up */
> > > + #define RST__DELAY_CNT              GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
> > > +
> > > +static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
> > > +{
> > > +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> > > +
> > > +     /* drives internal power management */
> > > +     clk_prepare_enable(data->clk_26m);
> > > +
> > > +     /* Power on/off delays for various signals */
> > > +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
> > > +                  FIELD_PREP(RST_B_DELAY_CNT, 77) |
> > > +                  FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
> > > +                  FIELD_PREP(CLK_DIS_DELAY_CNT, 60));
> >
> > I get that this is kinda odd to read, but still...
> >
> > FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
> > FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
> >
> > ...please :-)
>
> Sure.
>
> > > +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
> > > +                  FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
> > > +                  FIELD_PREP(ISO_DELAY_CNT, 68) |
> > > +                  FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
> > > +                  FIELD_PREP(RST__DELAY_CNT, 77));
> > > +
> > > +     /* Magic numbers related to core switch sequence and delays */
> > > +     regmap_write(data->regmap, 0xe0, 0x7a710184);
> > > +     regmap_write(data->regmap, 0xe4, 0x835f6856);
> > > +     regmap_write(data->regmap, 0xe8, 0x002b0234);
> > > +     regmap_write(data->regmap, 0xec, 0x80000000);
> > > +     regmap_write(data->regmap, 0xa0, 0x08000000);
> >
> > Is there any way to retrieve information about what those registers are?
>
> I asked. They said the project was too long ago, and they could only
> figure out that it had something to do with core switch sequencing and
> delays between each core, which is what I put in the comment there.
>
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
> > > +{
> > > +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
> > > +
> > > +     /* Magic numbers related to core switch sequence and delays */
> > > +     regmap_write(data->regmap, 0xec, 0);
> > > +
> > > +     /* drives internal power management */
> > > +     clk_disable_unprepare(data->clk_26m);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
> > > +{
> > > +     struct device *dev = &pdev->dev;
> > > +     struct device_node *node = dev->of_node;
> > > +     struct mt8173_mfgtop_data *data;
> > > +     int ret;
> > > +
> > > +     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> > > +     if (!data)
> > > +             return -ENOMEM;
> > > +
> > > +     platform_set_drvdata(pdev, data);
> > > +
> > > +     data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
> > > +     if (!data->clk_data)
> > > +             return -ENOMEM;
> > > +
> > > +     /* MTK clock gates also uses regmap */
> > > +     data->regmap = device_node_to_regmap(node);
> > > +     if (IS_ERR(data->regmap))
> > > +             return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
> > > +
> > > +     data->child_pd.np = node;
> > > +     data->child_pd.args_count = 0;
> > > +     ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
> > > +                                      &data->parent_pd);
> > > +     if (ret)
> > > +             return dev_err_probe(dev, ret, "Failed to parse power domain\n");
> > > +
> > > +     devm_pm_runtime_enable(dev);
> > > +     /*
> > > +      * Do a pm_runtime_resume_and_get() to workaround a possible
> > > +      * deadlock between clk_register() and the genpd framework.
> > > +      */
> > > +     ret = pm_runtime_resume_and_get(dev);
> > > +     if (ret) {
> > > +             dev_err_probe(dev, ret, "Failed to runtime resume device\n");
> > > +             goto put_of_node;
> > > +     }
> > > +
> > > +     ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
> > > +                                  data->clk_data);
> > > +     if (ret) {
> > > +             dev_err_probe(dev, ret, "Failed to register clock gates\n");
> > > +             goto put_pm_runtime;
> > > +     }
> > > +
> > > +     data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
> > > +     if (IS_ERR(data->clk_26m)) {
> > > +             dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
> > > +             goto unregister_clks;
> > > +     }
> > > +
> > > +     ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
> > > +     if (ret) {
> > > +             dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
> > > +             goto put_26m_clk;
> > > +     }
> > > +
> > > +     data->genpd.name = "mfg_apm";
> >
> > "mfg-apm" or "mfg-pwr" please!
>
> Ack.

On second thought, mfg-top seems like a better name, since it matches
the datasheet.

ChenYu

> > Everything else looks good.
> >
> > Thanks for taking care of that, I started this work way too much time ago and
> > realistically I wouldn't have been able to finish it due to time constraints.
> >
> > It's great to see that *finally* we can get some GPU upstream on this old SoC.
> > As its CPUs are really slow, LLVMPipe is quite unusable from a UX perspective
> > hence its only big issue was the lack of 3D HW acceleration.
>
> I think there's still more work on the GPU driver side. I was digging
> through the mailing list to find ways to get it running, and evidently
> it doesn't fully support zink yet.
>
> > This makes machines embedding this SoC usable, and that's simply awesome.
>
> I'll give the patches a week to simmer while I go work on some
> other stuff.
>
> ChenYu
AngeloGioacchino Del Regno June 5, 2024, 11:26 a.m. UTC | #9
Il 05/06/24 10:39, Chen-Yu Tsai ha scritto:
> On Thu, May 30, 2024 at 6:16 PM Chen-Yu Tsai <wenst@chromium.org> wrote:
>>
>> On Thu, May 30, 2024 at 5:59 PM AngeloGioacchino Del Regno
>> <angelogioacchino.delregno@collabora.com> wrote:
>>>
>>> Il 30/05/24 10:35, Chen-Yu Tsai ha scritto:
>>>> The MFG (GPU) block on the MT8173 has a small glue layer, named MFG_TOP
>>>> in the datasheet, that contains clock gates, some power sequence signal
>>>> delays, and other unknown registers that get toggled when the GPU is
>>>> powered on.
>>>>
>>>> The clock gates are exposed as clocks provided by a clock controller,
>>>> while the power sequencing bits are exposed as one singular power domain.
>>>>
>>>> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
>>>> ---
>>>>    drivers/clk/mediatek/Kconfig             |   9 +
>>>>    drivers/clk/mediatek/Makefile            |   1 +
>>>>    drivers/clk/mediatek/clk-mt8173-mfgtop.c | 240 +++++++++++++++++++++++
>>>>    3 files changed, 250 insertions(+)
>>>>    create mode 100644 drivers/clk/mediatek/clk-mt8173-mfgtop.c
>>>>
>>>> diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
>>>> index 70a005e7e1b1..9e279c739f1c 100644
>>>> --- a/drivers/clk/mediatek/Kconfig
>>>> +++ b/drivers/clk/mediatek/Kconfig
>>>> @@ -500,6 +500,15 @@ config COMMON_CLK_MT8173_IMGSYS
>>>>        help
>>>>          This driver supports MediaTek MT8173 imgsys clocks.
>>>>
>>>> +config COMMON_CLK_MT8173_MFGTOP
>>>> +     tristate "Clock and power driver for MediaTek MT8173 mfgtop"
>>>> +     depends on COMMON_CLK_MT8173
>>>> +     default COMMON_CLK_MT8173
>>>> +     select PM_GENERIC_DOMAINS
>>>> +     select PM_GENERIC_DOMAINS_OF
>>>> +     help
>>>> +       This driver supports MediaTek MT8173 mfgtop clocks and power domain.
>>>> +
>>>>    config COMMON_CLK_MT8173_MMSYS
>>>>           tristate "Clock driver for MediaTek MT8173 mmsys"
>>>>           depends on COMMON_CLK_MT8173
>>>> diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
>>>> index eeccfa039896..fdd3a76e12a1 100644
>>>> --- a/drivers/clk/mediatek/Makefile
>>>> +++ b/drivers/clk/mediatek/Makefile
>>>> @@ -77,6 +77,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
>>>>    obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
>>>>                                   clk-mt8173-pericfg.o clk-mt8173-topckgen.o
>>>>    obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
>>>> +obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
>>>>    obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
>>>>    obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
>>>>    obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
>>>> diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
>>>> new file mode 100644
>>>> index 000000000000..85fa7a7453ed
>>>> --- /dev/null
>>>> +++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
>>>> @@ -0,0 +1,240 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/*
>>>> + * Copyright (c) 2024 Google LLC
>>>> + * Author: Chen-Yu Tsai <wenst@chromium.org>
>>>> + *
>>>> + * Based on driver in downstream ChromeOS v5.15 kernel.
>>>> + *
>>>> + * Copyright (c) 2014 MediaTek Inc.
>>>> + * Author: Chiawen Lee <chiawen.lee@mediatek.com>
>>>> + */
>>>> +
>>>> +#include <dt-bindings/clock/mt8173-clk.h>
>>>> +
>>>> +#include <linux/bitfield.h>
>>>> +#include <linux/clk.h>
>>>> +#include <linux/mfd/syscon.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/pm_domain.h>
>>>> +#include <linux/pm_runtime.h>
>>>> +#include <linux/regmap.h>
>>>> +
>>>> +#include "clk-gate.h"
>>>> +#include "clk-mtk.h"
>>>> +
>>>> +static const struct mtk_gate_regs mfg_cg_regs = {
>>>> +     .sta_ofs = 0x0000,
>>>> +     .clr_ofs = 0x0008,
>>>> +     .set_ofs = 0x0004,
>>>> +};
>>>> +
>>>> +#define GATE_MFG(_id, _name, _parent, _shift, _flags)        \
>>>> +             GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
>>>
>>> Extra tabulation: please fix
>>
>> One tab instead of two? OK.
>>
>>>> +
>>>> +/* TODO: The block actually has dividers for the core and mem clocks. */
>>>> +static const struct mtk_gate mfg_clks[] = {
>>>> +     GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
>>>> +     GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
>>>> +     GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
>>>> +     GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
>>>> +};
>>>> +
>>>> +static const struct mtk_clk_desc mfg_desc = {
>>>> +     .clks = mfg_clks,
>>>> +     .num_clks = ARRAY_SIZE(mfg_clks),
>>>> +};
>>>> +
>>>> +struct mt8173_mfgtop_data {
>>>> +     struct clk_hw_onecell_data *clk_data;
>>>> +     struct regmap *regmap;
>>>> +     struct generic_pm_domain genpd;
>>>> +     struct of_phandle_args parent_pd, child_pd;
>>>> +     struct clk *clk_26m;
>>>> +};
>>>> +
>>>> +static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
>>>> +     { .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
>>>> +     { /* sentinel */ }
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
>>>
>>> Please move of_match_clk_mt8173_mfgtop before clk_mt8173_mfgtop_drv for consistency
>>> with all the other clock drivers.
>>
>> Ack.
>>
>>>> +
>>>> +/* Delay count in clock cycles */
>>>> +#define MFG_ACTIVE_POWER_CON0        0x24
>>>> + #define RST_B_DELAY_CNT     GENMASK(7, 0)   /* pwr_rst_b de-assert delay during power-up */
>>>> + #define CLK_EN_DELAY_CNT    GENMASK(15, 8)  /* CLK_DIS deassert delay during power-up */
>>>> + #define CLK_DIS_DELAY_CNT   GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
>>>
>>> The reason why I had EVT_FORCE_ABORT and ACTIVE_PWRCTL_EN in my driver is to
>>> document that we're keeping the event force abort disabled and, more importantly,
>>> we are keeping the "active power control" feature disabled.
>>>
>>> Please, add those two - or at least the ACTIVE_PWRCTL_EN - to keep that documented,
>>> or this information will be lost for sure.
>>> If in the future the ACTIVE_PWRCTL feature will become usable, it's going to be
>>> just a 30 seconds change, as the info is already there.
>>
>> OK.
>>
>>>> +
>>>> +#define MFG_ACTIVE_POWER_CON1        0x28
>>>> + #define PWR_ON_S_DELAY_CNT  GENMASK(7, 0)   /* pwr_on_s assert delay during power-up */
>>>> + #define ISO_DELAY_CNT               GENMASK(15, 8)  /* ISO assert delay during power-down */
>>>> + #define ISOOFF_DELAY_CNT    GENMASK(23, 16) /* ISO de-assert delay during power-up */
>>>> + #define RST__DELAY_CNT              GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
>>>> +
>>>> +static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
>>>> +{
>>>> +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
>>>> +
>>>> +     /* drives internal power management */
>>>> +     clk_prepare_enable(data->clk_26m);
>>>> +
>>>> +     /* Power on/off delays for various signals */
>>>> +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
>>>> +                  FIELD_PREP(RST_B_DELAY_CNT, 77) |
>>>> +                  FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
>>>> +                  FIELD_PREP(CLK_DIS_DELAY_CNT, 60));
>>>
>>> I get that this is kinda odd to read, but still...
>>>
>>> FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
>>> FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
>>>
>>> ...please :-)
>>
>> Sure.
>>
>>>> +     regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
>>>> +                  FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
>>>> +                  FIELD_PREP(ISO_DELAY_CNT, 68) |
>>>> +                  FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
>>>> +                  FIELD_PREP(RST__DELAY_CNT, 77));
>>>> +
>>>> +     /* Magic numbers related to core switch sequence and delays */
>>>> +     regmap_write(data->regmap, 0xe0, 0x7a710184);
>>>> +     regmap_write(data->regmap, 0xe4, 0x835f6856);
>>>> +     regmap_write(data->regmap, 0xe8, 0x002b0234);
>>>> +     regmap_write(data->regmap, 0xec, 0x80000000);
>>>> +     regmap_write(data->regmap, 0xa0, 0x08000000);
>>>
>>> Is there any way to retrieve information about what those registers are?
>>
>> I asked. They said the project was too long ago, and they could only
>> figure out that it had something to do with core switch sequencing and
>> delays between each core, which is what I put in the comment there.
>>
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
>>>> +{
>>>> +     struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
>>>> +
>>>> +     /* Magic numbers related to core switch sequence and delays */
>>>> +     regmap_write(data->regmap, 0xec, 0);
>>>> +
>>>> +     /* drives internal power management */
>>>> +     clk_disable_unprepare(data->clk_26m);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
>>>> +{
>>>> +     struct device *dev = &pdev->dev;
>>>> +     struct device_node *node = dev->of_node;
>>>> +     struct mt8173_mfgtop_data *data;
>>>> +     int ret;
>>>> +
>>>> +     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
>>>> +     if (!data)
>>>> +             return -ENOMEM;
>>>> +
>>>> +     platform_set_drvdata(pdev, data);
>>>> +
>>>> +     data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
>>>> +     if (!data->clk_data)
>>>> +             return -ENOMEM;
>>>> +
>>>> +     /* MTK clock gates also uses regmap */
>>>> +     data->regmap = device_node_to_regmap(node);
>>>> +     if (IS_ERR(data->regmap))
>>>> +             return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
>>>> +
>>>> +     data->child_pd.np = node;
>>>> +     data->child_pd.args_count = 0;
>>>> +     ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
>>>> +                                      &data->parent_pd);
>>>> +     if (ret)
>>>> +             return dev_err_probe(dev, ret, "Failed to parse power domain\n");
>>>> +
>>>> +     devm_pm_runtime_enable(dev);
>>>> +     /*
>>>> +      * Do a pm_runtime_resume_and_get() to workaround a possible
>>>> +      * deadlock between clk_register() and the genpd framework.
>>>> +      */
>>>> +     ret = pm_runtime_resume_and_get(dev);
>>>> +     if (ret) {
>>>> +             dev_err_probe(dev, ret, "Failed to runtime resume device\n");
>>>> +             goto put_of_node;
>>>> +     }
>>>> +
>>>> +     ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
>>>> +                                  data->clk_data);
>>>> +     if (ret) {
>>>> +             dev_err_probe(dev, ret, "Failed to register clock gates\n");
>>>> +             goto put_pm_runtime;
>>>> +     }
>>>> +
>>>> +     data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
>>>> +     if (IS_ERR(data->clk_26m)) {
>>>> +             dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
>>>> +             goto unregister_clks;
>>>> +     }
>>>> +
>>>> +     ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
>>>> +     if (ret) {
>>>> +             dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
>>>> +             goto put_26m_clk;
>>>> +     }
>>>> +
>>>> +     data->genpd.name = "mfg_apm";
>>>
>>> "mfg-apm" or "mfg-pwr" please!
>>
>> Ack.
> 
> On second thought, mfg-top seems like a better name, since it matches
> the datasheet.
> 

Yes, I definitely agree. Let's go for mfg-top.

Cheers!

> ChenYu
> 
>>> Everything else looks good.
>>>
>>> Thanks for taking care of that, I started this work way too much time ago and
>>> realistically I wouldn't have been able to finish it due to time constraints.
>>>
>>> It's great to see that *finally* we can get some GPU upstream on this old SoC.
>>> As its CPUs are really slow, LLVMPipe is quite unusable from a UX perspective
>>> hence its only big issue was the lack of 3D HW acceleration.
>>
>> I think there's still more work on the GPU driver side. I was digging
>> through the mailing list to find ways to get it running, and evidently
>> it doesn't fully support zink yet.
>>
>>> This makes machines embedding this SoC usable, and that's simply awesome.
>>
>> I'll give the patches a week to simmer while I go work on some
>> other stuff.
>>
>> ChenYu
diff mbox series

Patch

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 70a005e7e1b1..9e279c739f1c 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -500,6 +500,15 @@  config COMMON_CLK_MT8173_IMGSYS
 	help
 	  This driver supports MediaTek MT8173 imgsys clocks.
 
+config COMMON_CLK_MT8173_MFGTOP
+	tristate "Clock and power driver for MediaTek MT8173 mfgtop"
+	depends on COMMON_CLK_MT8173
+	default COMMON_CLK_MT8173
+	select PM_GENERIC_DOMAINS
+	select PM_GENERIC_DOMAINS_OF
+	help
+	  This driver supports MediaTek MT8173 mfgtop clocks and power domain.
+
 config COMMON_CLK_MT8173_MMSYS
        tristate "Clock driver for MediaTek MT8173 mmsys"
        depends on COMMON_CLK_MT8173
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index eeccfa039896..fdd3a76e12a1 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -77,6 +77,7 @@  obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
 obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
 				   clk-mt8173-pericfg.o clk-mt8173-topckgen.o
 obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
+obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
 obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
 obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
 obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
diff --git a/drivers/clk/mediatek/clk-mt8173-mfgtop.c b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
new file mode 100644
index 000000000000..85fa7a7453ed
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-mfgtop.c
@@ -0,0 +1,240 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 Google LLC
+ * Author: Chen-Yu Tsai <wenst@chromium.org>
+ *
+ * Based on driver in downstream ChromeOS v5.15 kernel.
+ *
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Chiawen Lee <chiawen.lee@mediatek.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "clk-gate.h"
+#include "clk-mtk.h"
+
+static const struct mtk_gate_regs mfg_cg_regs = {
+	.sta_ofs = 0x0000,
+	.clr_ofs = 0x0008,
+	.set_ofs = 0x0004,
+};
+
+#define GATE_MFG(_id, _name, _parent, _shift, _flags)	\
+		GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
+
+/* TODO: The block actually has dividers for the core and mem clocks. */
+static const struct mtk_gate mfg_clks[] = {
+	GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
+	GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
+	GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
+	GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
+};
+
+static const struct mtk_clk_desc mfg_desc = {
+	.clks = mfg_clks,
+	.num_clks = ARRAY_SIZE(mfg_clks),
+};
+
+struct mt8173_mfgtop_data {
+	struct clk_hw_onecell_data *clk_data;
+	struct regmap *regmap;
+	struct generic_pm_domain genpd;
+	struct of_phandle_args parent_pd, child_pd;
+	struct clk *clk_26m;
+};
+
+static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
+	{ .compatible = "mediatek,mt8173-mfgtop", .data = &mfg_desc },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
+
+/* Delay count in clock cycles */
+#define MFG_ACTIVE_POWER_CON0	0x24
+ #define RST_B_DELAY_CNT	GENMASK(7, 0)	/* pwr_rst_b de-assert delay during power-up */
+ #define CLK_EN_DELAY_CNT	GENMASK(15, 8)	/* CLK_DIS deassert delay during power-up */
+ #define CLK_DIS_DELAY_CNT	GENMASK(23, 16)	/* CLK_DIS assert delay during power-down */
+
+#define MFG_ACTIVE_POWER_CON1	0x28
+ #define PWR_ON_S_DELAY_CNT	GENMASK(7, 0)	/* pwr_on_s assert delay during power-up */
+ #define ISO_DELAY_CNT		GENMASK(15, 8)	/* ISO assert delay during power-down */
+ #define ISOOFF_DELAY_CNT	GENMASK(23, 16)	/* ISO de-assert delay during power-up */
+ #define RST__DELAY_CNT		GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
+
+static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
+{
+	struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
+
+	/* drives internal power management */
+	clk_prepare_enable(data->clk_26m);
+
+	/* Power on/off delays for various signals */
+	regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
+		     FIELD_PREP(RST_B_DELAY_CNT, 77) |
+		     FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
+		     FIELD_PREP(CLK_DIS_DELAY_CNT, 60));
+	regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
+		     FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
+		     FIELD_PREP(ISO_DELAY_CNT, 68) |
+		     FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
+		     FIELD_PREP(RST__DELAY_CNT, 77));
+
+	/* Magic numbers related to core switch sequence and delays */
+	regmap_write(data->regmap, 0xe0, 0x7a710184);
+	regmap_write(data->regmap, 0xe4, 0x835f6856);
+	regmap_write(data->regmap, 0xe8, 0x002b0234);
+	regmap_write(data->regmap, 0xec, 0x80000000);
+	regmap_write(data->regmap, 0xa0, 0x08000000);
+
+	return 0;
+}
+
+static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
+{
+	struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
+
+	/* Magic numbers related to core switch sequence and delays */
+	regmap_write(data->regmap, 0xec, 0);
+
+	/* drives internal power management */
+	clk_disable_unprepare(data->clk_26m);
+
+	return 0;
+}
+
+static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct mt8173_mfgtop_data *data;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, data);
+
+	data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
+	if (!data->clk_data)
+		return -ENOMEM;
+
+	/* MTK clock gates also uses regmap */
+	data->regmap = device_node_to_regmap(node);
+	if (IS_ERR(data->regmap))
+		return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
+
+	data->child_pd.np = node;
+	data->child_pd.args_count = 0;
+	ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
+					 &data->parent_pd);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to parse power domain\n");
+
+	devm_pm_runtime_enable(dev);
+	/*
+	 * Do a pm_runtime_resume_and_get() to workaround a possible
+	 * deadlock between clk_register() and the genpd framework.
+	 */
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to runtime resume device\n");
+		goto put_of_node;
+	}
+
+	ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
+				     data->clk_data);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to register clock gates\n");
+		goto put_pm_runtime;
+	}
+
+	data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
+	if (IS_ERR(data->clk_26m)) {
+		dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
+		goto unregister_clks;
+	}
+
+	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
+		goto put_26m_clk;
+	}
+
+	data->genpd.name = "mfg_apm";
+	data->genpd.power_on = clk_mt8173_mfgtop_power_on;
+	data->genpd.power_off = clk_mt8173_mfgtop_power_off;
+	ret = pm_genpd_init(&data->genpd, NULL, true);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to add power domain\n");
+		goto del_clk_provider;
+	}
+
+	ret = of_genpd_add_provider_simple(node, &data->genpd);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to add power domain OF provider\n");
+		goto remove_pd;
+	}
+
+	ret = of_genpd_add_subdomain(&data->parent_pd, &data->child_pd);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to link PM domains\n");
+		goto del_pd_provider;
+	}
+
+	pm_runtime_put(dev);
+	return 0;
+
+del_pd_provider:
+	of_genpd_del_provider(node);
+remove_pd:
+	pm_genpd_remove(&data->genpd);
+del_clk_provider:
+	of_clk_del_provider(node);
+put_26m_clk:
+	clk_put(data->clk_26m);
+unregister_clks:
+	mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
+put_pm_runtime:
+	pm_runtime_put(dev);
+put_of_node:
+	of_node_put(data->parent_pd.np);
+	return ret;
+}
+
+static void clk_mt8173_mfgtop_remove(struct platform_device *pdev)
+{
+	struct mt8173_mfgtop_data *data = platform_get_drvdata(pdev);
+	struct device_node *node = pdev->dev.of_node;
+
+	of_genpd_remove_subdomain(&data->parent_pd, &data->child_pd);
+	of_genpd_del_provider(node);
+	pm_genpd_remove(&data->genpd);
+	of_clk_del_provider(node);
+	clk_put(data->clk_26m);
+	mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
+}
+
+static struct platform_driver clk_mt8173_mfgtop_drv = {
+	.probe = clk_mt8173_mfgtop_probe,
+	.remove_new = clk_mt8173_mfgtop_remove,
+	.driver = {
+		.name = "clk-mt8173-mfgtop",
+		.of_match_table = of_match_clk_mt8173_mfgtop,
+	},
+};
+module_platform_driver(clk_mt8173_mfgtop_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 mfgtop clock driver");
+MODULE_LICENSE("GPL");