Commit fd7226fb authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm/tegra/for-5.6-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next



drm/tegra: Changes for v5.6-rc1

This contains a small set of mostly fixes and some minor improvements.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Thierry Reding <thierry.reding@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200111004835.2412858-1-thierry.reding@gmail.com
parents 688486a4 033ccdb7
Loading
Loading
Loading
Loading
+87 −60
Original line number Diff line number Diff line
@@ -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,
+1 −1
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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;

+2 −0
Original line number Diff line number Diff line
@@ -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
+98 −79
Original line number Diff line number Diff line
@@ -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,
Loading