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

Merge tag 'drm-vc4-next-2016-05-02' of https://github.com/anholt/linux into drm-next

This pull request brings in DPI panel support, gamma ramp support, and
render nodes for vc4.

* tag 'drm-vc4-next-2016-05-02' of https://github.com/anholt/linux:
drm/vc4: Add missing render node support
drm/vc4: Add support for gamma ramps.
drm/vc4: Fix NULL deref in HDMI init error path
drm/vc4: Add DPI driver
drm: Add an encoder and connector type enum for DPI.

+635 -1
+36
Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
··· 35 35 as an interrupt/status bit in the HDMI controller 36 36 itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt 37 37 38 + Required properties for DPI: 39 + - compatible: Should be "brcm,bcm2835-dpi" 40 + - reg: Physical base address and length of the registers 41 + - clocks: a) core: The core clock the unit runs on 42 + b) pixel: The pixel clock that feeds the pixelvalve 43 + - port: Port node with a single endpoint connecting to the panel 44 + device, as defined in [1] 45 + 38 46 Required properties for V3D: 39 47 - compatible: Should be "brcm,bcm2835-v3d" 40 48 - reg: Physical base address and length of the V3D's registers 41 49 - interrupts: The interrupt number 42 50 See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt 51 + 52 + [1] Documentation/devicetree/bindings/media/video-interfaces.txt 43 53 44 54 Example: 45 55 pixelvalve@7e807000 { ··· 76 66 clock-names = "pixel", "hdmi"; 77 67 }; 78 68 69 + dpi: dpi@7e208000 { 70 + compatible = "brcm,bcm2835-dpi"; 71 + reg = <0x7e208000 0x8c>; 72 + clocks = <&clocks BCM2835_CLOCK_VPU>, 73 + <&clocks BCM2835_CLOCK_DPI>; 74 + clock-names = "core", "pixel"; 75 + #address-cells = <1>; 76 + #size-cells = <0>; 77 + 78 + port { 79 + dpi_out: endpoint@0 { 80 + remote-endpoint = <&panel_in>; 81 + }; 82 + }; 83 + }; 84 + 79 85 v3d: v3d@7ec00000 { 80 86 compatible = "brcm,bcm2835-v3d"; 81 87 reg = <0x7ec00000 0x1000>; ··· 100 74 101 75 vc4: gpu { 102 76 compatible = "brcm,bcm2835-vc4"; 77 + }; 78 + 79 + panel: panel { 80 + compatible = "ontat,yx700wv03", "simple-panel"; 81 + 82 + port { 83 + panel_in: endpoint { 84 + remote-endpoint = <&dpi_out>; 85 + }; 86 + }; 103 87 };
+2
drivers/gpu/drm/drm_crtc.c
··· 168 168 { DRM_MODE_CONNECTOR_eDP, "eDP" }, 169 169 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 170 170 { DRM_MODE_CONNECTOR_DSI, "DSI" }, 171 + { DRM_MODE_CONNECTOR_DPI, "DPI" }, 171 172 }; 172 173 173 174 static const struct drm_prop_enum_list drm_encoder_enum_list[] = { ··· 180 179 { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 181 180 { DRM_MODE_ENCODER_DSI, "DSI" }, 182 181 { DRM_MODE_ENCODER_DPMST, "DP MST" }, 182 + { DRM_MODE_ENCODER_DPI, "DPI" }, 183 183 }; 184 184 185 185 static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
+1
drivers/gpu/drm/vc4/Kconfig
··· 5 5 select DRM_KMS_HELPER 6 6 select DRM_KMS_CMA_HELPER 7 7 select DRM_GEM_CMA_HELPER 8 + select DRM_PANEL 8 9 help 9 10 Choose this option if you have a system that has a Broadcom 10 11 VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835.
+1
drivers/gpu/drm/vc4/Makefile
··· 7 7 vc4_bo.o \ 8 8 vc4_crtc.o \ 9 9 vc4_drv.o \ 10 + vc4_dpi.o \ 10 11 vc4_kms.o \ 11 12 vc4_gem.o \ 12 13 vc4_hdmi.o \
+58
drivers/gpu/drm/vc4/vc4_crtc.c
··· 49 49 /* Which HVS channel we're using for our CRTC. */ 50 50 int channel; 51 51 52 + u8 lut_r[256]; 53 + u8 lut_g[256]; 54 + u8 lut_b[256]; 55 + 52 56 struct drm_pending_vblank_event *event; 53 57 }; 54 58 ··· 149 145 static void vc4_crtc_destroy(struct drm_crtc *crtc) 150 146 { 151 147 drm_crtc_cleanup(crtc); 148 + } 149 + 150 + static void 151 + vc4_crtc_lut_load(struct drm_crtc *crtc) 152 + { 153 + struct drm_device *dev = crtc->dev; 154 + struct vc4_dev *vc4 = to_vc4_dev(dev); 155 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 156 + u32 i; 157 + 158 + /* The LUT memory is laid out with each HVS channel in order, 159 + * each of which takes 256 writes for R, 256 for G, then 256 160 + * for B. 161 + */ 162 + HVS_WRITE(SCALER_GAMADDR, 163 + SCALER_GAMADDR_AUTOINC | 164 + (vc4_crtc->channel * 3 * crtc->gamma_size)); 165 + 166 + for (i = 0; i < crtc->gamma_size; i++) 167 + HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]); 168 + for (i = 0; i < crtc->gamma_size; i++) 169 + HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_g[i]); 170 + for (i = 0; i < crtc->gamma_size; i++) 171 + HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_b[i]); 172 + } 173 + 174 + static void 175 + vc4_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, 176 + uint32_t start, uint32_t size) 177 + { 178 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); 179 + u32 i; 180 + 181 + for (i = start; i < start + size; i++) { 182 + vc4_crtc->lut_r[i] = r[i] >> 8; 183 + vc4_crtc->lut_g[i] = g[i] >> 8; 184 + vc4_crtc->lut_b[i] = b[i] >> 8; 185 + } 186 + 187 + vc4_crtc_lut_load(crtc); 152 188 } 153 189 154 190 static u32 vc4_get_fifo_full_level(u32 format) ··· 304 260 305 261 HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), 306 262 SCALER_DISPBKGND_AUTOHS | 263 + SCALER_DISPBKGND_GAMMA | 307 264 (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); 265 + 266 + /* Reload the LUT, since the SRAMs would have been disabled if 267 + * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. 268 + */ 269 + vc4_crtc_lut_load(crtc); 308 270 309 271 if (debug_dump_regs) { 310 272 DRM_INFO("CRTC %d regs after:\n", drm_crtc_index(crtc)); ··· 663 613 .reset = drm_atomic_helper_crtc_reset, 664 614 .atomic_duplicate_state = vc4_crtc_duplicate_state, 665 615 .atomic_destroy_state = vc4_crtc_destroy_state, 616 + .gamma_set = vc4_crtc_gamma_set, 666 617 }; 667 618 668 619 static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { ··· 762 711 primary_plane->crtc = crtc; 763 712 vc4->crtc[drm_crtc_index(crtc)] = vc4_crtc; 764 713 vc4_crtc->channel = vc4_crtc->data->hvs_channel; 714 + drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); 765 715 766 716 /* Set up some arbitrary number of planes. We're not limited 767 717 * by a set number of physical registers, just the space in ··· 802 750 goto err_destroy_planes; 803 751 804 752 vc4_set_crtc_possible_masks(drm, crtc); 753 + 754 + for (i = 0; i < crtc->gamma_size; i++) { 755 + vc4_crtc->lut_r[i] = i; 756 + vc4_crtc->lut_g[i] = i; 757 + vc4_crtc->lut_b[i] = i; 758 + } 805 759 806 760 platform_set_drvdata(pdev, vc4_crtc); 807 761
+1
drivers/gpu/drm/vc4/vc4_debugfs.c
··· 17 17 18 18 static const struct drm_info_list vc4_debugfs_list[] = { 19 19 {"bo_stats", vc4_bo_stats_debugfs, 0}, 20 + {"dpi_regs", vc4_dpi_debugfs_regs, 0}, 20 21 {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, 21 22 {"hvs_regs", vc4_hvs_debugfs_regs, 0}, 22 23 {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
+520
drivers/gpu/drm/vc4/vc4_dpi.c
··· 1 + /* 2 + * Copyright (C) 2016 Broadcom Limited 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms of the GNU General Public License version 2 as published by 6 + * the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along with 14 + * this program. If not, see <http://www.gnu.org/licenses/>. 15 + */ 16 + 17 + /** 18 + * DOC: VC4 DPI module 19 + * 20 + * The VC4 DPI hardware supports MIPI DPI type 4 and Nokia ViSSI 21 + * signals, which are routed out to GPIO0-27 with the ALT2 function. 22 + */ 23 + 24 + #include "drm_atomic_helper.h" 25 + #include "drm_crtc_helper.h" 26 + #include "drm_edid.h" 27 + #include "drm_panel.h" 28 + #include "linux/clk.h" 29 + #include "linux/component.h" 30 + #include "linux/of_graph.h" 31 + #include "linux/of_platform.h" 32 + #include "vc4_drv.h" 33 + #include "vc4_regs.h" 34 + 35 + #define DPI_C 0x00 36 + # define DPI_OUTPUT_ENABLE_MODE BIT(16) 37 + 38 + /* The order field takes the incoming 24 bit RGB from the pixel valve 39 + * and shuffles the 3 channels. 40 + */ 41 + # define DPI_ORDER_MASK VC4_MASK(15, 14) 42 + # define DPI_ORDER_SHIFT 14 43 + # define DPI_ORDER_RGB 0 44 + # define DPI_ORDER_BGR 1 45 + # define DPI_ORDER_GRB 2 46 + # define DPI_ORDER_BRG 3 47 + 48 + /* The format field takes the ORDER-shuffled pixel valve data and 49 + * formats it onto the output lines. 50 + */ 51 + # define DPI_FORMAT_MASK VC4_MASK(13, 11) 52 + # define DPI_FORMAT_SHIFT 11 53 + /* This define is named in the hardware, but actually just outputs 0. */ 54 + # define DPI_FORMAT_9BIT_666_RGB 0 55 + /* Outputs 00000000rrrrrggggggbbbbb */ 56 + # define DPI_FORMAT_16BIT_565_RGB_1 1 57 + /* Outputs 000rrrrr00gggggg000bbbbb */ 58 + # define DPI_FORMAT_16BIT_565_RGB_2 2 59 + /* Outputs 00rrrrr000gggggg00bbbbb0 */ 60 + # define DPI_FORMAT_16BIT_565_RGB_3 3 61 + /* Outputs 000000rrrrrrggggggbbbbbb */ 62 + # define DPI_FORMAT_18BIT_666_RGB_1 4 63 + /* Outputs 00rrrrrr00gggggg00bbbbbb */ 64 + # define DPI_FORMAT_18BIT_666_RGB_2 5 65 + /* Outputs rrrrrrrrggggggggbbbbbbbb */ 66 + # define DPI_FORMAT_24BIT_888_RGB 6 67 + 68 + /* Reverses the polarity of the corresponding signal */ 69 + # define DPI_PIXEL_CLK_INVERT BIT(10) 70 + # define DPI_HSYNC_INVERT BIT(9) 71 + # define DPI_VSYNC_INVERT BIT(8) 72 + # define DPI_OUTPUT_ENABLE_INVERT BIT(7) 73 + 74 + /* Outputs the signal the falling clock edge instead of rising. */ 75 + # define DPI_HSYNC_NEGATE BIT(6) 76 + # define DPI_VSYNC_NEGATE BIT(5) 77 + # define DPI_OUTPUT_ENABLE_NEGATE BIT(4) 78 + 79 + /* Disables the signal */ 80 + # define DPI_HSYNC_DISABLE BIT(3) 81 + # define DPI_VSYNC_DISABLE BIT(2) 82 + # define DPI_OUTPUT_ENABLE_DISABLE BIT(1) 83 + 84 + /* Power gate to the device, full reset at 0 -> 1 transition */ 85 + # define DPI_ENABLE BIT(0) 86 + 87 + /* All other registers besides DPI_C return the ID */ 88 + #define DPI_ID 0x04 89 + # define DPI_ID_VALUE 0x00647069 90 + 91 + /* General DPI hardware state. */ 92 + struct vc4_dpi { 93 + struct platform_device *pdev; 94 + 95 + struct drm_encoder *encoder; 96 + struct drm_connector *connector; 97 + struct drm_panel *panel; 98 + 99 + void __iomem *regs; 100 + 101 + struct clk *pixel_clock; 102 + struct clk *core_clock; 103 + }; 104 + 105 + #define DPI_READ(offset) readl(dpi->regs + (offset)) 106 + #define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset)) 107 + 108 + /* VC4 DPI encoder KMS struct */ 109 + struct vc4_dpi_encoder { 110 + struct vc4_encoder base; 111 + struct vc4_dpi *dpi; 112 + }; 113 + 114 + static inline struct vc4_dpi_encoder * 115 + to_vc4_dpi_encoder(struct drm_encoder *encoder) 116 + { 117 + return container_of(encoder, struct vc4_dpi_encoder, base.base); 118 + } 119 + 120 + /* VC4 DPI connector KMS struct */ 121 + struct vc4_dpi_connector { 122 + struct drm_connector base; 123 + struct vc4_dpi *dpi; 124 + 125 + /* Since the connector is attached to just the one encoder, 126 + * this is the reference to it so we can do the best_encoder() 127 + * hook. 128 + */ 129 + struct drm_encoder *encoder; 130 + }; 131 + 132 + static inline struct vc4_dpi_connector * 133 + to_vc4_dpi_connector(struct drm_connector *connector) 134 + { 135 + return container_of(connector, struct vc4_dpi_connector, base); 136 + } 137 + 138 + #define DPI_REG(reg) { reg, #reg } 139 + static const struct { 140 + u32 reg; 141 + const char *name; 142 + } dpi_regs[] = { 143 + DPI_REG(DPI_C), 144 + DPI_REG(DPI_ID), 145 + }; 146 + 147 + static void vc4_dpi_dump_regs(struct vc4_dpi *dpi) 148 + { 149 + int i; 150 + 151 + for (i = 0; i < ARRAY_SIZE(dpi_regs); i++) { 152 + DRM_INFO("0x%04x (%s): 0x%08x\n", 153 + dpi_regs[i].reg, dpi_regs[i].name, 154 + DPI_READ(dpi_regs[i].reg)); 155 + } 156 + } 157 + 158 + #ifdef CONFIG_DEBUG_FS 159 + int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused) 160 + { 161 + struct drm_info_node *node = (struct drm_info_node *)m->private; 162 + struct drm_device *dev = node->minor->dev; 163 + struct vc4_dev *vc4 = to_vc4_dev(dev); 164 + struct vc4_dpi *dpi = vc4->dpi; 165 + int i; 166 + 167 + if (!dpi) 168 + return 0; 169 + 170 + for (i = 0; i < ARRAY_SIZE(dpi_regs); i++) { 171 + seq_printf(m, "%s (0x%04x): 0x%08x\n", 172 + dpi_regs[i].name, dpi_regs[i].reg, 173 + DPI_READ(dpi_regs[i].reg)); 174 + } 175 + 176 + return 0; 177 + } 178 + #endif 179 + 180 + static enum drm_connector_status 181 + vc4_dpi_connector_detect(struct drm_connector *connector, bool force) 182 + { 183 + struct vc4_dpi_connector *vc4_connector = 184 + to_vc4_dpi_connector(connector); 185 + struct vc4_dpi *dpi = vc4_connector->dpi; 186 + 187 + if (dpi->panel) 188 + return connector_status_connected; 189 + else 190 + return connector_status_disconnected; 191 + } 192 + 193 + static void vc4_dpi_connector_destroy(struct drm_connector *connector) 194 + { 195 + drm_connector_unregister(connector); 196 + drm_connector_cleanup(connector); 197 + } 198 + 199 + static int vc4_dpi_connector_get_modes(struct drm_connector *connector) 200 + { 201 + struct vc4_dpi_connector *vc4_connector = 202 + to_vc4_dpi_connector(connector); 203 + struct vc4_dpi *dpi = vc4_connector->dpi; 204 + 205 + if (dpi->panel) 206 + return drm_panel_get_modes(dpi->panel); 207 + 208 + return 0; 209 + } 210 + 211 + static struct drm_encoder * 212 + vc4_dpi_connector_best_encoder(struct drm_connector *connector) 213 + { 214 + struct vc4_dpi_connector *dpi_connector = 215 + to_vc4_dpi_connector(connector); 216 + return dpi_connector->encoder; 217 + } 218 + 219 + static const struct drm_connector_funcs vc4_dpi_connector_funcs = { 220 + .dpms = drm_atomic_helper_connector_dpms, 221 + .detect = vc4_dpi_connector_detect, 222 + .fill_modes = drm_helper_probe_single_connector_modes, 223 + .destroy = vc4_dpi_connector_destroy, 224 + .reset = drm_atomic_helper_connector_reset, 225 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 226 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 227 + }; 228 + 229 + static const struct drm_connector_helper_funcs vc4_dpi_connector_helper_funcs = { 230 + .get_modes = vc4_dpi_connector_get_modes, 231 + .best_encoder = vc4_dpi_connector_best_encoder, 232 + }; 233 + 234 + static struct drm_connector *vc4_dpi_connector_init(struct drm_device *dev, 235 + struct vc4_dpi *dpi) 236 + { 237 + struct drm_connector *connector = NULL; 238 + struct vc4_dpi_connector *dpi_connector; 239 + int ret = 0; 240 + 241 + dpi_connector = devm_kzalloc(dev->dev, sizeof(*dpi_connector), 242 + GFP_KERNEL); 243 + if (!dpi_connector) { 244 + ret = -ENOMEM; 245 + goto fail; 246 + } 247 + connector = &dpi_connector->base; 248 + 249 + dpi_connector->encoder = dpi->encoder; 250 + dpi_connector->dpi = dpi; 251 + 252 + drm_connector_init(dev, connector, &vc4_dpi_connector_funcs, 253 + DRM_MODE_CONNECTOR_DPI); 254 + drm_connector_helper_add(connector, &vc4_dpi_connector_helper_funcs); 255 + 256 + connector->polled = 0; 257 + connector->interlace_allowed = 0; 258 + connector->doublescan_allowed = 0; 259 + 260 + drm_mode_connector_attach_encoder(connector, dpi->encoder); 261 + 262 + return connector; 263 + 264 + fail: 265 + if (connector) 266 + vc4_dpi_connector_destroy(connector); 267 + 268 + return ERR_PTR(ret); 269 + } 270 + 271 + static const struct drm_encoder_funcs vc4_dpi_encoder_funcs = { 272 + .destroy = drm_encoder_cleanup, 273 + }; 274 + 275 + static void vc4_dpi_encoder_disable(struct drm_encoder *encoder) 276 + { 277 + struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); 278 + struct vc4_dpi *dpi = vc4_encoder->dpi; 279 + 280 + drm_panel_disable(dpi->panel); 281 + 282 + clk_disable_unprepare(dpi->pixel_clock); 283 + 284 + drm_panel_unprepare(dpi->panel); 285 + } 286 + 287 + static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) 288 + { 289 + struct drm_display_mode *mode = &encoder->crtc->mode; 290 + struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); 291 + struct vc4_dpi *dpi = vc4_encoder->dpi; 292 + u32 dpi_c = DPI_ENABLE | DPI_OUTPUT_ENABLE_MODE; 293 + int ret; 294 + 295 + ret = drm_panel_prepare(dpi->panel); 296 + if (ret) { 297 + DRM_ERROR("Panel failed to prepare\n"); 298 + return; 299 + } 300 + 301 + if (dpi->connector->display_info.num_bus_formats) { 302 + u32 bus_format = dpi->connector->display_info.bus_formats[0]; 303 + 304 + switch (bus_format) { 305 + case MEDIA_BUS_FMT_RGB888_1X24: 306 + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, 307 + DPI_FORMAT); 308 + break; 309 + case MEDIA_BUS_FMT_BGR888_1X24: 310 + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, 311 + DPI_FORMAT); 312 + dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER); 313 + break; 314 + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 315 + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, 316 + DPI_FORMAT); 317 + break; 318 + case MEDIA_BUS_FMT_RGB666_1X18: 319 + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, 320 + DPI_FORMAT); 321 + break; 322 + case MEDIA_BUS_FMT_RGB565_1X16: 323 + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3, 324 + DPI_FORMAT); 325 + break; 326 + default: 327 + DRM_ERROR("Unknown media bus format %d\n", bus_format); 328 + break; 329 + } 330 + } 331 + 332 + if (mode->flags & DRM_MODE_FLAG_NHSYNC) 333 + dpi_c |= DPI_HSYNC_INVERT; 334 + else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) 335 + dpi_c |= DPI_HSYNC_DISABLE; 336 + 337 + if (mode->flags & DRM_MODE_FLAG_NVSYNC) 338 + dpi_c |= DPI_VSYNC_INVERT; 339 + else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) 340 + dpi_c |= DPI_VSYNC_DISABLE; 341 + 342 + DPI_WRITE(DPI_C, dpi_c); 343 + 344 + ret = clk_set_rate(dpi->pixel_clock, mode->clock * 1000); 345 + if (ret) 346 + DRM_ERROR("Failed to set clock rate: %d\n", ret); 347 + 348 + ret = clk_prepare_enable(dpi->pixel_clock); 349 + if (ret) 350 + DRM_ERROR("Failed to set clock rate: %d\n", ret); 351 + 352 + ret = drm_panel_enable(dpi->panel); 353 + if (ret) { 354 + DRM_ERROR("Panel failed to enable\n"); 355 + drm_panel_unprepare(dpi->panel); 356 + return; 357 + } 358 + } 359 + 360 + static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = { 361 + .disable = vc4_dpi_encoder_disable, 362 + .enable = vc4_dpi_encoder_enable, 363 + }; 364 + 365 + static const struct of_device_id vc4_dpi_dt_match[] = { 366 + { .compatible = "brcm,bcm2835-dpi", .data = NULL }, 367 + {} 368 + }; 369 + 370 + /* Walks the OF graph to find the panel node and then asks DRM to look 371 + * up the panel. 372 + */ 373 + static struct drm_panel *vc4_dpi_get_panel(struct device *dev) 374 + { 375 + struct device_node *endpoint, *panel_node; 376 + struct device_node *np = dev->of_node; 377 + struct drm_panel *panel; 378 + 379 + endpoint = of_graph_get_next_endpoint(np, NULL); 380 + if (!endpoint) { 381 + dev_err(dev, "no endpoint to fetch DPI panel\n"); 382 + return NULL; 383 + } 384 + 385 + /* don't proceed if we have an endpoint but no panel_node tied to it */ 386 + panel_node = of_graph_get_remote_port_parent(endpoint); 387 + of_node_put(endpoint); 388 + if (!panel_node) { 389 + dev_err(dev, "no valid panel node\n"); 390 + return NULL; 391 + } 392 + 393 + panel = of_drm_find_panel(panel_node); 394 + of_node_put(panel_node); 395 + 396 + return panel; 397 + } 398 + 399 + static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) 400 + { 401 + struct platform_device *pdev = to_platform_device(dev); 402 + struct drm_device *drm = dev_get_drvdata(master); 403 + struct vc4_dev *vc4 = to_vc4_dev(drm); 404 + struct vc4_dpi *dpi; 405 + struct vc4_dpi_encoder *vc4_dpi_encoder; 406 + int ret; 407 + 408 + dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); 409 + if (!dpi) 410 + return -ENOMEM; 411 + 412 + vc4_dpi_encoder = devm_kzalloc(dev, sizeof(*vc4_dpi_encoder), 413 + GFP_KERNEL); 414 + if (!vc4_dpi_encoder) 415 + return -ENOMEM; 416 + vc4_dpi_encoder->base.type = VC4_ENCODER_TYPE_DPI; 417 + vc4_dpi_encoder->dpi = dpi; 418 + dpi->encoder = &vc4_dpi_encoder->base.base; 419 + 420 + dpi->pdev = pdev; 421 + dpi->regs = vc4_ioremap_regs(pdev, 0); 422 + if (IS_ERR(dpi->regs)) 423 + return PTR_ERR(dpi->regs); 424 + 425 + vc4_dpi_dump_regs(dpi); 426 + 427 + if (DPI_READ(DPI_ID) != DPI_ID_VALUE) { 428 + dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", 429 + DPI_READ(DPI_ID), DPI_ID_VALUE); 430 + return -ENODEV; 431 + } 432 + 433 + dpi->core_clock = devm_clk_get(dev, "core"); 434 + if (IS_ERR(dpi->core_clock)) { 435 + ret = PTR_ERR(dpi->core_clock); 436 + if (ret != -EPROBE_DEFER) 437 + DRM_ERROR("Failed to get core clock: %d\n", ret); 438 + return ret; 439 + } 440 + dpi->pixel_clock = devm_clk_get(dev, "pixel"); 441 + if (IS_ERR(dpi->pixel_clock)) { 442 + ret = PTR_ERR(dpi->pixel_clock); 443 + if (ret != -EPROBE_DEFER) 444 + DRM_ERROR("Failed to get pixel clock: %d\n", ret); 445 + return ret; 446 + } 447 + 448 + ret = clk_prepare_enable(dpi->core_clock); 449 + if (ret) 450 + DRM_ERROR("Failed to turn on core clock: %d\n", ret); 451 + 452 + dpi->panel = vc4_dpi_get_panel(dev); 453 + 454 + drm_encoder_init(drm, dpi->encoder, &vc4_dpi_encoder_funcs, 455 + DRM_MODE_ENCODER_DPI, NULL); 456 + drm_encoder_helper_add(dpi->encoder, &vc4_dpi_encoder_helper_funcs); 457 + 458 + dpi->connector = vc4_dpi_connector_init(drm, dpi); 459 + if (IS_ERR(dpi->connector)) { 460 + ret = PTR_ERR(dpi->connector); 461 + goto err_destroy_encoder; 462 + } 463 + 464 + if (dpi->panel) 465 + drm_panel_attach(dpi->panel, dpi->connector); 466 + 467 + dev_set_drvdata(dev, dpi); 468 + 469 + vc4->dpi = dpi; 470 + 471 + return 0; 472 + 473 + err_destroy_encoder: 474 + drm_encoder_cleanup(dpi->encoder); 475 + clk_disable_unprepare(dpi->core_clock); 476 + return ret; 477 + } 478 + 479 + static void vc4_dpi_unbind(struct device *dev, struct device *master, 480 + void *data) 481 + { 482 + struct drm_device *drm = dev_get_drvdata(master); 483 + struct vc4_dev *vc4 = to_vc4_dev(drm); 484 + struct vc4_dpi *dpi = dev_get_drvdata(dev); 485 + 486 + if (dpi->panel) 487 + drm_panel_detach(dpi->panel); 488 + 489 + vc4_dpi_connector_destroy(dpi->connector); 490 + drm_encoder_cleanup(dpi->encoder); 491 + 492 + clk_disable_unprepare(dpi->core_clock); 493 + 494 + vc4->dpi = NULL; 495 + } 496 + 497 + static const struct component_ops vc4_dpi_ops = { 498 + .bind = vc4_dpi_bind, 499 + .unbind = vc4_dpi_unbind, 500 + }; 501 + 502 + static int vc4_dpi_dev_probe(struct platform_device *pdev) 503 + { 504 + return component_add(&pdev->dev, &vc4_dpi_ops); 505 + } 506 + 507 + static int vc4_dpi_dev_remove(struct platform_device *pdev) 508 + { 509 + component_del(&pdev->dev, &vc4_dpi_ops); 510 + return 0; 511 + } 512 + 513 + struct platform_driver vc4_dpi_driver = { 514 + .probe = vc4_dpi_dev_probe, 515 + .remove = vc4_dpi_dev_remove, 516 + .driver = { 517 + .name = "vc4_dpi", 518 + .of_match_table = vc4_dpi_dt_match, 519 + }, 520 + };
+2
drivers/gpu/drm/vc4/vc4_drv.c
··· 81 81 DRIVER_ATOMIC | 82 82 DRIVER_GEM | 83 83 DRIVER_HAVE_IRQ | 84 + DRIVER_RENDER | 84 85 DRIVER_PRIME), 85 86 .lastclose = vc4_lastclose, 86 87 .irq_handler = vc4_irq, ··· 238 237 239 238 static struct platform_driver *const component_drivers[] = { 240 239 &vc4_hdmi_driver, 240 + &vc4_dpi_driver, 241 241 &vc4_crtc_driver, 242 242 &vc4_hvs_driver, 243 243 &vc4_v3d_driver,
+5
drivers/gpu/drm/vc4/vc4_drv.h
··· 16 16 struct vc4_hvs *hvs; 17 17 struct vc4_crtc *crtc[3]; 18 18 struct vc4_v3d *v3d; 19 + struct vc4_dpi *dpi; 19 20 20 21 struct drm_fbdev_cma *fbdev; 21 22 ··· 422 421 423 422 /* vc4_drv.c */ 424 423 void __iomem *vc4_ioremap_regs(struct platform_device *dev, int index); 424 + 425 + /* vc4_dpi.c */ 426 + extern struct platform_driver vc4_dpi_driver; 427 + int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused); 425 428 426 429 /* vc4_gem.c */ 427 430 void vc4_gem_init(struct drm_device *dev);
+1 -1
drivers/gpu/drm/vc4/vc4_hdmi.c
··· 573 573 err_unprepare_pix: 574 574 clk_disable_unprepare(hdmi->pixel_clock); 575 575 err_put_i2c: 576 - put_device(&vc4->hdmi->ddc->dev); 576 + put_device(&hdmi->ddc->dev); 577 577 578 578 return ret; 579 579 }
+6
drivers/gpu/drm/vc4/vc4_regs.h
··· 390 390 #define SCALER_DISPBASE2 0x0000006c 391 391 #define SCALER_DISPALPHA2 0x00000070 392 392 #define SCALER_GAMADDR 0x00000078 393 + # define SCALER_GAMADDR_AUTOINC BIT(31) 394 + /* Enables all gamma ramp SRAMs, not just those of CRTCs with gamma 395 + * enabled. 396 + */ 397 + # define SCALER_GAMADDR_SRAMENB BIT(30) 398 + 393 399 #define SCALER_GAMDATA 0x000000e0 394 400 #define SCALER_DLIST_START 0x00002000 395 401 #define SCALER_DLIST_SIZE 0x00004000
+2
include/uapi/drm/drm_mode.h
··· 202 202 #define DRM_MODE_ENCODER_VIRTUAL 5 203 203 #define DRM_MODE_ENCODER_DSI 6 204 204 #define DRM_MODE_ENCODER_DPMST 7 205 + #define DRM_MODE_ENCODER_DPI 8 205 206 206 207 struct drm_mode_get_encoder { 207 208 __u32 encoder_id; ··· 242 241 #define DRM_MODE_CONNECTOR_eDP 14 243 242 #define DRM_MODE_CONNECTOR_VIRTUAL 15 244 243 #define DRM_MODE_CONNECTOR_DSI 16 244 + #define DRM_MODE_CONNECTOR_DPI 17 245 245 246 246 struct drm_mode_get_connector { 247 247