Commit 1cac9ba2 authored by Sebastian Reichel's avatar Sebastian Reichel Committed by Tomi Valkeinen
Browse files

drm/omap: dsi: convert to drm_panel



This converts the DSI module to expect common drm_panel display
drivers instead of dssdev based ones.

Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201215104657.802264-33-tomi.valkeinen@ti.com
parent e4869b04
Loading
Loading
Loading
Loading
+77 −126
Original line number Diff line number Diff line
@@ -6,8 +6,6 @@
 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
 */

/* #define DEBUG */

#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -19,11 +17,14 @@
#include <linux/regulator/consumer.h>

#include <drm/drm_connector.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>

#include <video/display_timing.h>
#include <video/mipi_display.h>
#include <video/of_display_timing.h>

#include "../dss/omapdss.h"
#include <video/videomode.h>

#define DCS_READ_NUM_ERRORS	0x05
#define DCS_GET_ID1		0xda
@@ -34,11 +35,8 @@

struct panel_drv_data {
	struct mipi_dsi_device *dsi;

	struct omap_dss_device dssdev;
	struct omap_dss_device *src;

	struct videomode vm;
	struct drm_panel panel;
	struct drm_display_mode mode;

	struct mutex lock;

@@ -66,7 +64,10 @@ struct panel_drv_data {
	bool intro_printed;
};

#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
static inline struct panel_drv_data *panel_to_ddata(struct drm_panel *panel)
{
	return container_of(panel, struct panel_drv_data, panel);
}

static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable);

@@ -281,7 +282,6 @@ static void dsicm_hw_reset(struct panel_drv_data *ddata)

static int dsicm_power_on(struct panel_drv_data *ddata)
{
	struct omap_dss_device *src = ddata->src;
	u8 id1, id2, id3;
	int r;

@@ -318,10 +318,6 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
	if (r)
		goto err;

	r = src->ops->dsi.enable_video_output(src, ddata->dsi->channel);
	if (r)
		goto err;

	ddata->enabled = true;

	if (!ddata->intro_printed) {
@@ -341,15 +337,12 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
	return r;
}

static void dsicm_power_off(struct panel_drv_data *ddata)
static int dsicm_power_off(struct panel_drv_data *ddata)
{
	struct omap_dss_device *src = ddata->src;
	int r;

	ddata->enabled = false;

	src->ops->dsi.disable_video_output(src, ddata->dsi->channel);

	r = mipi_dsi_dcs_set_display_off(ddata->dsi);
	if (!r)
		r = dsicm_sleep_in(ddata);
@@ -359,51 +352,25 @@ static void dsicm_power_off(struct panel_drv_data *ddata)
				"error disabling panel, issuing HW reset\n");
		dsicm_hw_reset(ddata);
	}
}

static int dsicm_connect(struct omap_dss_device *src,
			 struct omap_dss_device *dst)
{
	struct panel_drv_data *ddata = to_panel_data(dst);

	ddata->src = src;
	return 0;
}

static void dsicm_disconnect(struct omap_dss_device *src,
			     struct omap_dss_device *dst)
{
	struct panel_drv_data *ddata = to_panel_data(dst);

	ddata->src = NULL;
	return r;
}

static void dsicm_pre_enable(struct omap_dss_device *dssdev)
static int dsicm_prepare(struct drm_panel *panel)
{
	struct panel_drv_data *ddata = to_panel_data(dssdev);
	struct omap_dss_device *src = ddata->src;
	struct panel_drv_data *ddata = panel_to_ddata(panel);
	int r;
	struct omap_dss_dsi_config dsi_config = {
		.vm = &ddata->vm,
		.hs_clk_min = 150000000,
		.hs_clk_max = 300000000,
		.lp_clk_min = 7000000,
		.lp_clk_max = 10000000,
	};

	r = regulator_bulk_enable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
	if (r)
		dev_err(&ddata->dsi->dev, "failed to enable supplies: %d\n", r);

	r = src->ops->dsi.set_config(src, &dsi_config);
	if (r) {
		dev_err(&ddata->dsi->dev, "failed to configure DSI\n");
	}
	return r;
}

