Commit d0234043 authored by Robert Chiras's avatar Robert Chiras Committed by Stefan Agner

drm/mxsfb: Update mxsfb to support a bridge

Currently, the MXSFB DRM driver only supports a panel. But, its output
display signal can also be redirected to another encoder, like a DSI
controller. In this case, that DSI controller may act like a drm_bridge.
In order support this use-case too, this patch adds support for drm_bridge
in mxsfb.
Signed-off-by: default avatarRobert Chiras <robert.chiras@nxp.com>
Tested-by: default avatarGuido Günther <agx@sigxcpu.org>
Signed-off-by: default avatarStefan Agner <stefan@agner.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/1567078215-31601-2-git-send-email-robert.chiras@nxp.com
parent 67c698fc
...@@ -95,8 +95,11 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb) ...@@ -95,8 +95,11 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
reg = readl(mxsfb->base + LCDC_CTRL); reg = readl(mxsfb->base + LCDC_CTRL);
if (mxsfb->connector.display_info.num_bus_formats) if (mxsfb->connector->display_info.num_bus_formats)
bus_format = mxsfb->connector.display_info.bus_formats[0]; bus_format = mxsfb->connector->display_info.bus_formats[0];
DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
bus_format);
reg &= ~CTRL_BUS_WIDTH_MASK; reg &= ~CTRL_BUS_WIDTH_MASK;
switch (bus_format) { switch (bus_format) {
...@@ -204,8 +207,9 @@ static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb) ...@@ -204,8 +207,9 @@ static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
{ {
struct drm_device *drm = mxsfb->pipe.crtc.dev;
struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
const u32 bus_flags = mxsfb->connector.display_info.bus_flags; const u32 bus_flags = mxsfb->connector->display_info.bus_flags;
u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
int err; int err;
...@@ -229,6 +233,13 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) ...@@ -229,6 +233,13 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
m->crtc_clock,
(int)(clk_get_rate(mxsfb->clk) / 1000));
DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
bus_flags);
DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay), TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
mxsfb->base + mxsfb->devdata->transfer_count); mxsfb->base + mxsfb->devdata->transfer_count);
......
...@@ -101,9 +101,25 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, ...@@ -101,9 +101,25 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state, struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state) struct drm_plane_state *plane_state)
{ {
struct drm_connector *connector;
struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
struct drm_device *drm = pipe->plane.dev; struct drm_device *drm = pipe->plane.dev;
if (!mxsfb->connector) {
list_for_each_entry(connector,
&drm->mode_config.connector_list,
head)
if (connector->encoder == &mxsfb->pipe.encoder) {
mxsfb->connector = connector;
break;
}
}
if (!mxsfb->connector) {
dev_warn(drm->dev, "No connector attached, using default\n");
mxsfb->connector = &mxsfb->panel_connector;
}
pm_runtime_get_sync(drm->dev); pm_runtime_get_sync(drm->dev);
drm_panel_prepare(mxsfb->panel); drm_panel_prepare(mxsfb->panel);
mxsfb_crtc_enable(mxsfb); mxsfb_crtc_enable(mxsfb);
...@@ -129,6 +145,9 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) ...@@ -129,6 +145,9 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
drm_crtc_send_vblank_event(crtc, event); drm_crtc_send_vblank_event(crtc, event);
} }
spin_unlock_irq(&drm->event_lock); spin_unlock_irq(&drm->event_lock);
if (mxsfb->connector != &mxsfb->panel_connector)
mxsfb->connector = NULL;
} }
static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
...@@ -226,16 +245,33 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) ...@@ -226,16 +245,33 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags)
ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL, mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
&mxsfb->connector); mxsfb->connector);
if (ret < 0) { if (ret < 0) {
dev_err(drm->dev, "Cannot setup simple display pipe\n"); dev_err(drm->dev, "Cannot setup simple display pipe\n");
goto err_vblank; goto err_vblank;
} }
ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector); /*
if (ret) { * Attach panel only if there is one.
dev_err(drm->dev, "Cannot connect panel\n"); * If there is no panel attach, it must be a bridge. In this case, we
goto err_vblank; * need a reference to its connector for a proper initialization.
* We will do this check in pipe->enable(), since the connector won't
* be attached to an encoder until then.
*/
if (mxsfb->panel) {
ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
if (ret) {
dev_err(drm->dev, "Cannot connect panel: %d\n", ret);
goto err_vblank;
}
} else if (mxsfb->bridge) {
ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
mxsfb->bridge);
if (ret) {
dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
goto err_vblank;
}
} }
drm->mode_config.min_width = MXSFB_MIN_XRES; drm->mode_config.min_width = MXSFB_MIN_XRES;
......
...@@ -27,8 +27,10 @@ struct mxsfb_drm_private { ...@@ -27,8 +27,10 @@ struct mxsfb_drm_private {
struct clk *clk_disp_axi; struct clk *clk_disp_axi;
struct drm_simple_display_pipe pipe; struct drm_simple_display_pipe pipe;
struct drm_connector connector; struct drm_connector panel_connector;
struct drm_connector *connector;
struct drm_panel *panel; struct drm_panel *panel;
struct drm_bridge *bridge;
}; };
int mxsfb_setup_crtc(struct drm_device *dev); int mxsfb_setup_crtc(struct drm_device *dev);
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
static struct mxsfb_drm_private * static struct mxsfb_drm_private *
drm_connector_to_mxsfb_drm_private(struct drm_connector *connector) drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
{ {
return container_of(connector, struct mxsfb_drm_private, connector); return container_of(connector, struct mxsfb_drm_private,
panel_connector);
} }
static int mxsfb_panel_get_modes(struct drm_connector *connector) static int mxsfb_panel_get_modes(struct drm_connector *connector)
...@@ -76,22 +77,23 @@ static const struct drm_connector_funcs mxsfb_panel_connector_funcs = { ...@@ -76,22 +77,23 @@ static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
int mxsfb_create_output(struct drm_device *drm) int mxsfb_create_output(struct drm_device *drm)
{ {
struct mxsfb_drm_private *mxsfb = drm->dev_private; struct mxsfb_drm_private *mxsfb = drm->dev_private;
struct drm_panel *panel;
int ret; int ret;
ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL); ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
&mxsfb->panel, &mxsfb->bridge);
if (ret) if (ret)
return ret; return ret;
mxsfb->connector.dpms = DRM_MODE_DPMS_OFF; if (mxsfb->panel) {
mxsfb->connector.polled = 0; mxsfb->connector = &mxsfb->panel_connector;
drm_connector_helper_add(&mxsfb->connector, mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
&mxsfb_panel_connector_helper_funcs); mxsfb->connector->polled = 0;
ret = drm_connector_init(drm, &mxsfb->connector, drm_connector_helper_add(mxsfb->connector,
&mxsfb_panel_connector_funcs, &mxsfb_panel_connector_helper_funcs);
DRM_MODE_CONNECTOR_Unknown); ret = drm_connector_init(drm, mxsfb->connector,
if (!ret) &mxsfb_panel_connector_funcs,
mxsfb->panel = panel; DRM_MODE_CONNECTOR_Unknown);
}
return ret; return ret;
} }
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