Commit ac3f6915 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Tomi Valkeinen
Browse files

drm/omap: dpi: Register a drm_bridge



In order to integrate with a chain of drm_bridge, the internal DPI
output has to expose its operations through the drm_bridge API.
Register a bridge at initialisation time to do so and remove the
omap_dss_device operations that are now unused.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200226112514.12455-49-laurent.pinchart@ideasonboard.com
parent 76777d6c
Loading
Loading
Loading
Loading
+116 −93
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@
#include <linux/string.h>
#include <linux/sys_soc.h>

#include <drm/drm_bridge.h>

#include "dss.h"
#include "omapdss.h"

@@ -34,19 +36,15 @@ struct dpi_data {
	enum dss_clk_source clk_src;
	struct dss_pll *pll;

	struct mutex lock;

	struct dss_lcd_mgr_config mgr_config;
	unsigned long pixelclock;
	int data_lines;

	struct omap_dss_device output;
	struct drm_bridge bridge;
};

static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
{
	return container_of(dssdev, struct dpi_data, output);
}
#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)

/* -----------------------------------------------------------------------------
 * Clock Handling and PLL
@@ -354,6 +352,32 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
}

static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
{
	int lck_div, pck_div;
	unsigned long fck;
	struct dpi_clk_calc_ctx ctx;

	if (dpi->pll) {
		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
			return -EINVAL;

		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
	} else {
		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
			return -EINVAL;

		fck = ctx.fck;
	}

	lck_div = ctx.dispc_cinfo.lck_div;
	pck_div = ctx.dispc_cinfo.pck_div;

	*clock = fck / lck_div / pck_div;

	return 0;
}

static int dpi_verify_pll(struct dss_pll *pll)
{
	int r;
@@ -391,44 +415,86 @@ static void dpi_init_pll(struct dpi_data *dpi)
}

/* -----------------------------------------------------------------------------
 * omap_dss_device Operations
 * DRM Bridge Operations
 */

static int dpi_connect(struct omap_dss_device *src,
		       struct omap_dss_device *dst)
static int dpi_bridge_attach(struct drm_bridge *bridge,
			     enum drm_bridge_attach_flags flags)
{
	struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);

	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
		return -EINVAL;

	dpi_init_pll(dpi);

	return omapdss_device_connect(dst->dss, dst, dst->next);
	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
				 bridge, flags);
}

static void dpi_disconnect(struct omap_dss_device *src,
			   struct omap_dss_device *dst)
static enum drm_mode_status
dpi_bridge_mode_valid(struct drm_bridge *bridge,
		       const struct drm_display_mode *mode)
{
	omapdss_device_disconnect(dst, dst->next);
	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
	unsigned long clock = mode->clock * 1000;
	int ret;

	if (mode->hdisplay % 8 != 0)
		return MODE_BAD_WIDTH;

	if (mode->clock == 0)
		return MODE_NOCLOCK;

	ret = dpi_clock_update(dpi, &clock);
	if (ret < 0)
		return MODE_CLOCK_RANGE;

	return MODE_OK;
}

static void dpi_display_enable(struct omap_dss_device *dssdev)
static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
				   const struct drm_display_mode *mode,
				   struct drm_display_mode *adjusted_mode)
{
	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
	struct omap_dss_device *out = &dpi->output;
	int r;
	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
	unsigned long clock = mode->clock * 1000;
	int ret;

	mutex_lock(&dpi->lock);
	ret = dpi_clock_update(dpi, &clock);
	if (ret < 0)
		return false;

	adjusted_mode->clock = clock / 1000;

	return true;
}

static void dpi_bridge_mode_set(struct drm_bridge *bridge,
				 const struct drm_display_mode *mode,
				 const struct drm_display_mode *adjusted_mode)
{
	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);

	dpi->pixelclock = adjusted_mode->clock * 1000;
}

static void dpi_bridge_enable(struct drm_bridge *bridge)
{
	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
	int r;

	if (dpi->vdds_dsi_reg) {
		r = regulator_enable(dpi->vdds_dsi_reg);
		if (r)
			goto err_reg_enable;
			return;
	}

	r = dispc_runtime_get(dpi->dss->dispc);
	if (r)
		goto err_get_dispc;

	r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
	if (r)
		goto err_src_sel;

@@ -450,8 +516,6 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
	if (r)
		goto err_mgr_enable;

	mutex_unlock(&dpi->lock);

	return;

err_mgr_enable:
@@ -464,15 +528,11 @@ err_src_sel:
err_get_dispc:
	if (dpi->vdds_dsi_reg)
		regulator_disable(dpi->vdds_dsi_reg);
err_reg_enable:
	mutex_unlock(&dpi->lock);
}

