pmdomain providers:

- imx: Assign child domains for imx93 to prevent power off when in use
  - imx: Fix i.MX8MP power up sequences
  - mediatek: Fix possible nullptr in HWV cleanup/on-check
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmpY0fEQHHVsZmhAa2Vy
 bmVsLm9yZwAKCRD+JoQlc1iMKZtVD/9E1rSTcAK/tHKIt2Ng8hLPZgWib8z8JjDj
 OU8i5kmMJHnymEcnWYllMFkAjJicVauo3kbNyMZqtU+TxDTqrZgUjWzO9Pu7OGMy
 ZA4YBBGnDQP7faRrfTDB31EVuwxziTq9kcctpqkYEiSWnN1+ZOpAF2vqfHvOEek0
 v82Wu6fSorZXeXYjH49sEEAW8qiel8u3gA6ctHv2MFXD7fqK6POTTWpHdvnBI0rp
 CRP4imWH6tTKC2FVMw5rLel+JzHU6y658Qg/gd2AVtG+8nQH/LX7gu0M2tg0E/Sq
 TTMbRSnS93+rlTyWSkJgIyQnlSGkYddHJEGDFxaUxfln2LiLCNeXgbPcJvAQIEji
 GH5AeJEoz6XtkVBsv4Aga+EG1O154YKQ8/jnGGM2q+cFrBItfeiNcSwhexHoNMnw
 hIcKW7lvmEUM/N/GS3wsBBJBftAz8bmeSITEqrVzscIZRVjWlElYrtAuG+cmKagc
 jamfwQDJ2WfzJz9lolSMbKobo6bJEzmxqvP6cN1iVgHkdm22BxE29q2/XACilzH4
 ASMHbkxd3gAR2P4HrzhxX6jn0SI7YxJCfrI1aYD6yKKp7MA2sdWBm3IVTREHZhP2
 5FiArPQced3tjdtlDfbXLan1AmEiZ49o31fEUssylA4D7Z1G8qKB7RXXphDayRM/
 ATNSav1EzQ==
 =tWH8
 -----END PGP SIGNATURE-----

Merge tag 'pmdomain-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm

Pull pmdomain fixes from Ulf Hansson:
 "imx:
   - Assign child domains for imx93 to prevent power off when in use
   - Fix i.MX8MP power up sequences

  mediatek:
   - Fix possible nullptr in HWV cleanup/on-check"

* tag 'pmdomain-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm:
  pmdomain: mediatek: Fix possible nullptr KP in HWV cleanup/on-check
  pmdomain: imx: Fix i.MX8MP VC8000E power up sequence
  pmdomain: imx: Fix i.MX8MP power notifier
  pmdomain: imx93-blk-ctrl: Extract PHY as shared domain for DSI/CSI
  dt-bindings: power: imx93: Add MIPI PHY power domain
This commit is contained in:
Linus Torvalds 2026-07-16 08:46:20 -07:00
commit 4302c3503c
4 changed files with 136 additions and 11 deletions

View File

@ -54,6 +54,15 @@ struct imx8m_blk_ctrl_domain_data {
* register.
*/
u32 mipi_phy_rst_mask;
/*
* VC8000E reset de-assertion edge and AXI clock may have a timing issue.
* Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off
* both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to
* VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is
* de-asserted by HW)
*/
bool is_errata_err050531;
};
#define DOMAIN_MAX_CLKS 4
@ -108,7 +117,11 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
dev_err(bc->dev, "failed to enable clocks\n");
goto bus_put;
}
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
if (data->is_errata_err050531)
regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
else
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* power up upstream GPC domain */
ret = pm_runtime_get_sync(domain->power_dev);
@ -117,6 +130,9 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
goto clk_disable;
}
if (data->is_errata_err050531)
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* wait for reset to propagate */
udelay(5);
@ -511,12 +527,38 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[]
.clk_mask = BIT(2),
.path_names = (const char *[]){"vc8000e"},
.num_paths = 1,
.is_errata_err050531 = true,
},
};
static int imx8mp_vpu_power_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
power_nb);
if (action == GENPD_NOTIFY_ON) {
/*
* On power up we have no software backchannel to the GPC to
* wait for the ADB handshake to happen, so we just delay for a
* bit. On power down the GPC driver waits for the handshake.
*/
udelay(5);
/* set "fuse" bits to enable the VPUs */
regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
}
return NOTIFY_OK;
}
static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = {
.max_reg = 0x18,
.power_notifier_fn = imx8mm_vpu_power_notifier,
.power_notifier_fn = imx8mp_vpu_power_notifier,
.domains = imx8mp_vpu_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data),
};

View File

