aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2019-04-17 10:10:00 +0200
committerLinus Walleij <linus.walleij@linaro.org>2019-04-17 10:10:50 +0200
commit5516b1c3fb52f8186547481d81d2af08916f5367 (patch)
tree59ecc2d87afd402a89f5f266f07d08ec008e30ad
parentc9f9761ff0dd1da6e1d4710c2c3368dc6a01336b (diff)
downloadlinux-stericsson-ux500-mcde.tar.gz
new workux500-mcde
-rw-r--r--drivers/gpu/drm/mcde/mcde_display.c1
-rw-r--r--drivers/gpu/drm/mcde/mcde_drv.c17
-rw-r--r--drivers/gpu/drm/mcde/mcde_dsi.c141
3 files changed, 102 insertions, 57 deletions
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
index efa4c1c752a8..3c73adc9ba69 100644
--- a/drivers/gpu/drm/mcde/mcde_display.c
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -1281,4 +1281,3 @@ int mcde_display_init(struct drm_device *drm)
return 0;
}
EXPORT_SYMBOL_GPL(mcde_display_init);
-
diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
index ae70bc74544f..69de8ee6bc45 100644
--- a/drivers/gpu/drm/mcde/mcde_drv.c
+++ b/drivers/gpu/drm/mcde/mcde_drv.c
@@ -142,6 +142,11 @@ static int mcde_modeset_init(struct drm_device *drm)
struct mcde *mcde = drm->dev_private;
int ret;
+ if (!mcde->bridge) {
+ dev_err(drm->dev, "no display output bridge yet\n");
+ return -EPROBE_DEFER;
+ }
+
mode_config = &drm->mode_config;
mode_config->funcs = &mode_config_funcs;
/* This hardware can do 1080p */
@@ -164,6 +169,18 @@ static int mcde_modeset_init(struct drm_device *drm)
goto out_config;
}
+ /*
+ * Attach the DSI bridge
+ * TODO: when adding support for the CLCD bridge we add that here
+ * instead.
+ */
+ ret = drm_simple_display_pipe_attach_bridge(&mcde->pipe,
+ mcde->bridge);
+ if (ret) {
+ dev_err(drm->dev, "failed to attach display output bridge\n");
+ goto out_config;
+ }
+
drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm);
drm_fbdev_generic_setup(drm, 32);
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 642f68b5f1d9..82e0b492416f 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -12,6 +12,7 @@
#include <video/mipi_display.h>
#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
@@ -417,10 +418,10 @@
struct mcde_dsi {
struct device *dev;
struct mcde *mcde;
- struct drm_encoder encoder;
+ struct drm_bridge bridge;
struct drm_connector connector;
struct drm_panel *panel;
- struct drm_bridge *bridge;
+ struct drm_bridge *bridge_out;
struct mipi_dsi_host dsi_host;
struct mipi_dsi_device *mdsi;
struct clk *hs_clk;
@@ -433,9 +434,9 @@ struct mcde_dsi {
struct regmap *prcmu;
};
-static inline struct mcde_dsi *encoder_to_mcde_dsi(struct drm_encoder *e)
+static inline struct mcde_dsi *bridge_to_mcde_dsi(struct drm_bridge *bridge)
{
- return container_of(e, struct mcde_dsi, encoder);
+ return container_of(bridge, struct mcde_dsi, bridge);
}
static inline struct mcde_dsi *host_to_mcde_dsi(struct mipi_dsi_host *h)
@@ -718,7 +719,7 @@ void mcde_dsi_te_request(struct mipi_dsi_device *mdsi)
}
static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *mode)
{
u8 bpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format);
u64 bpl;
@@ -1018,10 +1019,19 @@ static void mcde_dsi_start(struct mcde_dsi *d)
dev_info(d->dev, "DSI link enabled\n");
}
-static void mcde_dsi_enable(struct drm_encoder *encoder)
+
+static void mcde_dsi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
+
+ dev_info(d->dev, "enable DSI master\n");
+};
+
+static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adj)
{
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
- struct mcde_dsi *d = encoder_to_mcde_dsi(encoder);
+ struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
unsigned long pixel_clock_hz = mode->clock * 1000;
unsigned long hs_freq, lp_freq;
u32 val;
@@ -1032,7 +1042,7 @@ static void mcde_dsi_enable(struct drm_encoder *encoder)
return;
}
- dev_info(d->dev, "enable DSI master for %dx%d %lu Hz %s mode\n",
+ dev_info(d->dev, "set DSI master to %dx%d %lu Hz %s mode\n",
mode->hdisplay, mode->vdisplay, pixel_clock_hz,
(d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD"
);
@@ -1127,11 +1137,13 @@ static void mcde_dsi_wait_for_video_mode_stop(struct mcde_dsi *d)
}
}
-static void mcde_dsi_disable(struct drm_encoder *encoder)
+static void mcde_dsi_bridge_disable(struct drm_bridge *bridge)
{
- struct mcde_dsi *d = encoder_to_mcde_dsi(encoder);
+ struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
u32 val;
+ dev_info(d->dev, "disable DSI master\n");
+
/* Disable all error interrupts */
writel(0, d->regs + DSI_VID_MODE_STS_CTL);
@@ -1151,15 +1163,10 @@ static void mcde_dsi_disable(struct drm_encoder *encoder)
clk_disable_unprepare(d->lp_clk);
}
-static const struct drm_encoder_helper_funcs mcde_dsi_encoder_helper_funcs = {
- .enable = mcde_dsi_enable,
- .disable = mcde_dsi_disable,
-};
-
-static const struct drm_encoder_funcs mcde_dsi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
+/*
+ * This connector needs no special handling, just use the default
+ * helpers for everything. It's pretty dummy.
+ */
static const struct drm_connector_funcs mcde_dsi_connector_funcs = {
.reset = drm_atomic_helper_connector_reset,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1172,6 +1179,7 @@ static int mcde_dsi_get_modes(struct drm_connector *connector)
{
struct mcde_dsi *d = connector_to_mcde_dsi(connector);
+ /* Just pass the question to the panel */
if (d->panel)
return drm_panel_get_modes(d->panel);
@@ -1180,9 +1188,56 @@ static int mcde_dsi_get_modes(struct drm_connector *connector)
return 0;
}
+static enum drm_mode_status mcde_dsi_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /* TODO: check mode */
+ /* FIXME: can this function be omitted? */
+
+ return MODE_OK;
+}
+
static const struct drm_connector_helper_funcs
mcde_dsi_connector_helper_funcs = {
.get_modes = mcde_dsi_get_modes,
+ .mode_valid = mcde_dsi_mode_valid,
+};
+
+static int mcde_dsi_bridge_attach(struct drm_bridge *bridge)
+{
+ struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
+ struct drm_device *drm = bridge->dev;
+ int ret;
+
+ drm_connector_helper_add(&d->connector,
+ &mcde_dsi_connector_helper_funcs);
+
+ if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
+ dev_err(d->dev, "we need atomic updates\n");
+ return -ENOTSUPP;
+ }
+
+ ret = drm_connector_init(drm, &d->connector,
+ &mcde_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (ret) {
+ dev_err(d->dev, "failed to initialize DSI bridge connector\n");
+ return ret;
+ }
+ d->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
+ drm_connector_attach_encoder(&d->connector, bridge->encoder);
+ d->connector.status = connector_status_connected;
+
+ dev_info(d->dev, "intialized DSI bridge connector\n");
+
+ return 0;
+}
+
+static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
+ .attach = mcde_dsi_bridge_attach,
+ .mode_set = mcde_dsi_bridge_mode_set,
+ .disable = mcde_dsi_bridge_disable,
+ .enable = mcde_dsi_bridge_enable,
};
static int mcde_dsi_bind(struct device *dev, struct device *master,
@@ -1191,12 +1246,9 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct mcde *mcde = drm->dev_private;
struct mcde_dsi *d = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &d->encoder;
- struct drm_connector *connector = &d->connector;
struct device_node *child;
struct drm_panel *panel = NULL;
struct drm_bridge *bridge = NULL;
- int ret;
if (!of_get_available_child_count(dev->of_node)) {
dev_info(dev, "unused DSI interface\n");
@@ -1236,28 +1288,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
/* Start up the hardware */
mcde_dsi_start(d);
- /* Create an encoder and attach the display bridge to it */
- drm_encoder_init(drm, encoder, &mcde_dsi_encoder_funcs,
- DRM_MODE_ENCODER_DSI, NULL);
- drm_encoder_helper_add(encoder, &mcde_dsi_encoder_helper_funcs);
-
- /* Create a connector and attach the encoder to it */
- connector->polled = DRM_CONNECTOR_POLL_HPD;
- ret = drm_connector_init(encoder->dev, connector,
- &mcde_dsi_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
- if (ret) {
- dev_err(dev, "failed to initialize connector\n");
- drm_encoder_cleanup(encoder);
- return ret;
- }
- connector->status = connector_status_disconnected;
- drm_connector_helper_add(connector, &mcde_dsi_connector_helper_funcs);
- drm_connector_attach_encoder(connector, encoder);
- drm_connector_register(connector);
-
- dev_info(dev, "initialized encoder and connector\n");
-
/* Look for a panel as a child to this node */
for_each_available_child_of_node(dev->of_node, child) {
panel = of_drm_find_panel(child);
@@ -1290,19 +1320,17 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
return -ENODEV;
}
- d->bridge = bridge;
- d->connector.status = connector_status_connected;
+ d->bridge_out = bridge;
- ret = drm_bridge_attach(encoder, bridge, NULL);
- if (ret) {
- dev_err(dev, "bridge attach failed: %d\n", ret);
- return ret;
- }
+ /* Create a bridge for this DSI channel */
+ d->bridge.funcs = &mcde_dsi_bridge_funcs;
+ d->bridge.of_node = dev->of_node;
+ drm_bridge_add(&d->bridge);
/* FIXME: first come first serve, use a list */
- mcde->connector = connector;
- mcde->bridge = bridge;
- dev_info(dev, "set up DSI connector and panel bridge\n");
+ mcde->bridge = &d->bridge;
+
+ dev_info(dev, "initialized MCDE DSI bridge\n");
return 0;
}
@@ -1312,6 +1340,8 @@ static void mcde_dsi_unbind(struct device *dev, struct device *master,
{
struct mcde_dsi *d = dev_get_drvdata(dev);
+ if (d->panel)
+ drm_panel_bridge_remove(d->bridge_out);
regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
clk_disable_unprepare(d->hs_clk);
@@ -1375,7 +1405,6 @@ static int mcde_dsi_remove(struct platform_device *pdev)
struct mcde_dsi *d = platform_get_drvdata(pdev);
component_del(&pdev->dev, &mcde_dsi_component_ops);
- mcde_dsi_disable(&d->encoder);
mipi_dsi_host_unregister(&d->dsi_host);
return 0;