static void dpi_display_disable(struct omap_dss_device *dssdev)
static void dpi_bridge_disable(struct drm_bridge *bridge)
{
	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);

	mutex_lock(&dpi->lock);
	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);

	dss_mgr_disable(&dpi->output);

@@ -486,74 +546,34 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)

	if (dpi->vdds_dsi_reg)
		regulator_disable(dpi->vdds_dsi_reg);

	mutex_unlock(&dpi->lock);
}

static int dpi_check_timings(struct omap_dss_device *dssdev,
			     struct drm_display_mode *mode)
{
	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
	int lck_div, pck_div;
	unsigned long fck;
	unsigned long pck;
	struct dpi_clk_calc_ctx ctx;
	bool ok;

	if (mode->hdisplay % 8 != 0)
		return -EINVAL;

	if (mode->clock == 0)
		return -EINVAL;

	if (dpi->pll) {
		ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
		if (!ok)
			return -EINVAL;

		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
	} else {
		ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
		if (!ok)
			return -EINVAL;

		fck = ctx.fck;
	}

	lck_div = ctx.dispc_cinfo.lck_div;
	pck_div = ctx.dispc_cinfo.pck_div;

	pck = fck / lck_div / pck_div;
static const struct drm_bridge_funcs dpi_bridge_funcs = {
	.attach = dpi_bridge_attach,
	.mode_valid = dpi_bridge_mode_valid,
	.mode_fixup = dpi_bridge_mode_fixup,
	.mode_set = dpi_bridge_mode_set,
	.enable = dpi_bridge_enable,
	.disable = dpi_bridge_disable,
};

	mode->clock = pck / 1000;
static void dpi_bridge_init(struct dpi_data *dpi)
{
	dpi->bridge.funcs = &dpi_bridge_funcs;
	dpi->bridge.of_node = dpi->pdev->dev.of_node;
	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;

	return 0;
	drm_bridge_add(&dpi->bridge);
}

static void dpi_set_timings(struct omap_dss_device *dssdev,
			    const struct drm_display_mode *mode)
static void dpi_bridge_cleanup(struct dpi_data *dpi)
{
	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);

	DSSDBG("dpi_set_timings\n");

	mutex_lock(&dpi->lock);

	dpi->pixelclock = mode->clock * 1000;

	mutex_unlock(&dpi->lock);
	drm_bridge_remove(&dpi->bridge);
}

static const struct omap_dss_device_ops dpi_ops = {
	.connect = dpi_connect,
	.disconnect = dpi_disconnect,

	.enable = dpi_display_enable,
	.disable = dpi_display_disable,

	.check_timings = dpi_check_timings,
	.set_timings = dpi_set_timings,
};
/* -----------------------------------------------------------------------------
 * Initialisation and Cleanup
 */

/*
 * Return a hardcoded channel for the DPI output. This should work for
@@ -597,6 +617,8 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
	u32 port_num = 0;
	int r;

	dpi_bridge_init(dpi);

	of_property_read_u32(port, "reg", &port_num);
	dpi->id = port_num <= 2 ? port_num : 0;

@@ -618,12 +640,13 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
	out->type = OMAP_DISPLAY_TYPE_DPI;
	out->dispc_channel = dpi_get_channel(dpi);
	out->of_port = port_num;
	out->ops = &dpi_ops;
	out->owner = THIS_MODULE;

	r = omapdss_device_init_output(out, NULL);
	if (r < 0)
	r = omapdss_device_init_output(out, &dpi->bridge);
	if (r < 0) {
		dpi_bridge_cleanup(dpi);
		return r;
	}

	omapdss_device_register(out);

@@ -637,6 +660,8 @@ static void dpi_uninit_output_port(struct device_node *port)

	omapdss_device_unregister(out);
	omapdss_device_cleanup_output(out);

	dpi_bridge_cleanup(dpi);
}

/* -----------------------------------------------------------------------------
@@ -702,8 +727,6 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
	dpi->dss = dss;
	port->data = dpi;

	mutex_init(&dpi->lock);

	r = dpi_init_regulator(dpi);
	if (r)
		return r;