@ -48,6 +48,8 @@
#define PRIO(X) (X)
#define BLK_CTRL_NO_PARENT UINT_MAX
struct imx93_blk_ctrl_domain;
struct imx93_blk_ctrl {
@ -68,12 +70,18 @@ struct imx93_blk_ctrl_qos {
u32 cfg_prio;
};
struct imx93_blk_ctrl_subdomain_link {
struct generic_pm_domain *parent;
struct generic_pm_domain *subdomain;
};
struct imx93_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
u32 rst_mask;
u32 clk_mask;
u32 parent;
int num_qos;
struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS];
};
@ -203,6 +211,13 @@ static void imx93_release_pm_genpd(void *data)
pm_genpd_remove(genpd);
}
static void imx93_release_subdomain(void *data)
{
struct imx93_blk_ctrl_subdomain_link *link = data;
pm_genpd_remove_subdomain(link->parent, link->subdomain);
}
static struct lock_class_key blk_ctrl_genpd_lock_class;
static int imx93_blk_ctrl_probe(struct platform_device *pdev)
@ -302,6 +317,34 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev)
bc->onecell_data.domains[i] = &domain->genpd;
}
for (i = 0; i < bc_data->num_domains; i++) {
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl_subdomain_link *link;
if (bc_data->skip_mask & BIT(i) ||
data->parent == BLK_CTRL_NO_PARENT)
continue;
link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL);
if (!link)
return -ENOMEM;
link->parent = &bc->domains[data->parent].genpd;
link->subdomain = &domain->genpd;
ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd,
&domain->genpd);
if (ret)
return dev_err_probe(dev, ret, "failed to add subdomain %s\n",
domain->genpd.name);
ret = devm_add_action_or_reset(dev, imx93_release_subdomain, link);
if (ret)
return dev_err_probe(dev, ret,
"failed to add subdomain release callback\n");
}
ret = devm_pm_runtime_enable(dev);
if (ret)
return dev_err_probe(dev, ret, "failed to enable pm-runtime\n");
@ -326,8 +369,9 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.name = "mediablk-mipi-dsi",
.clk_names = (const char *[]){ "dsi" },
.num_clks = 1,
.rst_mask = BIT(11) | BIT(12),
.clk_mask = BIT(11) | BIT(12),
.rst_mask = BIT(11),
.clk_mask = BIT(11),
.parent = IMX93_MEDIABLK_PD_MIPI_PHY,
},
[IMX93_MEDIABLK_PD_MIPI_CSI] = {
.name = "mediablk-mipi-csi",
@ -335,6 +379,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 2,
.rst_mask = BIT(9) | BIT(10),
.clk_mask = BIT(9) | BIT(10),
.parent = IMX93_MEDIABLK_PD_MIPI_PHY,
},
[IMX93_MEDIABLK_PD_PXP] = {
.name = "mediablk-pxp",
@ -342,6 +387,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 1,
.rst_mask = BIT(7) | BIT(8),
.clk_mask = BIT(7) | BIT(8),
.parent = BLK_CTRL_NO_PARENT,
.num_qos = 2,
.qos = {
{
@ -363,6 +409,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 2,
.rst_mask = BIT(4) | BIT(5) | BIT(6),
.clk_mask = BIT(4) | BIT(5) | BIT(6),
.parent = BLK_CTRL_NO_PARENT,
.num_qos = 1,
.qos = {
{
@ -379,6 +426,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
.num_clks = 1,
.rst_mask = BIT(2) | BIT(3),
.clk_mask = BIT(2) | BIT(3),
.parent = BLK_CTRL_NO_PARENT,
.num_qos = 4,
.qos = {
{
@ -404,6 +452,14 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[]
}
}
},
[IMX93_MEDIABLK_PD_MIPI_PHY] = {
.name = "mediablk-mipi-phy",
.clk_names = NULL,
.num_clks = 0,
.rst_mask = BIT(12),
.clk_mask = BIT(12),
.parent = BLK_CTRL_NO_PARENT,
},
};
static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = {

View File

@ -393,9 +393,8 @@ static int scpsys_hwv_power_on(struct generic_pm_domain *genpd)
return ret;
};
static int scpsys_hwv_power_off(struct generic_pm_domain *genpd)
static int scpsys_hwv_power_off_internal(struct scpsys_domain *pd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
struct scpsys *scpsys = pd->scpsys;
u32 val;
@ -464,6 +463,13 @@ static int scpsys_hwv_power_off(struct generic_pm_domain *genpd)
return ret;
};
static int scpsys_hwv_power_off(struct generic_pm_domain *genpd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
return scpsys_hwv_power_off_internal(pd);
}
static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
@ -694,9 +700,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
return ret;
}
static int scpsys_power_off(struct generic_pm_domain *genpd)
static int scpsys_power_off_internal(struct scpsys_domain *pd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
struct scpsys *scpsys = pd->scpsys;
bool tmp;
int ret;
@ -737,6 +742,13 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
return 0;
}
static int scpsys_power_off(struct generic_pm_domain *genpd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
return scpsys_power_off_internal(pd);
}
static struct
generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
{
@ -884,7 +896,14 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
* late_init time.
*/
if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
if (scpsys_domain_is_on(pd))
bool domain_is_on;
if (scpsys->soc_data->type == SCPSYS_MTCMOS_TYPE_HW_VOTER)
domain_is_on = scpsys_hwv_domain_is_enable_done(pd);
else
domain_is_on = scpsys_domain_is_on(pd);
if (domain_is_on)
dev_warn(scpsys->dev,
"%pOF: A default off power domain has been ON\n", node);
} else {
@ -973,6 +992,7 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren
static void scpsys_remove_one_domain(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
int ret;
/*
@ -984,8 +1004,14 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd)
dev_err(pd->scpsys->dev,
"failed to remove domain '%s' : %d - state may be inconsistent\n",
pd->genpd.name, ret);
if (scpsys_domain_is_on(pd))
scpsys_power_off(&pd->genpd);
if (scpsys->soc_data->type == SCPSYS_MTCMOS_TYPE_HW_VOTER) {
if (scpsys_hwv_domain_is_enable_done(pd))
scpsys_hwv_power_off_internal(pd);
} else {
if (scpsys_domain_is_on(pd))
scpsys_power_off_internal(pd);
}
clk_bulk_put(pd->num_clks, pd->clks);
clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);

View File

@ -11,5 +11,6 @@
#define IMX93_MEDIABLK_PD_PXP 2
#define IMX93_MEDIABLK_PD_LCDIF 3
#define IMX93_MEDIABLK_PD_ISI 4
#define IMX93_MEDIABLK_PD_MIPI_PHY 5
#endif