static void dsicm_enable(struct omap_dss_device *dssdev)
static int dsicm_enable(struct drm_panel *panel)
{
	struct panel_drv_data *ddata = to_panel_data(dssdev);
	struct panel_drv_data *ddata = panel_to_ddata(panel);
	int r;

	mutex_lock(&ddata->lock);
@@ -416,33 +383,39 @@ static void dsicm_enable(struct omap_dss_device *dssdev)

	dsicm_bl_power(ddata, true);

	return;
	return 0;
err:
	dev_dbg(&ddata->dsi->dev, "enable failed (%d)\n", r);
	dev_err(&ddata->dsi->dev, "enable failed (%d)\n", r);
	mutex_unlock(&ddata->lock);
	return r;
}

static void dsicm_disable(struct omap_dss_device *dssdev)
static int dsicm_unprepare(struct drm_panel *panel)
{
	struct panel_drv_data *ddata = to_panel_data(dssdev);
	struct panel_drv_data *ddata = panel_to_ddata(panel);
	int r;

	r = regulator_bulk_disable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
	if (r)
		dev_err(&ddata->dsi->dev, "failed to disable supplies: %d\n", r);

	return r;
}

static int dsicm_disable(struct drm_panel *panel)
{
	struct panel_drv_data *ddata = panel_to_ddata(panel);
	int r;

	dsicm_bl_power(ddata, false);

	mutex_lock(&ddata->lock);

	dsicm_power_off(ddata);
	r = dsicm_power_off(ddata);

	mutex_unlock(&ddata->lock);
}

static void dsicm_post_disable(struct omap_dss_device *dssdev)
{
	struct panel_drv_data *ddata = to_panel_data(dssdev);
	int r;

	r = regulator_bulk_disable(ARRAY_SIZE(ddata->supplies), ddata->supplies);
	if (r)
		dev_err(&ddata->dsi->dev, "failed to disable supplies: %d\n", r);
	return r;
}

static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
@@ -461,50 +434,37 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
	return r;
}

