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

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
......@@ -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 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment