[PATCH v2 44/50] drm/omap: dpi: Register a drm_bridge
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue Aug 20 01:17:15 UTC 2019
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: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
drivers/gpu/drm/omapdrm/dss/dpi.c | 205 ++++++++++++++++++------------
1 file changed, 122 insertions(+), 83 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
index c167bd1116ec..3874e6b6ec49 100644
--- a/drivers/gpu/drm/omapdrm/dss/dpi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -21,6 +21,8 @@
#include <linux/string.h>
#include <linux/sys_soc.h>
+#include <drm/drm_bridge.h>
+
#include "dss.h"
#include "omapdss.h"
@@ -41,12 +43,10 @@ struct dpi_data {
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 +354,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,29 +417,76 @@ 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 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 = drm_bridge_to_dpi(bridge);
+ unsigned long clock = mode->clock * 1000;
+ int ret;
+
+ 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);
+
+ mutex_lock(&dpi->lock);
+ dpi->pixelclock = adjusted_mode->clock * 1000;
+ mutex_unlock(&dpi->lock);
}
-static void dpi_display_enable(struct omap_dss_device *dssdev)
+static void dpi_bridge_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
- struct omap_dss_device *out = &dpi->output;
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
int r;
mutex_lock(&dpi->lock);
@@ -428,7 +501,7 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
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;
@@ -468,9 +541,10 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
mutex_unlock(&dpi->lock);
}
-static void dpi_display_disable(struct omap_dss_device *dssdev)
+static void dpi_bridge_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
- struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
mutex_lock(&dpi->lock);
@@ -490,71 +564,33 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
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;
-
- mode->clock = pck / 1000;
-
- return 0;
-}
-
-static void dpi_set_timings(struct omap_dss_device *dssdev,
- const struct drm_display_mode *mode)
-{
- 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);
-}
-
-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,
+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,
+ .atomic_enable = dpi_bridge_enable,
+ .atomic_disable = dpi_bridge_disable,
};
+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;
+
+ drm_bridge_add(&dpi->bridge);
+}
+
+static void dpi_bridge_cleanup(struct dpi_data *dpi)
+{
+ drm_bridge_remove(&dpi->bridge);
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialisation and Cleanup
+ */
+
/*
* Return a hardcoded channel for the DPI output. This should work for
* current use cases, but this can be later expanded to either resolve
@@ -597,6 +633,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,10 +656,9 @@ 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);
+ r = omapdss_device_init_output(out, &dpi->bridge);
if (r < 0)
return r;
@@ -637,6 +674,8 @@ static void dpi_uninit_output_port(struct device_node *port)
omapdss_device_unregister(out);
omapdss_device_cleanup_output(out);
+
+ dpi_bridge_cleanup(dpi);
}
/* -----------------------------------------------------------------------------
--
Regards,
Laurent Pinchart
More information about the dri-devel
mailing list