static int dsicm_get_modes(struct omap_dss_device *dssdev,
static int dsicm_get_modes(struct drm_panel *panel,
			   struct drm_connector *connector)
{
	struct panel_drv_data *ddata = to_panel_data(dssdev);

	connector->display_info.width_mm = ddata->width_mm;
	connector->display_info.height_mm = ddata->height_mm;

	return omapdss_display_get_modes(connector, &ddata->vm);
	struct panel_drv_data *ddata = panel_to_ddata(panel);
	struct drm_display_mode *mode;

	mode = drm_mode_duplicate(connector->dev, &ddata->mode);
	if (!mode) {
		dev_err(&ddata->dsi->dev, "failed to add mode %ux%ux@%u kHz\n",
			ddata->mode.hdisplay, ddata->mode.vdisplay,
			ddata->mode.clock);
		return -ENOMEM;
	}

static int dsicm_check_timings(struct omap_dss_device *dssdev,
			       struct drm_display_mode *mode)
{
	struct panel_drv_data *ddata = to_panel_data(dssdev);
	int ret = 0;
	drm_mode_set_name(mode);
	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;

	if (mode->hdisplay != ddata->vm.hactive)
		ret = -EINVAL;

	if (mode->vdisplay != ddata->vm.vactive)
		ret = -EINVAL;
	connector->display_info.width_mm = ddata->width_mm;
	connector->display_info.height_mm = ddata->height_mm;

	if (ret) {
		dev_warn(dssdev->dev, "wrong resolution: %d x %d",
			 mode->hdisplay, mode->vdisplay);
		dev_warn(dssdev->dev, "panel resolution: %d x %d",
			 ddata->vm.hactive, ddata->vm.vactive);
	}
	drm_mode_probed_add(connector, mode);

	return ret;
	return 1;
}

static const struct omap_dss_device_ops dsicm_ops = {
	.connect	= dsicm_connect,
	.disconnect	= dsicm_disconnect,

	.pre_enable	= dsicm_pre_enable,
	.enable		= dsicm_enable,
static const struct drm_panel_funcs dsicm_panel_funcs = {
	.unprepare = dsicm_unprepare,
	.disable = dsicm_disable,
	.post_disable	= dsicm_post_disable,

	.prepare = dsicm_prepare,
	.enable = dsicm_enable,
	.get_modes = dsicm_get_modes,
	.check_timings	= dsicm_check_timings,
};

static int dsicm_probe_of(struct mipi_dsi_device *dsi)
@@ -513,6 +473,10 @@ static int dsicm_probe_of(struct mipi_dsi_device *dsi)
	struct backlight_device *backlight;
	struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
	struct display_timing timing;
	struct videomode vm = {
		.hactive = 864,
		.vactive = 480,
	};
	int err;

	ddata->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
@@ -524,15 +488,16 @@ static int dsicm_probe_of(struct mipi_dsi_device *dsi)

	err = of_get_display_timing(node, "panel-timing", &timing);
	if (!err) {
		videomode_from_timing(&timing, &ddata->vm);
		if (!ddata->vm.pixelclock)
			ddata->vm.pixelclock =
				ddata->vm.hactive * ddata->vm.vactive * 60;
		videomode_from_timing(&timing, &vm);
	} else {
		dev_warn(&dsi->dev,
			 "failed to get video timing, using defaults\n");
	}

	if (!vm.pixelclock)
		vm.pixelclock = vm.hactive * vm.vactive * 60;
	drm_display_mode_from_videomode(&vm, &ddata->mode);

	ddata->width_mm = 0;
	of_property_read_u32(node, "width-mm", &ddata->width_mm);

@@ -564,7 +529,6 @@ static int dsicm_probe(struct mipi_dsi_device *dsi)
	struct panel_drv_data *ddata;
	struct backlight_device *bldev = NULL;
	struct device *dev = &dsi->dev;
	struct omap_dss_device *dssdev;
	int r;

	dev_dbg(dev, "probe\n");
@@ -576,30 +540,17 @@ static int dsicm_probe(struct mipi_dsi_device *dsi)
	mipi_dsi_set_drvdata(dsi, ddata);
	ddata->dsi = dsi;

	ddata->vm.hactive = 864;
	ddata->vm.vactive = 480;
	ddata->vm.pixelclock = 864 * 480 * 60;

	r = dsicm_probe_of(dsi);
	if (r)
		return r;

	dssdev = &ddata->dssdev;
	dssdev->dev = dev;
	dssdev->ops = &dsicm_ops;
	dssdev->type = OMAP_DISPLAY_TYPE_DSI;
	dssdev->display = true;
	dssdev->owner = THIS_MODULE;
	dssdev->of_port = 0;
	dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;

	omapdss_display_init(dssdev);
	omapdss_device_register(dssdev);

	mutex_init(&ddata->lock);

	dsicm_hw_reset(ddata);

	drm_panel_init(&ddata->panel, dev, &dsicm_panel_funcs,
		       DRM_MODE_CONNECTOR_DSI);

	if (ddata->use_dsi_backlight) {
		struct backlight_properties props = { 0 };
		props.max_brightness = 255;
@@ -628,6 +579,8 @@ static int dsicm_probe(struct mipi_dsi_device *dsi)
	dsi->hs_rate = 300000000;
	dsi->lp_rate = 10000000;

	drm_panel_add(&ddata->panel);

	r = mipi_dsi_attach(dsi);
	if (r < 0)
		goto err_dsi_attach;
@@ -635,6 +588,7 @@ static int dsicm_probe(struct mipi_dsi_device *dsi)
	return 0;

err_dsi_attach:
	drm_panel_remove(&ddata->panel);
	sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);
err_bl:
	if (ddata->extbldev)
@@ -646,15 +600,12 @@ static int dsicm_probe(struct mipi_dsi_device *dsi)
static int __exit dsicm_remove(struct mipi_dsi_device *dsi)
{
	struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi);
	struct omap_dss_device *dssdev = &ddata->dssdev;

	dev_dbg(&dsi->dev, "remove\n");

	mipi_dsi_detach(dsi);

	omapdss_device_unregister(dssdev);

	omapdss_device_disconnect(ddata->src, dssdev);
	drm_panel_remove(&ddata->panel);

	sysfs_remove_group(&dsi->dev.kobj, &dsicm_attr_group);

@@ -668,7 +619,7 @@ static int __exit dsicm_remove(struct mipi_dsi_device *dsi)
}

static const struct of_device_id dsicm_of_match[] = {
	{ .compatible = "omapdss,panel-dsi-cm", },
	{ .compatible = "panel-dsi-cm", },
	{},
};

+105 −23
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/sys_soc.h>

#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <video/mipi_display.h>

#include "omapdss.h"
@@ -217,6 +218,8 @@ static int dsi_vc_send_null(struct dsi_data *dsi, int channel);
static ssize_t _omap_dsi_host_transfer(struct dsi_data *dsi,
				       const struct mipi_dsi_msg *msg);

static void dsi_display_disable(struct omap_dss_device *dssdev);

/* DSI PLL HSDIV indices */
#define HSDIV_DISPC	0
#define HSDIV_DSI	1
@@ -384,6 +387,7 @@ struct dsi_data {
	bool te_enabled;
	bool ulps_enabled;
	bool ulps_auto_idle;
	bool video_enabled;

	struct delayed_work ulps_work;

@@ -424,6 +428,8 @@ struct dsi_data {

	unsigned int scp_clk_refcount;

	struct omap_dss_dsi_config config;

	struct dss_lcd_mgr_config mgr_config;
	struct videomode vm;
	enum mipi_dsi_pixel_format pix_fmt;
@@ -3624,7 +3630,7 @@ static int dsi_configure_pins(struct omap_dss_device *dssdev,
	return 0;
}

static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
static void dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
{
	struct dsi_data *dsi = to_dsi_data(dssdev);
	int bpp = mipi_dsi_pixel_format_to_bpp(dsi->pix_fmt);
@@ -3633,8 +3639,10 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
	int r;

	r = dsi_display_init_dispc(dsi);
	if (r)
		return r;
	if (r) {
		dev_err(dsi->dev, "failed to init dispc!\n");
		return;
	}

	if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
		switch (dsi->pix_fmt) {
@@ -3674,7 +3682,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
	if (r)
		goto err_mgr_enable;

	return 0;
	return;

err_mgr_enable:
	if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
@@ -3683,7 +3691,8 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
	}
err_pix_fmt:
	dsi_display_uninit_dispc(dsi);
	return r;
	dev_err(dsi->dev, "failed to enable DSI encoder!\n");
	return;
}

static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
@@ -3706,6 +3715,25 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel
	dsi_display_uninit_dispc(dsi);
}

static void dsi_disable_video_outputs(struct omap_dss_device *dssdev)
{
	struct dsi_data *dsi = to_dsi_data(dssdev);
	unsigned int i;

	dsi_bus_lock(dsi);
	dsi->video_enabled = false;

	for (i = 0; i < 4; i++) {
		if (!dsi->vc[i].dest)
			continue;
		dsi_disable_video_output(dssdev, i);
	}

	dsi_display_disable(dssdev);

	dsi_bus_unlock(dsi);
}

static void dsi_update_screen_dispc(struct dsi_data *dsi)
{
	unsigned int bytespp;
@@ -3894,6 +3922,11 @@ static int dsi_update_channel(struct omap_dss_device *dssdev, int channel)

	dsi_bus_lock(dsi);

	if (!dsi->video_enabled) {
		r = -EIO;
		goto err;
	}

	if (!dsi->vc[channel].dest) {
		r = -ENODEV;
		goto err;
@@ -4164,8 +4197,30 @@ static void dsi_display_enable(struct omap_dss_device *dssdev)
	struct dsi_data *dsi = to_dsi_data(dssdev);
	DSSDBG("dsi_display_enable\n");

	dsi_bus_lock(dsi);
	WARN_ON(!dsi_bus_is_locked(dsi));

	_dsi_display_enable(dsi);
}

static void dsi_enable_video_outputs(struct omap_dss_device *dssdev)
{
	struct dsi_data *dsi = to_dsi_data(dssdev);
	unsigned int i;

	dsi_bus_lock(dsi);

	dsi_display_enable(dssdev);

	for (i = 0; i < 4; i++) {
		if (!dsi->vc[i].dest)
			continue;
		dsi_enable_video_output(dssdev, i);
	}

	dsi->video_enabled = true;

	dsi_set_ulps_auto(dsi, true);

	dsi_bus_unlock(dsi);
}

@@ -4192,11 +4247,11 @@ static void dsi_display_disable(struct omap_dss_device *dssdev)
{
	struct dsi_data *dsi = to_dsi_data(dssdev);

	WARN_ON(!dsi_bus_is_locked(dsi));

	DSSDBG("dsi_display_disable\n");

	dsi_bus_lock(dsi);
	_dsi_display_disable(dsi, true, false);
	dsi_bus_unlock(dsi);
}

static int dsi_enable_te(struct dsi_data *dsi, bool enable)
@@ -4736,14 +4791,18 @@ static bool dsi_is_video_mode(struct omap_dss_device *dssdev)
}

static int dsi_set_config(struct omap_dss_device *dssdev,
		const struct omap_dss_dsi_config *config)
		const struct drm_display_mode *mode)
{
	struct dsi_data *dsi = to_dsi_data(dssdev);
	struct dsi_clk_calc_ctx ctx;
	struct omap_dss_dsi_config cfg = *config;
	struct videomode vm;
	struct omap_dss_dsi_config cfg = dsi->config;
	bool ok;
	int r;

	drm_display_mode_to_videomode(mode, &vm);
	cfg.vm = &vm;

	mutex_lock(&dsi->lock);

	cfg.mode = dsi->mode;
@@ -4906,9 +4965,15 @@ static ssize_t omap_dsi_host_transfer(struct mipi_dsi_host *host,
	int r;

	dsi_bus_lock(dsi);

	if (dsi->video_enabled) {
		dsi_set_ulps_auto(dsi, false);
		r = _omap_dsi_host_transfer(dsi, msg);
		dsi_set_ulps_auto(dsi, true);
	} else {
		r = -EIO;
	}

	dsi_bus_unlock(dsi);

	return r;
@@ -4929,6 +4994,23 @@ static int dsi_get_clocks(struct dsi_data *dsi)
	return 0;
}

static void dsi_set_timings(struct omap_dss_device *dssdev,
			    const struct drm_display_mode *mode)
{
	DSSDBG("dsi_set_timings\n");
	dsi_set_config(dssdev, mode);
}

static int dsi_check_timings(struct omap_dss_device *dssdev,
			     struct drm_display_mode *mode)
{
	DSSDBG("dsi_check_timings\n");

	/* TODO */

	return 0;
}

static int dsi_connect(struct omap_dss_device *src,
		       struct omap_dss_device *dst)
{
@@ -4944,15 +5026,13 @@ static void dsi_disconnect(struct omap_dss_device *src,
static const struct omap_dss_device_ops dsi_ops = {
	.connect = dsi_connect,
	.disconnect = dsi_disconnect,
	.enable = dsi_display_enable,
	.disable = dsi_display_disable,
	.enable = dsi_enable_video_outputs,
	.disable = dsi_disable_video_outputs,

	.dsi = {
		.set_config = dsi_set_config,

		.enable_video_output = dsi_enable_video_output,
		.disable_video_output = dsi_disable_video_output,
	.check_timings = dsi_check_timings,
	.set_timings = dsi_set_timings,

	.dsi = {
		.update = dsi_update_all,
		.is_video_mode = dsi_is_video_mode,
	},
@@ -5080,10 +5160,12 @@ static int omap_dsi_host_attach(struct mipi_dsi_host *host,
	INIT_DEFERRABLE_WORK(&dsi->ulps_work,
			     omap_dsi_ulps_work_callback);

	dsi_bus_lock(dsi);
	dsi->config.hs_clk_min = 150000000; // TODO: get from client?
	dsi->config.hs_clk_max = client->hs_rate;
	dsi->config.lp_clk_min = 7000000; // TODO: get from client?
	dsi->config.lp_clk_max = client->lp_rate;

	dsi->ulps_auto_idle = false;
	dsi_set_ulps_auto(dsi, true);
	dsi_bus_unlock(dsi);

	return 0;
}
+0 −1
Original line number Diff line number Diff line
@@ -174,7 +174,6 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
};

static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = {
	{ .compatible = "panel-dsi-cm" },
	{},
};

+0 −8
Original line number Diff line number Diff line
@@ -281,14 +281,6 @@ struct omap_dss_writeback_info {
struct omapdss_dsi_ops {
	int (*update)(struct omap_dss_device *dssdev);
	bool (*is_video_mode)(struct omap_dss_device *dssdev);

	/* legacy API used by omapdss panels */
	int (*set_config)(struct omap_dss_device *dssdev,
			const struct omap_dss_dsi_config *cfg);

	int (*enable_video_output)(struct omap_dss_device *dssdev, int channel);
	void (*disable_video_output)(struct omap_dss_device *dssdev,
			int channel);
};

struct omap_dss_device_ops {