Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Robert Chiras <robert.chiras@nxp.com>
Tested-by: Guido Günther <agx@sigxcpu.org>
Signed-off-by: Stefan Agner <stefan@agner.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/1567078215-31601-2-git-send-email-robert.chiras@nxp.com

authored by

Robert Chiras and committed by
Stefan Agner
d0234043 67c698fc

+72 -21
+14 -3
drivers/gpu/drm/mxsfb/mxsfb_crtc.c
··· 95 95 96 96 reg = readl(mxsfb->base + LCDC_CTRL); 97 97 98 - if (mxsfb->connector.display_info.num_bus_formats) 99 - bus_format = mxsfb->connector.display_info.bus_formats[0]; 98 + if (mxsfb->connector->display_info.num_bus_formats) 99 + bus_format = mxsfb->connector->display_info.bus_formats[0]; 100 + 101 + DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n", 102 + bus_format); 100 103 101 104 reg &= ~CTRL_BUS_WIDTH_MASK; 102 105 switch (bus_format) { ··· 207 204 208 205 static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) 209 206 { 207 + struct drm_device *drm = mxsfb->pipe.crtc.dev; 210 208 struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; 211 - const u32 bus_flags = mxsfb->connector.display_info.bus_flags; 209 + const u32 bus_flags = mxsfb->connector->display_info.bus_flags; 212 210 u32 vdctrl0, vsync_pulse_len, hsync_pulse_len; 213 211 int err; 214 212 ··· 232 228 return; 233 229 234 230 clk_set_rate(mxsfb->clk, m->crtc_clock * 1000); 231 + 232 + DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", 233 + m->crtc_clock, 234 + (int)(clk_get_rate(mxsfb->clk) / 1000)); 235 + DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n", 236 + bus_flags); 237 + DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); 235 238 236 239 writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) | 237 240 TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
+41 -5
drivers/gpu/drm/mxsfb/mxsfb_drv.c
··· 101 101 struct drm_crtc_state *crtc_state, 102 102 struct drm_plane_state *plane_state) 103 103 { 104 + struct drm_connector *connector; 104 105 struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); 105 106 struct drm_device *drm = pipe->plane.dev; 107 + 108 + if (!mxsfb->connector) { 109 + list_for_each_entry(connector, 110 + &drm->mode_config.connector_list, 111 + head) 112 + if (connector->encoder == &mxsfb->pipe.encoder) { 113 + mxsfb->connector = connector; 114 + break; 115 + } 116 + } 117 + 118 + if (!mxsfb->connector) { 119 + dev_warn(drm->dev, "No connector attached, using default\n"); 120 + mxsfb->connector = &mxsfb->panel_connector; 121 + } 106 122 107 123 pm_runtime_get_sync(drm->dev); 108 124 drm_panel_prepare(mxsfb->panel); ··· 145 129 drm_crtc_send_vblank_event(crtc, event); 146 130 } 147 131 spin_unlock_irq(&drm->event_lock); 132 + 133 + if (mxsfb->connector != &mxsfb->panel_connector) 134 + mxsfb->connector = NULL; 148 135 } 149 136 150 137 static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, ··· 245 226 246 227 ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs, 247 228 mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL, 248 - &mxsfb->connector); 229 + mxsfb->connector); 249 230 if (ret < 0) { 250 231 dev_err(drm->dev, "Cannot setup simple display pipe\n"); 251 232 goto err_vblank; 252 233 } 253 234 254 - ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector); 255 - if (ret) { 256 - dev_err(drm->dev, "Cannot connect panel\n"); 257 - goto err_vblank; 235 + /* 236 + * Attach panel only if there is one. 237 + * If there is no panel attach, it must be a bridge. In this case, we 238 + * need a reference to its connector for a proper initialization. 239 + * We will do this check in pipe->enable(), since the connector won't 240 + * be attached to an encoder until then. 241 + */ 242 + 243 + if (mxsfb->panel) { 244 + ret = drm_panel_attach(mxsfb->panel, mxsfb->connector); 245 + if (ret) { 246 + dev_err(drm->dev, "Cannot connect panel: %d\n", ret); 247 + goto err_vblank; 248 + } 249 + } else if (mxsfb->bridge) { 250 + ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe, 251 + mxsfb->bridge); 252 + if (ret) { 253 + dev_err(drm->dev, "Cannot connect bridge: %d\n", ret); 254 + goto err_vblank; 255 + } 258 256 } 259 257 260 258 drm->mode_config.min_width = MXSFB_MIN_XRES;
+3 -1
drivers/gpu/drm/mxsfb/mxsfb_drv.h
··· 27 27 struct clk *clk_disp_axi; 28 28 29 29 struct drm_simple_display_pipe pipe; 30 - struct drm_connector connector; 30 + struct drm_connector panel_connector; 31 + struct drm_connector *connector; 31 32 struct drm_panel *panel; 33 + struct drm_bridge *bridge; 32 34 }; 33 35 34 36 int mxsfb_setup_crtc(struct drm_device *dev);
+14 -12
drivers/gpu/drm/mxsfb/mxsfb_out.c
··· 21 21 static struct mxsfb_drm_private * 22 22 drm_connector_to_mxsfb_drm_private(struct drm_connector *connector) 23 23 { 24 - return container_of(connector, struct mxsfb_drm_private, connector); 24 + return container_of(connector, struct mxsfb_drm_private, 25 + panel_connector); 25 26 } 26 27 27 28 static int mxsfb_panel_get_modes(struct drm_connector *connector) ··· 77 76 int mxsfb_create_output(struct drm_device *drm) 78 77 { 79 78 struct mxsfb_drm_private *mxsfb = drm->dev_private; 80 - struct drm_panel *panel; 81 79 int ret; 82 80 83 - ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL); 81 + ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, 82 + &mxsfb->panel, &mxsfb->bridge); 84 83 if (ret) 85 84 return ret; 86 85 87 - mxsfb->connector.dpms = DRM_MODE_DPMS_OFF; 88 - mxsfb->connector.polled = 0; 89 - drm_connector_helper_add(&mxsfb->connector, 90 - &mxsfb_panel_connector_helper_funcs); 91 - ret = drm_connector_init(drm, &mxsfb->connector, 92 - &mxsfb_panel_connector_funcs, 93 - DRM_MODE_CONNECTOR_Unknown); 94 - if (!ret) 95 - mxsfb->panel = panel; 86 + if (mxsfb->panel) { 87 + mxsfb->connector = &mxsfb->panel_connector; 88 + mxsfb->connector->dpms = DRM_MODE_DPMS_OFF; 89 + mxsfb->connector->polled = 0; 90 + drm_connector_helper_add(mxsfb->connector, 91 + &mxsfb_panel_connector_helper_funcs); 92 + ret = drm_connector_init(drm, mxsfb->connector, 93 + &mxsfb_panel_connector_funcs, 94 + DRM_MODE_CONNECTOR_Unknown); 95 + } 96 96 97 97 return ret; 98 98 }