diff options
Diffstat (limited to 'drivers/gpu/drm/tegra')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 147 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dpaux.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 53 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.c | 177 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gr2d.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gr3d.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hdmi.c | 118 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 198 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/output.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/plane.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 210 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/vic.c | 8 |
15 files changed, 593 insertions, 402 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 714af052fbef..7c70fd31a4c2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1727,6 +1727,7 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, { struct tegra_dc *dc = to_tegra_dc(crtc); u32 value; + int err; if (!tegra_dc_idle(dc)) { tegra_dc_stop(dc); @@ -1773,7 +1774,9 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, spin_unlock_irq(&crtc->dev->event_lock); - pm_runtime_put_sync(dc->dev); + err = host1x_client_suspend(&dc->client); + if (err < 0) + dev_err(dc->dev, "failed to suspend: %d\n", err); } static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, @@ -1783,8 +1786,13 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, struct tegra_dc_state *state = to_dc_state(crtc->state); struct tegra_dc *dc = to_tegra_dc(crtc); u32 value; + int err; - pm_runtime_get_sync(dc->dev); + err = host1x_client_resume(&dc->client); + if (err < 0) { + dev_err(dc->dev, "failed to resume: %d\n", err); + return; + } /* initialize display controller */ if (dc->syncpt) { @@ -1996,7 +2004,7 @@ static bool tegra_dc_has_window_groups(struct tegra_dc *dc) static int tegra_dc_init(struct host1x_client *client) { - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; struct tegra_dc *dc = host1x_client_to_dc(client); struct tegra_drm *tegra = drm->dev_private; @@ -2012,6 +2020,15 @@ static int tegra_dc_init(struct host1x_client *client) if (!tegra_dc_has_window_groups(dc)) return 0; + /* + * Set the display hub as the host1x client parent for the display + * controller. This is needed for the runtime reference counting that + * ensures the display hub is always powered when any of the display + * controllers are. + */ + if (dc->soc->has_nvdisplay) + client->parent = &tegra->hub->client; + dc->syncpt = host1x_syncpt_request(client, flags); if (!dc->syncpt) dev_warn(dc->dev, "failed to allocate syncpoint\n"); @@ -2077,9 +2094,9 @@ static int tegra_dc_init(struct host1x_client *client) /* * Inherit the DMA parameters (such as maximum segment size) from the - * parent device. + * parent host1x device. */ - client->dev->dma_parms = client->parent->dma_parms; + client->dev->dma_parms = client->host->dma_parms; return 0; @@ -2121,9 +2138,74 @@ static int tegra_dc_exit(struct host1x_client *client) return 0; } +static int tegra_dc_runtime_suspend(struct host1x_client *client) +{ + struct tegra_dc *dc = host1x_client_to_dc(client); + struct device *dev = client->dev; + int err; + + err = reset_control_assert(dc->rst); + if (err < 0) { + dev_err(dev, "failed to assert reset: %d\n", err); + return err; + } + + if (dc->soc->has_powergate) + tegra_powergate_power_off(dc->powergate); + + clk_disable_unprepare(dc->clk); + pm_runtime_put_sync(dev); + + return 0; +} + +static int tegra_dc_runtime_resume(struct host1x_client *client) +{ + struct tegra_dc *dc = host1x_client_to_dc(client); + struct device *dev = client->dev; + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "failed to get runtime PM: %d\n", err); + return err; + } + + if (dc->soc->has_powergate) { + err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, + dc->rst); + if (err < 0) { + dev_err(dev, "failed to power partition: %d\n", err); + goto put_rpm; + } + } else { + err = clk_prepare_enable(dc->clk); + if (err < 0) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto put_rpm; + } + + err = reset_control_deassert(dc->rst); + if (err < 0) { + dev_err(dev, "failed to deassert reset: %d\n", err); + goto disable_clk; + } + } + + return 0; + +disable_clk: + clk_disable_unprepare(dc->clk); +put_rpm: + pm_runtime_put_sync(dev); + return err; +} + static const struct host1x_client_ops dc_client_ops = { .init = tegra_dc_init, .exit = tegra_dc_exit, + .suspend = tegra_dc_runtime_suspend, + .resume = tegra_dc_runtime_resume, }; static const struct tegra_dc_soc_info tegra20_dc_soc_info = { @@ -2535,65 +2617,10 @@ static int tegra_dc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int tegra_dc_suspend(struct device *dev) -{ - struct tegra_dc *dc = dev_get_drvdata(dev); - int err; - - err = reset_control_assert(dc->rst); - if (err < 0) { - dev_err(dev, "failed to assert reset: %d\n", err); - return err; - } - - if (dc->soc->has_powergate) - tegra_powergate_power_off(dc->powergate); - - clk_disable_unprepare(dc->clk); - - return 0; -} - -static int tegra_dc_resume(struct device *dev) -{ - struct tegra_dc *dc = dev_get_drvdata(dev); - int err; - - if (dc->soc->has_powergate) { - err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, - dc->rst); - if (err < 0) { - dev_err(dev, "failed to power partition: %d\n", err); - return err; - } - } else { - err = clk_prepare_enable(dc->clk); - if (err < 0) { - dev_err(dev, "failed to enable clock: %d\n", err); - return err; - } - - err = reset_control_deassert(dc->rst); - if (err < 0) { - dev_err(dev, "failed to deassert reset: %d\n", err); - return err; - } - } - - return 0; -} -#endif - -static const struct dev_pm_ops tegra_dc_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL) -}; - struct platform_driver tegra_dc_driver = { .driver = { .name = "tegra-dc", .of_match_table = tegra_dc_of_match, - .pm = &tegra_dc_pm_ops, }, .probe = tegra_dc_probe, .remove = tegra_dc_remove, diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 622cdf1ad246..7dfb50f65067 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -588,7 +588,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev) /* make sure pads are powered down when not in use */ tegra_dpaux_pad_power_down(dpaux); - pm_runtime_put(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); drm_dp_aux_unregister(&dpaux->aux); diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index f455ce71e85d..bd268028fb3d 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -905,7 +905,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, int host1x_client_iommu_attach(struct host1x_client *client) { struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev); - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); struct tegra_drm *tegra = drm->dev_private; struct iommu_group *group = NULL; int err; @@ -941,7 +941,7 @@ int host1x_client_iommu_attach(struct host1x_client *client) void host1x_client_iommu_detach(struct host1x_client *client) { - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); struct tegra_drm *tegra = drm->dev_private; struct iommu_domain *domain; @@ -1037,23 +1037,9 @@ void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt, free_pages((unsigned long)virt, get_order(size)); } -static int host1x_drm_probe(struct host1x_device *dev) +static bool host1x_drm_wants_iommu(struct host1x_device *dev) { - struct drm_driver *driver = &tegra_drm_driver; struct iommu_domain *domain; - struct tegra_drm *tegra; - struct drm_device *drm; - int err; - - drm = drm_dev_alloc(driver, &dev->dev); - if (IS_ERR(drm)) - return PTR_ERR(drm); - - tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); - if (!tegra) { - err = -ENOMEM; - goto put; - } /* * If the Tegra DRM clients are backed by an IOMMU, push buffers are @@ -1082,9 +1068,38 @@ static int host1x_drm_probe(struct host1x_device *dev) * up the device tree appropriately. This is considered an problem * of integration, so care must be taken for the DT to be consistent. */ - domain = iommu_get_domain_for_dev(drm->dev->parent); + domain = iommu_get_domain_for_dev(dev->dev.parent); + + /* + * Tegra20 and Tegra30 don't support addressing memory beyond the + * 32-bit boundary, so the regular GATHER opcodes will always be + * sufficient and whether or not the host1x is attached to an IOMMU + * doesn't matter. + */ + if (!domain && dma_get_mask(dev->dev.parent) <= DMA_BIT_MASK(32)) + return true; + + return domain != NULL; +} + +static int host1x_drm_probe(struct host1x_device *dev) +{ + struct drm_driver *driver = &tegra_drm_driver; + struct tegra_drm *tegra; + struct drm_device *drm; + int err; + + drm = drm_dev_alloc(driver, &dev->dev); + if (IS_ERR(drm)) + return PTR_ERR(drm); + + tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); + if (!tegra) { + err = -ENOMEM; + goto put; + } - if (domain && iommu_present(&platform_bus_type)) { + if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) { tegra->domain = iommu_domain_alloc(&platform_bus_type); if (!tegra->domain) { err = -ENOMEM; diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index d941553f7a3d..ed99b67deb29 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -144,6 +144,8 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output); void tegra_output_exit(struct tegra_output *output); void tegra_output_find_possible_crtcs(struct tegra_output *output, struct drm_device *drm); +int tegra_output_suspend(struct tegra_output *output); +int tegra_output_resume(struct tegra_output *output); int tegra_output_connector_get_modes(struct drm_connector *connector); enum drm_connector_status diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index a5d47e301c5f..88b9d64c77bf 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -840,7 +840,9 @@ static void tegra_dsi_unprepare(struct tegra_dsi *dsi) dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n", err); - pm_runtime_put(dsi->dev); + err = host1x_client_suspend(&dsi->client); + if (err < 0) + dev_err(dsi->dev, "failed to suspend: %d\n", err); } static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) @@ -882,11 +884,15 @@ static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) tegra_dsi_unprepare(dsi); } -static void tegra_dsi_prepare(struct tegra_dsi *dsi) +static int tegra_dsi_prepare(struct tegra_dsi *dsi) { int err; - pm_runtime_get_sync(dsi->dev); + err = host1x_client_resume(&dsi->client); + if (err < 0) { + dev_err(dsi->dev, "failed to resume: %d\n", err); + return err; + } err = tegra_mipi_enable(dsi->mipi); if (err < 0) @@ -899,6 +905,8 @@ static void tegra_dsi_prepare(struct tegra_dsi *dsi) if (dsi->slave) tegra_dsi_prepare(dsi->slave); + + return 0; } static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) @@ -909,8 +917,13 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) struct tegra_dsi *dsi = to_dsi(output); struct tegra_dsi_state *state; u32 value; + int err; - tegra_dsi_prepare(dsi); + err = tegra_dsi_prepare(dsi); + if (err < 0) { + dev_err(dsi->dev, "failed to prepare: %d\n", err); + return; + } state = tegra_dsi_get_state(dsi); @@ -1030,7 +1043,7 @@ static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = { static int tegra_dsi_init(struct host1x_client *client) { - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); struct tegra_dsi *dsi = host1x_client_to_dsi(client); int err; @@ -1075,9 +1088,89 @@ static int tegra_dsi_exit(struct host1x_client *client) return 0; } +static int tegra_dsi_runtime_suspend(struct host1x_client *client) +{ + struct tegra_dsi *dsi = host1x_client_to_dsi(client); + struct device *dev = client->dev; + int err; + + if (dsi->rst) { + err = reset_control_assert(dsi->rst); + if (err < 0) { + dev_err(dev, "failed to assert reset: %d\n", err); + return err; + } + } + + usleep_range(1000, 2000); + + clk_disable_unprepare(dsi->clk_lp); + clk_disable_unprepare(dsi->clk); + + regulator_disable(dsi->vdd); + pm_runtime_put_sync(dev); + + return 0; +} + +static int tegra_dsi_runtime_resume(struct host1x_client *client) +{ + struct tegra_dsi *dsi = host1x_client_to_dsi(client); + struct device *dev = client->dev; + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "failed to get runtime PM: %d\n", err); + return err; + } + + err = regulator_enable(dsi->vdd); + if (err < 0) { + dev_err(dev, "failed to enable VDD supply: %d\n", err); + goto put_rpm; + } + + err = clk_prepare_enable(dsi->clk); + if (err < 0) { + dev_err(dev, "cannot enable DSI clock: %d\n", err); + goto disable_vdd; + } + + err = clk_prepare_enable(dsi->clk_lp); + if (err < 0) { + dev_err(dev, "cannot enable low-power clock: %d\n", err); + goto disable_clk; + } + + usleep_range(1000, 2000); + + if (dsi->rst) { + err = reset_control_deassert(dsi->rst); + if (err < 0) { + dev_err(dev, "cannot assert reset: %d\n", err); + goto disable_clk_lp; + } + } + + return 0; + +disable_clk_lp: + clk_disable_unprepare(dsi->clk_lp); +disable_clk: + clk_disable_unprepare(dsi->clk); +disable_vdd: + regulator_disable(dsi->vdd); +put_rpm: + pm_runtime_put_sync(dev); + return err; +} + static const struct host1x_client_ops dsi_client_ops = { .init = tegra_dsi_init, .exit = tegra_dsi_exit, + .suspend = tegra_dsi_runtime_suspend, + .resume = tegra_dsi_runtime_resume, }; static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) @@ -1596,79 +1689,6 @@ static int tegra_dsi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int tegra_dsi_suspend(struct device *dev) -{ - struct tegra_dsi *dsi = dev_get_drvdata(dev); - int err; - - if (dsi->rst) { - err = reset_control_assert(dsi->rst); - if (err < 0) { - dev_err(dev, "failed to assert reset: %d\n", err); - return err; - } - } - - usleep_range(1000, 2000); - - clk_disable_unprepare(dsi->clk_lp); - clk_disable_unprepare(dsi->clk); - - regulator_disable(dsi->vdd); - - return 0; -} - -static int tegra_dsi_resume(struct device *dev) -{ - struct tegra_dsi *dsi = dev_get_drvdata(dev); - int err; - - err = regulator_enable(dsi->vdd); - if (err < 0) { - dev_err(dsi->dev, "failed to enable VDD supply: %d\n", err); - return err; - } - - err = clk_prepare_enable(dsi->clk); - if (err < 0) { - dev_err(dev, "cannot enable DSI clock: %d\n", err); - goto disable_vdd; - } - - err = clk_prepare_enable(dsi->clk_lp); - if (err < 0) { - dev_err(dev, "cannot enable low-power clock: %d\n", err); - goto disable_clk; - } - - usleep_range(1000, 2000); - - if (dsi->rst) { - err = reset_control_deassert(dsi->rst); - if (err < 0) { - dev_err(dev, "cannot assert reset: %d\n", err); - goto disable_clk_lp; - } - } - - return 0; - -disable_clk_lp: - clk_disable_unprepare(dsi->clk_lp); -disable_clk: - clk_disable_unprepare(dsi->clk); -disable_vdd: - regulator_disable(dsi->vdd); - return err; -} -#endif - -static const struct dev_pm_ops tegra_dsi_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_dsi_suspend, tegra_dsi_resume, NULL) -}; - static const struct of_device_id tegra_dsi_of_match[] = { { .compatible = "nvidia,tegra210-dsi", }, { .compatible = "nvidia,tegra132-dsi", }, @@ -1682,7 +1702,6 @@ struct platform_driver tegra_dsi_driver = { .driver = { .name = "tegra-dsi", .of_match_table = tegra_dsi_of_match, - .pm = &tegra_dsi_pm_ops, }, .probe = tegra_dsi_probe, .remove = tegra_dsi_remove, diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 1237df157e05..623768100c6a 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -60,8 +60,16 @@ static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo, /* * If we've manually mapped the buffer object through the IOMMU, make * sure to return the IOVA address of our mapping. + * + * Similarly, for buffers that have been allocated by the DMA API the + * physical address can be used for devices that are not attached to + * an IOMMU. For these devices, callers must pass a valid pointer via + * the @phys argument. + * + * Imported buffers were also already mapped at import time, so the + * existing mapping can be reused. */ - if (phys && obj->mm) { + if (phys) { *phys = obj->iova; return NULL; } diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 1fc4e56c7cc5..48363f744bb9 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -34,7 +34,7 @@ static inline struct gr2d *to_gr2d(struct tegra_drm_client *client) static int gr2d_init(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); - struct drm_device *dev = dev_get_drvdata(client->parent); + struct drm_device *dev = dev_get_drvdata(client->host); unsigned long flags = HOST1X_SYNCPT_HAS_BASE; struct gr2d *gr2d = to_gr2d(drm); int err; @@ -76,7 +76,7 @@ put: static int gr2d_exit(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); - struct drm_device *dev = dev_get_drvdata(client->parent); + struct drm_device *dev = dev_get_drvdata(client->host); struct tegra_drm *tegra = dev->dev_private; struct gr2d *gr2d = to_gr2d(drm); int err; diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 24fae0f64032..c0a528be0369 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -43,7 +43,7 @@ static inline struct gr3d *to_gr3d(struct tegra_drm_client *client) static int gr3d_init(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); - struct drm_device *dev = dev_get_drvdata(client->parent); + struct drm_device *dev = dev_get_drvdata(client->host); unsigned long flags = HOST1X_SYNCPT_HAS_BASE; struct gr3d *gr3d = to_gr3d(drm); int err; @@ -85,7 +85,7 @@ put: static int gr3d_exit(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); - struct drm_device *dev = dev_get_drvdata(client->parent); + struct drm_device *dev = dev_get_drvdata(client->host); struct gr3d *gr3d = to_gr3d(drm); int err; diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 21a629adcb51..6f117628f257 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1146,6 +1146,7 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) struct tegra_dc *dc = to_tegra_dc(encoder->crtc); struct tegra_hdmi *hdmi = to_hdmi(output); u32 value; + int err; /* * The following accesses registers of the display controller, so make @@ -1171,7 +1172,9 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_ENABLE); tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_MASK); - pm_runtime_put(hdmi->dev); + err = host1x_client_suspend(&hdmi->client); + if (err < 0) + dev_err(hdmi->dev, "failed to suspend: %d\n", err); } static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) @@ -1186,7 +1189,11 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) u32 value; int err; - pm_runtime_get_sync(hdmi->dev); + err = host1x_client_resume(&hdmi->client); + if (err < 0) { + dev_err(hdmi->dev, "failed to resume: %d\n", err); + return; + } /* * Enable and unmask the HDA codec SCRATCH0 register interrupt. This @@ -1424,8 +1431,8 @@ static const struct drm_encoder_helper_funcs tegra_hdmi_encoder_helper_funcs = { static int tegra_hdmi_init(struct host1x_client *client) { - struct drm_device *drm = dev_get_drvdata(client->parent); struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); + struct drm_device *drm = dev_get_drvdata(client->host); int err; hdmi->output.dev = client->dev; @@ -1490,9 +1497,66 @@ static int tegra_hdmi_exit(struct host1x_client *client) return 0; } +static int tegra_hdmi_runtime_suspend(struct host1x_client *client) +{ + struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); + struct device *dev = client->dev; + int err; + + err = reset_control_assert(hdmi->rst); + if (err < 0) { + dev_err(dev, "failed to assert reset: %d\n", err); + return err; + } + + usleep_range(1000, 2000); + + clk_disable_unprepare(hdmi->clk); + pm_runtime_put_sync(dev); + + return 0; +} + +static int tegra_hdmi_runtime_resume(struct host1x_client *client) +{ + struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); + struct device *dev = client->dev; + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "failed to get runtime PM: %d\n", err); + return err; + } + + err = clk_prepare_enable(hdmi->clk); + if (err < 0) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto put_rpm; + } + + usleep_range(1000, 2000); + + err = reset_control_deassert(hdmi->rst); + if (err < 0) { + dev_err(dev, "failed to deassert reset: %d\n", err); + goto disable_clk; + } + + return 0; + +disable_clk: + clk_disable_unprepare(hdmi->clk); +put_rpm: + pm_runtime_put_sync(dev); + return err; +} + static const struct host1x_client_ops hdmi_client_ops = { .init = tegra_hdmi_init, .exit = tegra_hdmi_exit, + .suspend = tegra_hdmi_runtime_suspend, + .resume = tegra_hdmi_runtime_resume, }; static const struct tegra_hdmi_config tegra20_hdmi_config = { @@ -1700,58 +1764,10 @@ static int tegra_hdmi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int tegra_hdmi_suspend(struct device *dev) -{ - struct tegra_hdmi *hdmi = dev_get_drvdata(dev); - int err; - - err = reset_control_assert(hdmi->rst); - if (err < 0) { - dev_err(dev, "failed to assert reset: %d\n", err); - return err; - } - - usleep_range(1000, 2000); - - clk_disable_unprepare(hdmi->clk); - - return 0; -} - -static int tegra_hdmi_resume(struct device *dev) -{ - struct tegra_hdmi *hdmi = dev_get_drvdata(dev); - int err; - - err = clk_prepare_enable(hdmi->clk); - if (err < 0) { - dev_err(dev, "failed to enable clock: %d\n", err); - return err; - } - - usleep_range(1000, 2000); - - err = reset_control_deassert(hdmi->rst); - if (err < 0) { - dev_err(dev, "failed to deassert reset: %d\n", err); - clk_disable_unprepare(hdmi->clk); - return err; - } - - return 0; -} -#endif - -static const struct dev_pm_ops tegra_hdmi_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_hdmi_suspend, tegra_hdmi_resume, NULL) -}; - struct platform_driver tegra_hdmi_driver = { .driver = { .name = "tegra-hdmi", .of_match_table = tegra_hdmi_of_match, - .pm = &tegra_hdmi_pm_ops, }, .probe = tegra_hdmi_probe, .remove = tegra_hdmi_remove, diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 47d985ac7cd7..8183e617bf6b 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -95,17 +95,25 @@ static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value, static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp) { + int err = 0; + mutex_lock(&wgrp->lock); if (wgrp->usecount == 0) { - pm_runtime_get_sync(wgrp->parent); + err = host1x_client_resume(wgrp->parent); + if (err < 0) { + dev_err(wgrp->parent->dev, "failed to resume: %d\n", err); + goto unlock; + } + reset_control_deassert(wgrp->rst); } wgrp->usecount++; - mutex_unlock(&wgrp->lock); - return 0; +unlock: + mutex_unlock(&wgrp->lock); + return err; } static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) @@ -121,7 +129,7 @@ static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) wgrp->index); } - pm_runtime_put(wgrp->parent); + host1x_client_suspend(wgrp->parent); } wgrp->usecount--; @@ -379,6 +387,7 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, struct tegra_plane *p = to_tegra_plane(plane); struct tegra_dc *dc; u32 value; + int err; /* rien ne va plus */ if (!old_state || !old_state->crtc) @@ -386,6 +395,12 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, dc = to_tegra_dc(old_state->crtc); + err = host1x_client_resume(&dc->client); + if (err < 0) { + dev_err(dc->dev, "failed to resume: %d\n", err); + return; + } + /* * XXX Legacy helpers seem to sometimes call ->atomic_disable() even * on planes that are already disabled. Make sure we fallback to the @@ -394,15 +409,13 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, if (WARN_ON(p->dc == NULL)) p->dc = dc; - pm_runtime_get_sync(dc->dev); - value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); value &= ~WIN_ENABLE; tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); tegra_dc_remove_shared_plane(dc, p); - pm_runtime_put(dc->dev); + host1x_client_suspend(&dc->client); } static void tegra_shared_plane_atomic_update(struct drm_plane *plane, @@ -415,6 +428,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, struct tegra_plane *p = to_tegra_plane(plane); dma_addr_t base; u32 value; + int err; /* rien ne va plus */ if (!plane->state->crtc || !plane->state->fb) @@ -425,7 +439,11 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, return; } - pm_runtime_get_sync(dc->dev); + err = host1x_client_resume(&dc->client); + if (err < 0) { + dev_err(dc->dev, "failed to resume: %d\n", err); + return; + } tegra_dc_assign_shared_plane(dc, p); @@ -515,7 +533,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, value &= ~CONTROL_CSC_ENABLE; tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL); - pm_runtime_put(dc->dev); + host1x_client_suspend(&dc->client); } static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = { @@ -551,7 +569,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, plane->base.index = index; plane->wgrp = &hub->wgrps[wgrp]; - plane->wgrp->parent = dc->dev; + plane->wgrp->parent = &dc->client; p = &plane->base.base; @@ -656,8 +674,13 @@ int tegra_display_hub_atomic_check(struct drm_device *drm, static void tegra_display_hub_update(struct tegra_dc *dc) { u32 value; + int err; - pm_runtime_get_sync(dc->dev); + err = host1x_client_resume(&dc->client); + if (err < 0) { + dev_err(dc->dev, "failed to resume: %d\n", err); + return; + } value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL); value &= ~LATENCY_EVENT; @@ -672,7 +695,7 @@ static void tegra_display_hub_update(struct tegra_dc *dc) tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL); tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); - pm_runtime_put(dc->dev); + host1x_client_suspend(&dc->client); } void tegra_display_hub_atomic_commit(struct drm_device *drm, @@ -705,7 +728,7 @@ void tegra_display_hub_atomic_commit(struct drm_device *drm, static int tegra_display_hub_init(struct host1x_client *client) { struct tegra_display_hub *hub = to_tegra_display_hub(client); - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); struct tegra_drm *tegra = drm->dev_private; struct tegra_display_hub_state *state; @@ -723,7 +746,7 @@ static int tegra_display_hub_init(struct host1x_client *client) static int tegra_display_hub_exit(struct host1x_client *client) { - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); struct tegra_drm *tegra = drm->dev_private; drm_atomic_private_obj_fini(&tegra->hub->base); @@ -732,9 +755,85 @@ static int tegra_display_hub_exit(struct host1x_client *client) return 0; } +static int tegra_display_hub_runtime_suspend(struct host1x_client *client) +{ + struct tegra_display_hub *hub = to_tegra_display_hub(client); + struct device *dev = client->dev; + unsigned int i = hub->num_heads; + int err; + + err = reset_control_assert(hub->rst); + if (err < 0) + return err; + + while (i--) + clk_disable_unprepare(hub->clk_heads[i]); + + clk_disable_unprepare(hub->clk_hub); + clk_disable_unprepare(hub->clk_dsc); + clk_disable_unprepare(hub->clk_disp); + + pm_runtime_put_sync(dev); + + return 0; +} + +static int tegra_display_hub_runtime_resume(struct host1x_client *client) +{ + struct tegra_display_hub *hub = to_tegra_display_hub(client); + struct device *dev = client->dev; + unsigned int i; + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "failed to get runtime PM: %d\n", err); + return err; + } + + err = clk_prepare_enable(hub->clk_disp); + if (err < 0) + goto put_rpm; + + err = clk_prepare_enable(hub->clk_dsc); + if (err < 0) + goto disable_disp; + + err = clk_prepare_enable(hub->clk_hub); + if (err < 0) + goto disable_dsc; + + for (i = 0; i < hub->num_heads; i++) { + err = clk_prepare_enable(hub->clk_heads[i]); + if (err < 0) + goto disable_heads; + } + + err = reset_control_deassert(hub->rst); + if (err < 0) + goto disable_heads; + + return 0; + +disable_heads: + while (i--) + clk_disable_unprepare(hub->clk_heads[i]); + + clk_disable_unprepare(hub->clk_hub); +disable_dsc: + clk_disable_unprepare(hub->clk_dsc); +disable_disp: + clk_disable_unprepare(hub->clk_disp); +put_rpm: + pm_runtime_put_sync(dev); + return err; +} + static const struct host1x_client_ops tegra_display_hub_ops = { .init = tegra_display_hub_init, .exit = tegra_display_hub_exit, + .suspend = tegra_display_hub_runtime_suspend, + .resume = tegra_display_hub_runtime_resume, }; static int tegra_display_hub_probe(struct platform_device *pdev) @@ -851,6 +950,7 @@ static int tegra_display_hub_probe(struct platform_device *pdev) static int tegra_display_hub_remove(struct platform_device *pdev) { struct tegra_display_hub *hub = platform_get_drvdata(pdev); + unsigned int i; int err; err = host1x_client_unregister(&hub->client); @@ -859,78 +959,17 @@ static int tegra_display_hub_remove(struct platform_device *pdev) err); } - pm_runtime_disable(&pdev->dev); - - return err; -} - -static int __maybe_unused tegra_display_hub_suspend(struct device *dev) -{ - struct tegra_display_hub *hub = dev_get_drvdata(dev); - unsigned int i = hub->num_heads; - int err; - - err = reset_control_assert(hub->rst); - if (err < 0) - return err; - - while (i--) - clk_disable_unprepare(hub->clk_heads[i]); - - clk_disable_unprepare(hub->clk_hub); - clk_disable_unprepare(hub->clk_dsc); - clk_disable_unprepare(hub->clk_disp); - - return 0; -} - -static int __maybe_unused tegra_display_hub_resume(struct device *dev) -{ - struct tegra_display_hub *hub = dev_get_drvdata(dev); - unsigned int i; - int err; - - err = clk_prepare_enable(hub->clk_disp); - if (err < 0) - return err; - - err = clk_prepare_enable(hub->clk_dsc); - if (err < 0) - goto disable_disp; - - err = clk_prepare_enable(hub->clk_hub); - if (err < 0) - goto disable_dsc; + for (i = 0; i < hub->soc->num_wgrps; i++) { + struct tegra_windowgroup *wgrp = &hub->wgrps[i]; - for (i = 0; i < hub->num_heads; i++) { - err = clk_prepare_enable(hub->clk_heads[i]); - if (err < 0) - goto disable_heads; + mutex_destroy(&wgrp->lock); } - err = reset_control_deassert(hub->rst); - if (err < 0) - goto disable_heads; - - return 0; - -disable_heads: - while (i--) - clk_disable_unprepare(hub->clk_heads[i]); + pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(hub->clk_hub); -disable_dsc: - clk_disable_unprepare(hub->clk_dsc); -disable_disp: - clk_disable_unprepare(hub->clk_disp); return err; } -static const struct dev_pm_ops tegra_display_hub_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_display_hub_suspend, - tegra_display_hub_resume, NULL) -}; - static const struct tegra_display_hub_soc tegra186_display_hub = { .num_wgrps = 6, .supports_dsc = true, @@ -958,7 +997,6 @@ struct platform_driver tegra_display_hub_driver = { .driver = { .name = "tegra-display-hub", .of_match_table = tegra_display_hub_of_match, - .pm = &tegra_display_hub_pm_ops, }, .probe = tegra_display_hub_probe, .remove = tegra_display_hub_remove, diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 767a60d9313c..3efa1be07ff8 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h @@ -17,7 +17,7 @@ struct tegra_windowgroup { struct mutex lock; unsigned int index; - struct device *parent; + struct host1x_client *parent; struct reset_control *rst; }; diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 80ddde4adbae..a264259b97a2 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -250,3 +250,19 @@ void tegra_output_find_possible_crtcs(struct tegra_output *output, output->encoder.possible_crtcs = mask; } + +int tegra_output_suspend(struct tegra_output *output) +{ + if (output->hpd_irq) + disable_irq(output->hpd_irq); + + return 0; +} + +int tegra_output_resume(struct tegra_output *output) +{ + if (output->hpd_irq) + enable_irq(output->hpd_irq); + + return 0; +} diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index cadcdd9ea427..9ccfb56e9b01 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -3,6 +3,8 @@ * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. */ +#include <linux/iommu.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> @@ -107,21 +109,27 @@ const struct drm_plane_funcs tegra_plane_funcs = { static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) { + struct iommu_domain *domain = iommu_get_domain_for_dev(dc->dev); unsigned int i; int err; for (i = 0; i < state->base.fb->format->num_planes; i++) { struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); + dma_addr_t phys_addr, *phys; + struct sg_table *sgt; - if (!dc->client.group) { - struct sg_table *sgt; + if (!domain || dc->client.group) + phys = &phys_addr; + else + phys = NULL; - sgt = host1x_bo_pin(dc->dev, &bo->base, NULL); - if (IS_ERR(sgt)) { - err = PTR_ERR(sgt); - goto unpin; - } + sgt = host1x_bo_pin(dc->dev, &bo->base, phys); + if (IS_ERR(sgt)) { + err = PTR_ERR(sgt); + goto unpin; + } + if (sgt) { err = dma_map_sg(dc->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE); if (err == 0) { @@ -143,7 +151,7 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) state->iova[i] = sg_dma_address(sgt->sgl); state->sgt[i] = sgt; } else { - state->iova[i] = bo->iova; + state->iova[i] = phys_addr; } } @@ -156,9 +164,11 @@ unpin: struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); struct sg_table *sgt = state->sgt[i]; - dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE); - host1x_bo_unpin(dc->dev, &bo->base, sgt); + if (sgt) + dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, + DMA_TO_DEVICE); + host1x_bo_unpin(dc->dev, &bo->base, sgt); state->iova[i] = DMA_MAPPING_ERROR; state->sgt[i] = NULL; } @@ -172,17 +182,13 @@ static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state) for (i = 0; i < state->base.fb->format->num_planes; i++) { struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); + struct sg_table *sgt = state->sgt[i]; - if (!dc->client.group) { - struct sg_table *sgt = state->sgt[i]; - - if (sgt) { - dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, - DMA_TO_DEVICE); - host1x_bo_unpin(dc->dev, &bo->base, sgt); - } - } + if (sgt) + dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, + DMA_TO_DEVICE); + host1x_bo_unpin(dc->dev, &bo->base, sgt); state->iova[i] = DMA_MAPPING_ERROR; state->sgt[i] = NULL; } diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 1b8087d2dafe..81226a4953c1 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -2255,7 +2255,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) if (err < 0) dev_err(sor->dev, "failed to power off I/O pad: %d\n", err); - pm_runtime_put(sor->dev); + host1x_client_suspend(&sor->client); } static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) @@ -2276,7 +2276,11 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) mode = &encoder->crtc->state->adjusted_mode; pclk = mode->clock * 1000; - pm_runtime_get_sync(sor->dev); + err = host1x_client_resume(&sor->client); + if (err < 0) { + dev_err(sor->dev, "failed to resume: %d\n", err); + return; + } /* switch to safe parent clock */ err = tegra_sor_set_parent_clock(sor, sor->clk_safe); @@ -2722,7 +2726,7 @@ static void tegra_sor_dp_disable(struct drm_encoder *encoder) if (output->panel) drm_panel_unprepare(output->panel); - pm_runtime_put(sor->dev); + host1x_client_suspend(&sor->client); } static void tegra_sor_dp_enable(struct drm_encoder *encoder) @@ -2742,7 +2746,11 @@ static void tegra_sor_dp_enable(struct drm_encoder *encoder) mode = &encoder->crtc->state->adjusted_mode; info = &output->connector.display_info; - pm_runtime_get_sync(sor->dev); + err = host1x_client_resume(&sor->client); + if (err < 0) { + dev_err(sor->dev, "failed to resume: %d\n", err); + return; + } /* switch to safe parent clock */ err = tegra_sor_set_parent_clock(sor, sor->clk_safe); @@ -3053,7 +3061,7 @@ static const struct tegra_sor_ops tegra_sor_dp_ops = { static int tegra_sor_init(struct host1x_client *client) { - struct drm_device *drm = dev_get_drvdata(client->parent); + struct drm_device *drm = dev_get_drvdata(client->host); const struct drm_encoder_helper_funcs *helpers = NULL; struct tegra_sor *sor = host1x_client_to_sor(client); int connector = DRM_MODE_CONNECTOR_Unknown; @@ -3190,9 +3198,80 @@ static int tegra_sor_exit(struct host1x_client *client) return 0; } +static int tegra_sor_runtime_suspend(struct host1x_client *client) +{ + struct tegra_sor *sor = host1x_client_to_sor(client); + struct device *dev = client->dev; + int err; + + if (sor->rst) { + err = reset_control_assert(sor->rst); + if (err < 0) { + dev_err(dev, "failed to assert reset: %d\n", err); + return err; + } + + reset_control_release(sor->rst); + } + + usleep_range(1000, 2000); + + clk_disable_unprepare(sor->clk); + pm_runtime_put_sync(dev); + + return 0; +} + +static int tegra_sor_runtime_resume(struct host1x_client *client) +{ + struct tegra_sor *sor = host1x_client_to_sor(client); + struct device *dev = client->dev; + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "failed to get runtime PM: %d\n", err); + return err; + } + + err = clk_prepare_enable(sor->clk); + if (err < 0) { + dev_err(dev, "failed to enable clock: %d\n", err); + goto put_rpm; + } + + usleep_range(1000, 2000); + + if (sor->rst) { + err = reset_control_acquire(sor->rst); + if (err < 0) { + dev_err(dev, "failed to acquire reset: %d\n", err); + goto disable_clk; + } + + err = reset_control_deassert(sor->rst); + if (err < 0) { + dev_err(dev, "failed to deassert reset: %d\n", err); + goto release_reset; + } + } + + return 0; + +release_reset: + reset_control_release(sor->rst); +disable_clk: + clk_disable_unprepare(sor->clk); +put_rpm: + pm_runtime_put_sync(dev); + return err; +} + static const struct host1x_client_ops sor_client_ops = { .init = tegra_sor_init, .exit = tegra_sor_exit, + .suspend = tegra_sor_runtime_suspend, + .resume = tegra_sor_runtime_resume, }; static const u8 tegra124_sor_xbar_cfg[5] = { @@ -3836,6 +3915,17 @@ static int tegra_sor_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sor); pm_runtime_enable(&pdev->dev); + INIT_LIST_HEAD(&sor->client.list); + sor->client.ops = &sor_client_ops; + sor->client.dev = &pdev->dev; + + err = host1x_client_register(&sor->client); + if (err < 0) { + dev_err(&pdev->dev, "failed to register host1x client: %d\n", + err); + goto rpm_disable; + } + /* * On Tegra210 and earlier, provide our own implementation for the * pad output clock. @@ -3843,43 +3933,36 @@ static int tegra_sor_probe(struct platform_device *pdev) if (!sor->clk_pad) { char *name; - err = pm_runtime_get_sync(&pdev->dev); - if (err < 0) { - dev_err(&pdev->dev, "failed to get runtime PM: %d\n", - err); - goto remove; - } - - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "sor%u_pad_clkout", sor->index); + name = devm_kasprintf(sor->dev, GFP_KERNEL, "sor%u_pad_clkout", + sor->index); if (!name) { err = -ENOMEM; - goto remove; + goto unregister; + } + + err = host1x_client_resume(&sor->client); + if (err < 0) { + dev_err(sor->dev, "failed to resume: %d\n", err); + goto unregister; } sor->clk_pad = tegra_clk_sor_pad_register(sor, name); - pm_runtime_put(&pdev->dev); + host1x_client_suspend(&sor->client); } if (IS_ERR(sor->clk_pad)) { err = PTR_ERR(sor->clk_pad); - dev_err(&pdev->dev, "failed to register SOR pad clock: %d\n", - err); - goto remove; - } - - INIT_LIST_HEAD(&sor->client.list); - sor->client.ops = &sor_client_ops; - sor->client.dev = &pdev->dev; - - err = host1x_client_register(&sor->client); - if (err < 0) { - dev_err(&pdev->dev, "failed to register host1x client: %d\n", + dev_err(sor->dev, "failed to register SOR pad clock: %d\n", err); - goto remove; + goto unregister; } return 0; +unregister: + host1x_client_unregister(&sor->client); +rpm_disable: + pm_runtime_disable(&pdev->dev); remove: if (sor->ops && sor->ops->remove) sor->ops->remove(sor); @@ -3893,8 +3976,6 @@ static int tegra_sor_remove(struct platform_device *pdev) struct tegra_sor *sor = platform_get_drvdata(pdev); int err; - pm_runtime_disable(&pdev->dev); - err = host1x_client_unregister(&sor->client); if (err < 0) { dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", @@ -3902,6 +3983,8 @@ static int tegra_sor_remove(struct platform_device *pdev) return err; } + pm_runtime_disable(&pdev->dev); + if (sor->ops && sor->ops->remove) { err = sor->ops->remove(sor); if (err < 0) @@ -3913,54 +3996,21 @@ static int tegra_sor_remove(struct platform_device *pdev) return 0; } -static int tegra_sor_runtime_suspend(struct device *dev) -{ - struct tegra_sor *sor = dev_get_drvdata(dev); - int err; - - if (sor->rst) { - err = reset_control_assert(sor->rst); - if (err < 0) { - dev_err(dev, "failed to assert reset: %d\n", err); - return err; - } - - reset_control_release(sor->rst); - } - - usleep_range(1000, 2000); - - clk_disable_unprepare(sor->clk); - - return 0; -} - -static int tegra_sor_runtime_resume(struct device *dev) +static int __maybe_unused tegra_sor_suspend(struct device *dev) { struct tegra_sor *sor = dev_get_drvdata(dev); int err; - err = clk_prepare_enable(sor->clk); + err = tegra_output_suspend(&sor->output); if (err < 0) { - dev_err(dev, "failed to enable clock: %d\n", err); + dev_err(dev, "failed to suspend output: %d\n", err); return err; } - usleep_range(1000, 2000); - - if (sor->rst) { - err = reset_control_acquire(sor->rst); - if (err < 0) { - dev_err(dev, "failed to acquire reset: %d\n", err); - clk_disable_unprepare(sor->clk); - return err; - } - - err = reset_control_deassert(sor->rst); + if (sor->hdmi_supply) { + err = regulator_disable(sor->hdmi_supply); if (err < 0) { - dev_err(dev, "failed to deassert reset: %d\n", err); - reset_control_release(sor->rst); - clk_disable_unprepare(sor->clk); + tegra_output_resume(&sor->output); return err; } } @@ -3968,37 +4018,31 @@ static int tegra_sor_runtime_resume(struct device *dev) return 0; } -static int tegra_sor_suspend(struct device *dev) +static int __maybe_unused tegra_sor_resume(struct device *dev) { struct tegra_sor *sor = dev_get_drvdata(dev); int err; if (sor->hdmi_supply) { - err = regulator_disable(sor->hdmi_supply); + err = regulator_enable(sor->hdmi_supply); if (err < 0) return err; } - return 0; -} + err = tegra_output_resume(&sor->output); + if (err < 0) { + dev_err(dev, "failed to resume output: %d\n", err); -static int tegra_sor_resume(struct device *dev) -{ - struct tegra_sor *sor = dev_get_drvdata(dev); - int err; + if (sor->hdmi_supply) + regulator_disable(sor->hdmi_supply); - if (sor->hdmi_supply) { - err = regulator_enable(sor->hdmi_supply); - if (err < 0) - return err; + return err; } return 0; } static const struct dev_pm_ops tegra_sor_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_sor_runtime_suspend, tegra_sor_runtime_resume, - NULL) SET_SYSTEM_SLEEP_PM_OPS(tegra_sor_suspend, tegra_sor_resume) }; diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 3526c2892ddb..ade56b860cf9 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -161,7 +161,7 @@ static int vic_boot(struct vic *vic) static int vic_init(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); - struct drm_device *dev = dev_get_drvdata(client->parent); + struct drm_device *dev = dev_get_drvdata(client->host); struct tegra_drm *tegra = dev->dev_private; struct vic *vic = to_vic(drm); int err; @@ -190,9 +190,9 @@ static int vic_init(struct host1x_client *client) /* * Inherit the DMA parameters (such as maximum segment size) from the - * parent device. + * parent host1x device. */ - client->dev->dma_parms = client->parent->dma_parms; + client->dev->dma_parms = client->host->dma_parms; return 0; @@ -209,7 +209,7 @@ detach: static int vic_exit(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); - struct drm_device *dev = dev_get_drvdata(client->parent); + struct drm_device *dev = dev_get_drvdata(client->host); struct tegra_drm *tegra = dev->dev_private; struct vic *vic = to_vic(drm); int err; |