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

drm/pl111: Replace custom connector with panel bridge

This replaces the custom connector in the PL111 with the
panel bridge helper.

This works nicely for all standard panels, but since there
are several PL11x-based systems that will need to use the dumb
VGA connector bridge we use drm_of_find_panel_or_bridge()
and make some headroom for dealing with bridges that are
not panels as well, and drop a TODO in the code.

Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20170908124709.4758-3-linus.walleij@linaro.org

+49 -168
+2 -1
drivers/gpu/drm/pl111/Kconfig
··· 6 6 select DRM_KMS_HELPER 7 7 select DRM_KMS_CMA_HELPER 8 8 select DRM_GEM_CMA_HELPER 9 - select DRM_PANEL 9 + select DRM_BRIDGE 10 + select DRM_PANEL_BRIDGE 10 11 select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE 11 12 help 12 13 Choose this option for DRM support for the PL111 CLCD controller.
+1 -2
drivers/gpu/drm/pl111/Makefile
··· 1 - pl111_drm-y += pl111_connector.o \ 2 - pl111_display.o \ 1 + pl111_drm-y += pl111_display.o \ 3 2 pl111_drv.o 4 3 5 4 pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o
-126
drivers/gpu/drm/pl111/pl111_connector.c
··· 1 - /* 2 - * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved. 3 - * 4 - * Parts of this file were based on sources as follows: 5 - * 6 - * Copyright (c) 2006-2008 Intel Corporation 7 - * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 8 - * Copyright (C) 2011 Texas Instruments 9 - * 10 - * This program is free software and is provided to you under the terms of the 11 - * GNU General Public License version 2 as published by the Free Software 12 - * Foundation, and any use by you of this program is subject to the terms of 13 - * such GNU licence. 14 - * 15 - */ 16 - 17 - /** 18 - * pl111_drm_connector.c 19 - * Implementation of the connector functions for PL111 DRM 20 - */ 21 - #include <linux/amba/clcd-regs.h> 22 - #include <linux/version.h> 23 - #include <linux/shmem_fs.h> 24 - #include <linux/dma-buf.h> 25 - 26 - #include <drm/drmP.h> 27 - #include <drm/drm_atomic_helper.h> 28 - #include <drm/drm_crtc_helper.h> 29 - #include <drm/drm_of.h> 30 - #include <drm/drm_panel.h> 31 - 32 - #include "pl111_drm.h" 33 - 34 - static void pl111_connector_destroy(struct drm_connector *connector) 35 - { 36 - struct pl111_drm_connector *pl111_connector = 37 - to_pl111_connector(connector); 38 - 39 - if (pl111_connector->panel) 40 - drm_panel_detach(pl111_connector->panel); 41 - 42 - drm_connector_unregister(connector); 43 - drm_connector_cleanup(connector); 44 - } 45 - 46 - static enum drm_connector_status pl111_connector_detect(struct drm_connector 47 - *connector, bool force) 48 - { 49 - struct pl111_drm_connector *pl111_connector = 50 - to_pl111_connector(connector); 51 - 52 - return (pl111_connector->panel ? 53 - connector_status_connected : 54 - connector_status_disconnected); 55 - } 56 - 57 - static int pl111_connector_helper_get_modes(struct drm_connector *connector) 58 - { 59 - struct pl111_drm_connector *pl111_connector = 60 - to_pl111_connector(connector); 61 - 62 - if (!pl111_connector->panel) 63 - return 0; 64 - 65 - return drm_panel_get_modes(pl111_connector->panel); 66 - } 67 - 68 - const struct drm_connector_funcs connector_funcs = { 69 - .fill_modes = drm_helper_probe_single_connector_modes, 70 - .destroy = pl111_connector_destroy, 71 - .detect = pl111_connector_detect, 72 - .reset = drm_atomic_helper_connector_reset, 73 - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 74 - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 75 - }; 76 - 77 - const struct drm_connector_helper_funcs connector_helper_funcs = { 78 - .get_modes = pl111_connector_helper_get_modes, 79 - }; 80 - 81 - /* Walks the OF graph to find the panel node and then asks DRM to look 82 - * up the panel. 83 - */ 84 - static struct drm_panel *pl111_get_panel(struct device *dev) 85 - { 86 - struct device_node *endpoint, *panel_node; 87 - struct device_node *np = dev->of_node; 88 - struct drm_panel *panel; 89 - 90 - endpoint = of_graph_get_next_endpoint(np, NULL); 91 - if (!endpoint) { 92 - dev_err(dev, "no endpoint to fetch panel\n"); 93 - return NULL; 94 - } 95 - 96 - /* don't proceed if we have an endpoint but no panel_node tied to it */ 97 - panel_node = of_graph_get_remote_port_parent(endpoint); 98 - of_node_put(endpoint); 99 - if (!panel_node) { 100 - dev_err(dev, "no valid panel node\n"); 101 - return NULL; 102 - } 103 - 104 - panel = of_drm_find_panel(panel_node); 105 - of_node_put(panel_node); 106 - 107 - return panel; 108 - } 109 - 110 - int pl111_connector_init(struct drm_device *dev) 111 - { 112 - struct pl111_drm_dev_private *priv = dev->dev_private; 113 - struct pl111_drm_connector *pl111_connector = &priv->connector; 114 - struct drm_connector *connector = &pl111_connector->connector; 115 - 116 - drm_connector_init(dev, connector, &connector_funcs, 117 - DRM_MODE_CONNECTOR_DPI); 118 - drm_connector_helper_add(connector, &connector_helper_funcs); 119 - 120 - pl111_connector->panel = pl111_get_panel(dev->dev); 121 - if (pl111_connector->panel) 122 - drm_panel_attach(pl111_connector->panel, connector); 123 - 124 - return 0; 125 - } 126 -
+2 -11
drivers/gpu/drm/pl111/pl111_display.c
··· 21 21 #include <linux/of_graph.h> 22 22 23 23 #include <drm/drmP.h> 24 - #include <drm/drm_panel.h> 25 24 #include <drm/drm_gem_cma_helper.h> 26 25 #include <drm/drm_gem_framebuffer_helper.h> 27 26 #include <drm/drm_fb_cma_helper.h> ··· 93 94 struct pl111_drm_dev_private *priv = drm->dev_private; 94 95 const struct drm_display_mode *mode = &cstate->mode; 95 96 struct drm_framebuffer *fb = plane->state->fb; 96 - struct drm_connector *connector = &priv->connector.connector; 97 + struct drm_connector *connector = priv->connector; 97 98 u32 cntl; 98 99 u32 ppl, hsw, hfp, hbp; 99 100 u32 lpp, vsw, vfp, vbp; ··· 155 156 156 157 writel(0, priv->regs + CLCD_TIM3); 157 158 158 - drm_panel_prepare(priv->connector.panel); 159 - 160 159 /* Enable and Power Up */ 161 160 cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDPWR | CNTL_LCDVCOMP(1); 162 161 ··· 201 204 202 205 writel(cntl, priv->regs + CLCD_PL111_CNTL); 203 206 204 - drm_panel_enable(priv->connector.panel); 205 - 206 207 drm_crtc_vblank_on(crtc); 207 208 } 208 209 ··· 212 217 213 218 drm_crtc_vblank_off(crtc); 214 219 215 - drm_panel_disable(priv->connector.panel); 216 - 217 220 /* Disable and Power Down */ 218 221 writel(0, priv->regs + CLCD_PL111_CNTL); 219 - 220 - drm_panel_unprepare(priv->connector.panel); 221 222 222 223 clk_disable_unprepare(priv->clk); 223 224 } ··· 449 458 ret = drm_simple_display_pipe_init(drm, &priv->pipe, 450 459 &pl111_display_funcs, 451 460 formats, ARRAY_SIZE(formats), 452 - NULL, &priv->connector.connector); 461 + NULL, priv->connector); 453 462 if (ret) 454 463 return ret; 455 464
+7 -10
drivers/gpu/drm/pl111/pl111_drm.h
··· 21 21 22 22 #include <drm/drm_gem.h> 23 23 #include <drm/drm_simple_kms_helper.h> 24 + #include <drm/drm_connector.h> 25 + #include <drm/drm_encoder.h> 26 + #include <drm/drm_panel.h> 27 + #include <drm/drm_bridge.h> 24 28 #include <linux/clk-provider.h> 25 29 26 30 #define CLCD_IRQ_NEXTBASE_UPDATE BIT(2) 27 31 28 32 struct drm_minor; 29 33 30 - struct pl111_drm_connector { 31 - struct drm_connector connector; 32 - struct drm_panel *panel; 33 - }; 34 - 35 34 struct pl111_drm_dev_private { 36 35 struct drm_device *drm; 37 36 38 - struct pl111_drm_connector connector; 37 + struct drm_connector *connector; 38 + struct drm_panel *panel; 39 + struct drm_bridge *bridge; 39 40 struct drm_simple_display_pipe pipe; 40 41 struct drm_fbdev_cma *fbdev; 41 42 ··· 51 50 spinlock_t tim2_lock; 52 51 }; 53 52 54 - #define to_pl111_connector(x) \ 55 - container_of(x, struct pl111_drm_connector, connector) 56 - 57 53 int pl111_display_init(struct drm_device *dev); 58 54 int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc); 59 55 void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc); 60 56 irqreturn_t pl111_irq(int irq, void *data); 61 - int pl111_connector_init(struct drm_device *dev); 62 57 int pl111_debugfs_init(struct drm_minor *minor); 63 58 64 59 #endif /* _PL111_DRM_H_ */
+37 -18
drivers/gpu/drm/pl111/pl111_drv.c
··· 68 68 #include <drm/drm_gem_cma_helper.h> 69 69 #include <drm/drm_gem_framebuffer_helper.h> 70 70 #include <drm/drm_fb_cma_helper.h> 71 + #include <drm/drm_of.h> 72 + #include <drm/drm_bridge.h> 73 + #include <drm/drm_panel.h> 71 74 72 75 #include "pl111_drm.h" 73 76 ··· 86 83 { 87 84 struct drm_mode_config *mode_config; 88 85 struct pl111_drm_dev_private *priv = dev->dev_private; 86 + struct drm_panel *panel; 87 + struct drm_bridge *bridge; 89 88 int ret = 0; 90 89 91 90 drm_mode_config_init(dev); ··· 98 93 mode_config->min_height = 1; 99 94 mode_config->max_height = 768; 100 95 101 - ret = pl111_connector_init(dev); 102 - if (ret) { 103 - dev_err(dev->dev, "Failed to create pl111_drm_connector\n"); 104 - goto out_config; 105 - } 106 - 107 - /* Don't actually attach if we didn't find a drm_panel 108 - * attached to us. This will allow a kernel to include both 109 - * the fbdev pl111 driver and this one, and choose between 110 - * them based on which subsystem has support for the panel. 111 - */ 112 - if (!priv->connector.panel) { 113 - dev_info(dev->dev, 114 - "Disabling due to lack of DRM panel device.\n"); 115 - ret = -ENODEV; 116 - goto out_config; 96 + ret = drm_of_find_panel_or_bridge(dev->dev->of_node, 97 + 0, 0, &panel, &bridge); 98 + if (ret && ret != -ENODEV) 99 + return ret; 100 + if (panel) { 101 + bridge = drm_panel_bridge_add(panel, 102 + DRM_MODE_CONNECTOR_Unknown); 103 + if (IS_ERR(bridge)) { 104 + ret = PTR_ERR(bridge); 105 + goto out_config; 106 + } 107 + /* 108 + * TODO: when we are using a different bridge than a panel 109 + * (such as a dumb VGA connector) we need to devise a different 110 + * method to get the connector out of the bridge. 111 + */ 117 112 } 118 113 119 114 ret = pl111_display_init(dev); 120 115 if (ret != 0) { 121 116 dev_err(dev->dev, "Failed to init display\n"); 122 - goto out_config; 117 + goto out_bridge; 123 118 } 119 + 120 + ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, 121 + bridge); 122 + if (ret) 123 + return ret; 124 + 125 + priv->bridge = bridge; 126 + priv->panel = panel; 127 + priv->connector = panel->connector; 124 128 125 129 ret = drm_vblank_init(dev, 1); 126 130 if (ret != 0) { 127 131 dev_err(dev->dev, "Failed to init vblank\n"); 128 - goto out_config; 132 + goto out_bridge; 129 133 } 130 134 131 135 drm_mode_config_reset(dev); ··· 146 132 147 133 goto finish; 148 134 135 + out_bridge: 136 + if (panel) 137 + drm_panel_bridge_remove(bridge); 149 138 out_config: 150 139 drm_mode_config_cleanup(dev); 151 140 finish: ··· 253 236 drm_dev_unregister(drm); 254 237 if (priv->fbdev) 255 238 drm_fbdev_cma_fini(priv->fbdev); 239 + if (priv->panel) 240 + drm_panel_bridge_remove(priv->bridge); 256 241 drm_mode_config_cleanup(drm); 257 242 drm_dev_unref(drm); 258 243