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 @@ ...@@ -21,6 +21,8 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
#include <drm/drm_bridge.h>
#include "dss.h" #include "dss.h"
#include "omapdss.h" #include "omapdss.h"
...@@ -34,19 +36,15 @@ struct dpi_data { ...@@ -34,19 +36,15 @@ struct dpi_data {
enum dss_clk_source clk_src; enum dss_clk_source clk_src;
struct dss_pll *pll; struct dss_pll *pll;
struct mutex lock;
struct dss_lcd_mgr_config mgr_config; struct dss_lcd_mgr_config mgr_config;
unsigned long pixelclock; unsigned long pixelclock;
int data_lines; int data_lines;
struct omap_dss_device output; struct omap_dss_device output;
struct drm_bridge bridge;
}; };
static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) #define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
{
return container_of(dssdev, struct dpi_data, output);
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Clock Handling and PLL * Clock Handling and PLL
...@@ -354,6 +352,32 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi) ...@@ -354,6 +352,32 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config); 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) static int dpi_verify_pll(struct dss_pll *pll)
{ {
int r; int r;
...@@ -391,44 +415,86 @@ static void dpi_init_pll(struct dpi_data *dpi) ...@@ -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, static int dpi_bridge_attach(struct drm_bridge *bridge,
struct omap_dss_device *dst) 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); 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, static enum drm_mode_status
struct omap_dss_device *dst) 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 dpi_data *dpi = drm_bridge_to_dpi(bridge);
struct omap_dss_device *out = &dpi->output; unsigned long clock = mode->clock * 1000;
int r; 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) { if (dpi->vdds_dsi_reg) {
r = regulator_enable(dpi->vdds_dsi_reg); r = regulator_enable(dpi->vdds_dsi_reg);
if (r) if (r)
goto err_reg_enable; return;
} }
r = dispc_runtime_get(dpi->dss->dispc); r = dispc_runtime_get(dpi->dss->dispc);
if (r) if (r)
goto err_get_dispc; 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) if (r)
goto err_src_sel; goto err_src_sel;
...@@ -450,8 +516,6 @@ static void dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -450,8 +516,6 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
if (r) if (r)
goto err_mgr_enable; goto err_mgr_enable;
mutex_unlock(&dpi->lock);
return; return;
err_mgr_enable: err_mgr_enable:
...@@ -464,15 +528,11 @@ static void dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -464,15 +528,11 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
err_get_dispc: err_get_dispc:
if (dpi->vdds_dsi_reg) if (dpi->vdds_dsi_reg)
regulator_disable(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); struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
mutex_lock(&dpi->lock);
dss_mgr_disable(&dpi->output); dss_mgr_disable(&dpi->output);
...@@ -486,74 +546,34 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) ...@@ -486,74 +546,34 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
if (dpi->vdds_dsi_reg) if (dpi->vdds_dsi_reg)
regulator_disable(dpi->vdds_dsi_reg); regulator_disable(dpi->vdds_dsi_reg);
mutex_unlock(&dpi->lock);
} }
static int dpi_check_timings(struct omap_dss_device *dssdev, static const struct drm_bridge_funcs dpi_bridge_funcs = {
struct drm_display_mode *mode) .attach = dpi_bridge_attach,
{ .mode_valid = dpi_bridge_mode_valid,
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); .mode_fixup = dpi_bridge_mode_fixup,
int lck_div, pck_div; .mode_set = dpi_bridge_mode_set,
unsigned long fck; .enable = dpi_bridge_enable,
unsigned long pck; .disable = dpi_bridge_disable,
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;
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, static void dpi_bridge_cleanup(struct dpi_data *dpi)
const struct drm_display_mode *mode)
{ {
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); drm_bridge_remove(&dpi->bridge);
DSSDBG("dpi_set_timings\n");
mutex_lock(&dpi->lock);
dpi->pixelclock = mode->clock * 1000;
mutex_unlock(&dpi->lock);
} }
static const struct omap_dss_device_ops dpi_ops = { /* -----------------------------------------------------------------------------
.connect = dpi_connect, * Initialisation and Cleanup
.disconnect = dpi_disconnect, */
.enable = dpi_display_enable,
.disable = dpi_display_disable,
.check_timings = dpi_check_timings,
.set_timings = dpi_set_timings,
};
/* /*
* Return a hardcoded channel for the DPI output. This should work for * 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) ...@@ -597,6 +617,8 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
u32 port_num = 0; u32 port_num = 0;
int r; int r;
dpi_bridge_init(dpi);
of_property_read_u32(port, "reg", &port_num); of_property_read_u32(port, "reg", &port_num);
dpi->id = port_num <= 2 ? port_num : 0; 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) ...@@ -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->type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(dpi); out->dispc_channel = dpi_get_channel(dpi);
out->of_port = port_num; out->of_port = port_num;
out->ops = &dpi_ops;
out->owner = THIS_MODULE; out->owner = THIS_MODULE;
r = omapdss_device_init_output(out, NULL); r = omapdss_device_init_output(out, &dpi->bridge);
if (r < 0) if (r < 0) {
dpi_bridge_cleanup(dpi);
return r; return r;
}
omapdss_device_register(out); omapdss_device_register(out);
...@@ -637,6 +660,8 @@ static void dpi_uninit_output_port(struct device_node *port) ...@@ -637,6 +660,8 @@ static void dpi_uninit_output_port(struct device_node *port)
omapdss_device_unregister(out); omapdss_device_unregister(out);
omapdss_device_cleanup_output(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, ...@@ -702,8 +727,6 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
dpi->dss = dss; dpi->dss = dss;
port->data = dpi; port->data = dpi;
mutex_init(&dpi->lock);
r = dpi_init_regulator(dpi); r = dpi_init_regulator(dpi);
if (r) if (r)
return 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