/* * i.MX8M Mini, Nano and Plus have a third DISPLAY_BLK_CTRL register * which is used to control the reset for the MIPI Phy. * Since it's only present in certain circumstances, * an if-statement should be used before setting and clearing this * register.
*/
u32 mipi_phy_rst_mask;
};
/* make sure bus domain is awake */
ret = pm_runtime_get_sync(bc->bus_power_dev); if (ret < 0) {
pm_runtime_put_noidle(bc->bus_power_dev);
dev_err(bc->dev, "failed to power up bus domain\n"); return ret;
}
/* put devices into reset */
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask); if (data->mipi_phy_rst_mask)
regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
/* enable upstream and blk-ctrl clocks to allow reset to propagate */
ret = clk_bulk_prepare_enable(data->num_clks, domain->clks); if (ret) {
dev_err(bc->dev, "failed to enable clocks\n"); goto bus_put;
}
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* power up upstream GPC domain */
ret = pm_runtime_get_sync(domain->power_dev); if (ret < 0) {
dev_err(bc->dev, "failed to power up peripheral domain\n"); goto clk_disable;
}
/* put devices into reset and disable clocks */ if (data->mipi_phy_rst_mask)
regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
for (j = 0; j < data->num_paths; j++) {
domain->paths[j].name = data->path_names[j]; /* Fake value for now, just let ICC could configure NoC mode/priority */
domain->paths[j].avg_bw = 1;
domain->paths[j].peak_bw = 1;
}
ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths); if (ret) { if (ret != -EPROBE_DEFER) {
dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
domain->num_paths = 0;
} else {
dev_err_probe(dev, ret, "failed to get noc entries\n"); goto cleanup_pds;
}
}
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n"); goto cleanup_pds;
}
domain->power_dev =
dev_pm_domain_attach_by_name(dev, data->gpc_name); if (IS_ERR_OR_NULL(domain->power_dev)) { if (!domain->power_dev)
ret = -ENODEV; else
ret = PTR_ERR(domain->power_dev);
dev_err_probe(dev, ret, "failed to attach power domain \"%s\"\n",
data->gpc_name); goto cleanup_pds;
}
ret = pm_genpd_init(&domain->genpd, NULL, true); if (ret) {
dev_err_probe(dev, ret, "failed to init power domain \"%s\"\n",
data->gpc_name);
dev_pm_domain_detach(domain->power_dev, true); goto cleanup_pds;
}
/* * We use runtime PM to trigger power on/off of the upstream GPC * domain, as a strict hierarchical parent/child power domain * setup doesn't allow us to meet the sequencing requirements. * This means we have nested locking of genpd locks, without the * nesting being visible at the genpd level, so we need a * separate lock class to make lockdep aware of the fact that * this are separate domain locks that can be nested without a * self-deadlock.
*/
lockdep_set_class(&domain->genpd.mlock,
&blk_ctrl_genpd_lock_class);
bc->onecell_data.domains[i] = &domain->genpd;
}
ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); if (ret) {
dev_err_probe(dev, ret, "failed to add power domain provider\n"); goto cleanup_pds;
}
bc->power_nb.notifier_call = bc_data->power_notifier_fn;
ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb); if (ret) {
dev_err_probe(dev, ret, "failed to add power notifier\n"); goto cleanup_provider;
}
dev_set_drvdata(dev, bc);
ret = devm_of_platform_populate(dev); if (ret) goto cleanup_provider;
return 0;
cleanup_provider:
of_genpd_del_provider(dev->of_node);
cleanup_pds: for (i--; i >= 0; i--) {
pm_genpd_remove(&bc->domains[i].genpd);
dev_pm_domain_detach(bc->domains[i].power_dev, true);
}
/* * This may look strange, but is done so the generic PM_SLEEP code * can power down our domains and more importantly power them up again * after resume, without tripping over our usage of runtime PM to * control the upstream GPC domains. Things happen in the right order * in the system suspend/resume paths due to the device parent/child * hierarchy.
*/
ret = pm_runtime_get_sync(bc->bus_power_dev); if (ret < 0) {
pm_runtime_put_noidle(bc->bus_power_dev); return ret;
}
for (i = 0; i < bc->onecell_data.num_domains; i++) { struct imx8m_blk_ctrl_domain *domain = &bc->domains[i];
ret = pm_runtime_get_sync(domain->power_dev); if (ret < 0) {
pm_runtime_put_noidle(domain->power_dev); goto out_fail;
}
}
return 0;
out_fail: for (i--; i >= 0; i--)
pm_runtime_put(bc->domains[i].power_dev);
if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) return NOTIFY_OK;
/* * The ADB in the VPUMIX domain has no separate reset and clock * enable bits, but is ungated together with the VPU clocks. To * allow the handshake with the GPC to progress we put the VPUs * in reset and ungate the clocks.
*/
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1) | BIT(2));
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1) | BIT(2));
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);
}
if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) return NOTIFY_OK;
/* Enable bus clock and deassert bus reset */
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(12));
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(6));
/* * 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.
*/ if (action == GENPD_NOTIFY_ON)
udelay(5);
if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) return NOTIFY_OK;
/* Enable bus clock and deassert bus reset */
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
/* * 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.
*/ if (action == GENPD_NOTIFY_ON)
udelay(5);
if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) return NOTIFY_OK;
/* Enable bus clock and deassert bus reset */
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
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 panic read hurry level for both LCDIF interfaces to * maximum priority to minimize chances of display FIFO * underflow.
*/
regmap_set_bits(bc->regmap, LCDIF_ARCACHE_CTRL,
FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
FIELD_PREP(LCDIF_0_RD_HURRY, 7)); /* Same here for ISI */
regmap_set_bits(bc->regmap, ISI_CACHE_CTRL,
FIELD_PREP(ISI_V_WR_HURRY, 7) |
FIELD_PREP(ISI_U_WR_HURRY, 7) |
FIELD_PREP(ISI_Y_WR_HURRY, 7));
}
if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) return NOTIFY_OK;
/* * The ADB in the VPUMIX domain has no separate reset and clock * enable bits, but is ungated and reset together with the VPUs. The * reset and clock enable inputs to the ADB is a logical OR of the * VPU bits. In order to set the G2 fuse bits, the G2 clock must * also be enabled.
*/
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(0) | BIT(1));
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(0) | BIT(1));
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);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.