"Das U-Boot" Source Tree
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

video: rockchip: Add RK3126 LVDS and VOP support

From Rockchip's u-boot tree

+510 -6
+4 -1
drivers/video/rockchip/Makefile
··· 5 5 6 6 ifdef CONFIG_VIDEO_ROCKCHIP 7 7 obj-y += rk_vop.o 8 + obj-$(CONFIG_ROCKCHIP_RK3128) += rk3126_vop.o 8 9 obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288_vop.o 9 10 obj-$(CONFIG_ROCKCHIP_RK3328) += rk3328_vop.o 10 11 obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399_vop.o 11 12 obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o 12 - obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o 13 + obj-lvds-$(CONFIG_ROCKCHIP_RK3288) += rk_lvds.o 14 + obj-lvds-$(CONFIG_ROCKCHIP_RK3128) += rk3126_lvds.o 15 + obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += $(obj-lvds-y) 13 16 obj-hdmi-$(CONFIG_ROCKCHIP_RK3288) += rk3288_hdmi.o 14 17 obj-hdmi-$(CONFIG_ROCKCHIP_RK3328) += rk3328_hdmi.o 15 18 obj-hdmi-$(CONFIG_ROCKCHIP_RK3399) += rk3399_hdmi.o
+274
drivers/video/rockchip/rk3126_lvds.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2008-2014 Rockchip Electronics 4 + */ 5 + 6 + #include <display.h> 7 + #include <dm.h> 8 + #include <log.h> 9 + #include <panel.h> 10 + #include <regmap.h> 11 + #include <syscon.h> 12 + #include <generic-phy.h> 13 + #include <asm/global_data.h> 14 + #include <asm/io.h> 15 + #include <asm/arch-rockchip/clock.h> 16 + #include <asm/arch-rockchip/hardware.h> 17 + #include <linux/err.h> 18 + 19 + DECLARE_GLOBAL_DATA_PTR; 20 + 21 + /* GRF_LVDS_CON0 offset within GRF */ 22 + #define RK3126_GRF_LVDS_CON0 0x150 23 + 24 + /* 25 + * GRF_LVDS_CON0 bits for rk312x (from vendor rk312x_lcdc.h) 26 + * Uses write-mask: upper 16 bits = mask, lower 16 bits = value 27 + */ 28 + #define LVDS_CON0_DATA_SEL(x) (((x) & 1) << 0) /* 0=from LCDC */ 29 + #define LVDS_CON0_OUTPUT_FORMAT(x) (((x) & 3) << 1) /* format */ 30 + #define LVDS_CON0_MSBSEL BIT(3) /* 1=MSB at D7 */ 31 + #define LVDS_CON0_LVDSMODE_EN BIT(6) /* LVDS mode enable */ 32 + #define LVDS_CON0_TTL_EN BIT(7) /* TTL mode enable */ 33 + #define LVDS_CON0_LANE0_EN BIT(8) /* MIPI PHY lane0 */ 34 + #define LVDS_CON0_FORCEX_EN BIT(9) /* DPI force enable */ 35 + 36 + /* LVDS output format values */ 37 + #define LVDS_FMT_8BIT_1 0 38 + #define LVDS_FMT_8BIT_2 1 39 + #define LVDS_FMT_8BIT_3 2 /* JEIDA-24 */ 40 + #define LVDS_FMT_6BIT 3 41 + 42 + struct rk3126_lvds_priv { 43 + void __iomem *grf; 44 + struct udevice *panel; 45 + struct phy phy; 46 + const char *data_mapping; 47 + int data_width; 48 + const char *output; 49 + }; 50 + 51 + static int rk3126_lvds_read_timing(struct udevice *dev, 52 + struct display_timing *timing) 53 + { 54 + struct rk3126_lvds_priv *priv = dev_get_priv(dev); 55 + ofnode panel_node, timing_node; 56 + 57 + panel_node = dev_ofnode(priv->panel); 58 + 59 + /* Try display-timings first, then panel-timing */ 60 + if (!ofnode_decode_display_timing(panel_node, 0, timing)) 61 + return 0; 62 + 63 + timing_node = ofnode_find_subnode(panel_node, "panel-timing"); 64 + if (!ofnode_valid(timing_node)) { 65 + debug("%s: no panel-timing subnode\n", __func__); 66 + return -EINVAL; 67 + } 68 + 69 + memset(timing, 0, sizeof(*timing)); 70 + 71 + timing->hback_porch.typ = ofnode_read_u32_default(timing_node, 72 + "hback-porch", 0); 73 + timing->hfront_porch.typ = ofnode_read_u32_default(timing_node, 74 + "hfront-porch", 0); 75 + timing->hactive.typ = ofnode_read_u32_default(timing_node, 76 + "hactive", 0); 77 + timing->hsync_len.typ = ofnode_read_u32_default(timing_node, 78 + "hsync-len", 0); 79 + timing->vback_porch.typ = ofnode_read_u32_default(timing_node, 80 + "vback-porch", 0); 81 + timing->vfront_porch.typ = ofnode_read_u32_default(timing_node, 82 + "vfront-porch", 0); 83 + timing->vactive.typ = ofnode_read_u32_default(timing_node, 84 + "vactive", 0); 85 + timing->vsync_len.typ = ofnode_read_u32_default(timing_node, 86 + "vsync-len", 0); 87 + timing->pixelclock.typ = ofnode_read_u32_default(timing_node, 88 + "clock-frequency", 0); 89 + 90 + timing->flags = 0; 91 + if (ofnode_read_u32_default(timing_node, "hsync-active", 0)) 92 + timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH; 93 + if (ofnode_read_u32_default(timing_node, "vsync-active", 0)) 94 + timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH; 95 + if (ofnode_read_u32_default(timing_node, "de-active", 0)) 96 + timing->flags |= DISPLAY_FLAGS_DE_HIGH; 97 + if (ofnode_read_u32_default(timing_node, "pixelclk-active", 0)) 98 + timing->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; 99 + 100 + return 0; 101 + } 102 + 103 + static int rk3126_lvds_enable(struct udevice *dev, int panel_bpp, 104 + const struct display_timing *edid) 105 + { 106 + struct rk3126_lvds_priv *priv = dev_get_priv(dev); 107 + u32 val; 108 + int ret; 109 + 110 + /* 111 + * Configure GRF_LVDS_CON0 per vendor rk312x_lcdc.h. 112 + * LVDS_8BIT_3 (=2) is the JEIDA-24 format. 113 + */ 114 + val = LVDS_CON0_LVDSMODE_EN | 115 + LVDS_CON0_DATA_SEL(0) | 116 + LVDS_CON0_OUTPUT_FORMAT(LVDS_FMT_8BIT_3) | 117 + LVDS_CON0_MSBSEL | 118 + LVDS_CON0_LANE0_EN | 119 + LVDS_CON0_FORCEX_EN; 120 + 121 + /* Write with mask in upper 16 bits */ 122 + writel(val | (0xffff << 16), priv->grf + RK3126_GRF_LVDS_CON0); 123 + 124 + /* Set PHY mode to LVDS and power on */ 125 + ret = generic_phy_set_mode(&priv->phy, PHY_MODE_LVDS, 0); 126 + if (ret) 127 + return ret; 128 + 129 + ret = generic_phy_power_on(&priv->phy); 130 + if (ret) 131 + return ret; 132 + 133 + /* 134 + * Drive panel enable GPIO and backlight directly. 135 + * panel enable-gpios = GPIO0_C0 (pin 24) 136 + * backlight enable-gpios = GPIO0_C3 (pin 27) 137 + * PWM0 at 0x20050000, period=0x61a8 (25000ns = 40kHz) 138 + */ 139 + #define GPIO0_BASE 0x2007c000 140 + #define GPIO_SWPORTA_DR 0x00 141 + #define GPIO_SWPORTA_DDR 0x04 142 + #define PWM0_BASE 0x20050000 143 + #define PWM_CNT 0x00 144 + #define PWM_PERIOD 0x04 145 + #define PWM_DUTY 0x08 146 + #define PWM_CTRL 0x0c 147 + { 148 + void __iomem *gpio0 = (void __iomem *)GPIO0_BASE; 149 + void __iomem *pwm0 = (void __iomem *)PWM0_BASE; 150 + u32 val; 151 + 152 + /* Set GPIO0_C0 (pin 24) and GPIO0_C3 (pin 27) as output high */ 153 + val = readl(gpio0 + GPIO_SWPORTA_DDR); 154 + val |= BIT(24) | BIT(27); 155 + writel(val, gpio0 + GPIO_SWPORTA_DDR); 156 + 157 + val = readl(gpio0 + GPIO_SWPORTA_DR); 158 + val |= BIT(24) | BIT(27); 159 + writel(val, gpio0 + GPIO_SWPORTA_DR); 160 + 161 + /* Configure PWM0: period=25000, duty=12500 (50%), enable */ 162 + writel(25000, pwm0 + PWM_PERIOD); 163 + writel(12500, pwm0 + PWM_DUTY); 164 + writel(BIT(0) | BIT(3), pwm0 + PWM_CTRL); /* enable, continuous */ 165 + } 166 + 167 + return 0; 168 + } 169 + 170 + static int rk3126_lvds_of_to_plat(struct udevice *dev) 171 + { 172 + struct rk3126_lvds_priv *priv = dev_get_priv(dev); 173 + 174 + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 175 + if (IS_ERR(priv->grf)) 176 + return PTR_ERR(priv->grf); 177 + 178 + priv->data_mapping = dev_read_string(dev, "rockchip,data-mapping"); 179 + priv->data_width = dev_read_u32_default(dev, "rockchip,data-width", 24); 180 + priv->output = dev_read_string(dev, "rockchip,output"); 181 + 182 + return 0; 183 + } 184 + 185 + static int rk3126_lvds_probe(struct udevice *dev) 186 + { 187 + struct rk3126_lvds_priv *priv = dev_get_priv(dev); 188 + int ret; 189 + 190 + /* Find the panel via port@1 endpoint */ 191 + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel", 192 + &priv->panel); 193 + if (ret) { 194 + /* 195 + * No rockchip,panel phandle - try to find panel via 196 + * port@1 remote-endpoint. Walk: ports/port@1/endpoint@0 197 + * -> remote-endpoint -> parent -> parent -> panel device. 198 + */ 199 + ofnode ports, port, ep; 200 + u32 phandle; 201 + ofnode remote, panel_node; 202 + 203 + ports = dev_read_subnode(dev, "ports"); 204 + if (!ofnode_valid(ports)) { 205 + debug("%s: no ports subnode\n", __func__); 206 + return -EINVAL; 207 + } 208 + 209 + port = ofnode_find_subnode(ports, "port@1"); 210 + if (!ofnode_valid(port)) { 211 + debug("%s: no port@1\n", __func__); 212 + return -EINVAL; 213 + } 214 + 215 + /* Find first endpoint */ 216 + ep = ofnode_first_subnode(port); 217 + if (!ofnode_valid(ep)) { 218 + debug("%s: no endpoint in port@1\n", __func__); 219 + return -EINVAL; 220 + } 221 + 222 + ret = ofnode_read_u32(ep, "remote-endpoint", &phandle); 223 + if (ret) { 224 + debug("%s: no remote-endpoint\n", __func__); 225 + return -EINVAL; 226 + } 227 + 228 + remote = ofnode_get_by_phandle(phandle); 229 + if (!ofnode_valid(remote)) { 230 + debug("%s: invalid remote phandle\n", __func__); 231 + return -EINVAL; 232 + } 233 + 234 + /* Walk up from the endpoint to the panel node */ 235 + panel_node = ofnode_get_parent(remote); /* port */ 236 + panel_node = ofnode_get_parent(panel_node); /* panel */ 237 + 238 + ret = uclass_get_device_by_ofnode(UCLASS_PANEL, panel_node, 239 + &priv->panel); 240 + if (ret) { 241 + debug("%s: cannot find panel: %d\n", __func__, ret); 242 + return ret; 243 + } 244 + } 245 + 246 + /* Get PHY */ 247 + ret = generic_phy_get_by_name(dev, "dphy", &priv->phy); 248 + if (ret) { 249 + debug("%s: cannot get dphy: %d\n", __func__, ret); 250 + return ret; 251 + } 252 + 253 + return 0; 254 + } 255 + 256 + static const struct dm_display_ops rk3126_lvds_ops = { 257 + .read_timing = rk3126_lvds_read_timing, 258 + .enable = rk3126_lvds_enable, 259 + }; 260 + 261 + static const struct udevice_id rk3126_lvds_ids[] = { 262 + { .compatible = "rockchip,rk3126-lvds" }, 263 + { } 264 + }; 265 + 266 + U_BOOT_DRIVER(rk3126_lvds) = { 267 + .name = "rk3126_lvds", 268 + .id = UCLASS_DISPLAY, 269 + .of_match = rk3126_lvds_ids, 270 + .ops = &rk3126_lvds_ops, 271 + .of_to_plat = rk3126_lvds_of_to_plat, 272 + .probe = rk3126_lvds_probe, 273 + .priv_auto = sizeof(struct rk3126_lvds_priv), 274 + };
+206
drivers/video/rockchip/rk3126_vop.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2008-2014 Rockchip Electronics 4 + */ 5 + 6 + #include <clk.h> 7 + #include <display.h> 8 + #include <dm.h> 9 + #include <linux/delay.h> 10 + #include <log.h> 11 + #include <reset.h> 12 + #include <video.h> 13 + #include <asm/global_data.h> 14 + #include <asm/io.h> 15 + #include <asm/arch-rockchip/vop_rk3288.h> 16 + #include "rk_vop.h" 17 + 18 + DECLARE_GLOBAL_DATA_PTR; 19 + 20 + enum rk3126_vop_pol { 21 + HSYNC_POSITIVE = 0, 22 + VSYNC_POSITIVE = 1, 23 + DEN_NEGATIVE = 2, 24 + DCLK_INVERT = 3 25 + }; 26 + 27 + /* 28 + * RK312x VOP register offsets - confirmed against vendor register dump. 29 + * Shadow registers: writes take effect after REG_CFG_DONE + vsync. 30 + */ 31 + #define SYS_CTRL 0x00 32 + #define DSP_CTRL0 0x04 33 + #define DSP_CTRL1 0x08 34 + #define WIN0_COLOR_KEY 0x18 35 + #define WIN0_YRGB_MST 0x20 36 + #define AXI_BUS_CTRL 0x2c 37 + #define WIN0_VIR 0x30 38 + #define WIN0_ACT_INFO 0x34 39 + #define WIN0_DSP_INFO 0x38 40 + #define WIN0_DSP_ST 0x3c 41 + #define DSP_HTOTAL_HS_END 0x6c 42 + #define DSP_HACT_ST_END 0x70 43 + #define DSP_VTOTAL_VS_END 0x74 44 + #define DSP_VACT_ST_END 0x78 45 + #define REG_CFG_DONE 0x90 46 + 47 + /* SYS_CTRL bits - WIN0 enable/format are here, not in a separate register */ 48 + #define m_WIN0_EN BIT(0) 49 + #define m_WIN0_FORMAT (0x7 << 3) 50 + #define v_WIN0_FORMAT(x) (((x) & 0x7) << 3) 51 + #define m_WIN0_RB_SWAP BIT(15) 52 + #define m_WIN0_OTSD_DISABLE BIT(22) 53 + #define m_DMA_STOP BIT(29) 54 + #define m_LCDC_STANDBY BIT(30) 55 + 56 + /* AXI_BUS_CTRL bits - display clock enables for rk312x */ 57 + #define m_LVDS_DCLK_INVERT BIT(27) 58 + #define m_LVDS_DCLK_EN BIT(26) 59 + #define m_RGB_DCLK_INVERT BIT(25) 60 + #define m_RGB_DCLK_EN BIT(24) 61 + #define m_HDMI_DCLK_INVERT BIT(23) 62 + #define m_HDMI_DCLK_EN BIT(22) 63 + 64 + /* VOP format IDs (different from rk3288!) */ 65 + #define VOP_FMT_ARGB888 0 66 + #define VOP_FMT_RGB888 1 67 + #define VOP_FMT_RGB565 2 68 + 69 + /* 70 + * CRU clock gate registers - ungate VOP clocks that the clock driver 71 + * doesn't handle. Write-mask: upper 16 = mask, lower 16 = value. 72 + * Value bit = 1 means gated, 0 means ungated. 73 + */ 74 + #define CRU_BASE 0x20000000 75 + #define CRU_CLKGATE_CON(x) (CRU_BASE + 0xd0 + (x) * 4) 76 + 77 + static void rk3126_vop_ungate_clocks(void) 78 + { 79 + /* CLKGATE_CON3: bit1=DCLK_VOP, bit2=DCLK_LCDC */ 80 + writel(BIT(17) | BIT(18), (void __iomem *)CRU_CLKGATE_CON(3)); 81 + /* CLKGATE_CON6: bit0=ACLK_VIO0, bit2=HCLK_VIO */ 82 + writel(BIT(16) | BIT(18), (void __iomem *)CRU_CLKGATE_CON(6)); 83 + /* CLKGATE_CON9: bit5=HCLK_LCDC0, bit6=ACLK_LCDC0 */ 84 + writel(BIT(21) | BIT(22), (void __iomem *)CRU_CLKGATE_CON(9)); 85 + } 86 + 87 + static void rk3126_mode_set(struct udevice *dev, 88 + const struct display_timing *edid, 89 + enum vop_modes mode) 90 + { 91 + struct rk_vop_priv *priv = dev_get_priv(dev); 92 + void __iomem *base = priv->regs; 93 + u32 hsync_len = edid->hsync_len.typ; 94 + u32 hback_porch = edid->hback_porch.typ; 95 + u32 vsync_len = edid->vsync_len.typ; 96 + u32 vback_porch = edid->vback_porch.typ; 97 + u32 hfront_porch = edid->hfront_porch.typ; 98 + u32 vfront_porch = edid->vfront_porch.typ; 99 + u32 hactive = edid->hactive.typ; 100 + u32 vactive = edid->vactive.typ; 101 + 102 + rk3126_vop_ungate_clocks(); 103 + 104 + /* Match vendor register values exactly */ 105 + writel(0, base + SYS_CTRL); /* clear standby/DMA stop */ 106 + writel(0, base + DSP_CTRL0); /* no polarity inversion, RGB888 */ 107 + writel(0, base + DSP_CTRL1); /* clear BLANK_EN/BLACK_EN */ 108 + writel(m_LVDS_DCLK_EN | m_LVDS_DCLK_INVERT, 109 + base + AXI_BUS_CTRL); /* vendor: 0x0c000000 */ 110 + 111 + /* Display timing */ 112 + writel(V_HSYNC(hsync_len) | 113 + V_HORPRD(hsync_len + hback_porch + hactive + hfront_porch), 114 + base + DSP_HTOTAL_HS_END); 115 + 116 + writel(V_HEAP(hsync_len + hback_porch + hactive) | 117 + V_HASP(hsync_len + hback_porch), 118 + base + DSP_HACT_ST_END); 119 + 120 + writel(V_VSYNC(vsync_len) | 121 + V_VERPRD(vsync_len + vback_porch + vactive + vfront_porch), 122 + base + DSP_VTOTAL_VS_END); 123 + 124 + writel(V_VAEP(vsync_len + vback_porch + vactive) | 125 + V_VASP(vsync_len + vback_porch), 126 + base + DSP_VACT_ST_END); 127 + 128 + writel(0x01, base + REG_CFG_DONE); 129 + } 130 + 131 + static void rk3126_enable(struct udevice *dev, ulong fbbase, 132 + int fb_bits_per_pixel, 133 + const struct display_timing *edid, 134 + struct reset_ctl *dclk_rst) 135 + { 136 + struct rk_vop_priv *priv = dev_get_priv(dev); 137 + void __iomem *base = priv->regs; 138 + u32 vop_fmt; 139 + u32 hactive = edid->hactive.typ; 140 + u32 vactive = edid->vactive.typ; 141 + 142 + /* Re-ungate clocks (clk_set_rate may have disrupted them) */ 143 + rk3126_vop_ungate_clocks(); 144 + 145 + switch (fb_bits_per_pixel) { 146 + case 16: 147 + vop_fmt = VOP_FMT_RGB565; 148 + writel(DIV_ROUND_UP(hactive, 2), base + WIN0_VIR); 149 + break; 150 + case 24: 151 + vop_fmt = VOP_FMT_RGB888; 152 + writel(DIV_ROUND_UP(hactive * 3, 4), base + WIN0_VIR); 153 + break; 154 + case 32: 155 + default: 156 + vop_fmt = VOP_FMT_ARGB888; 157 + writel(hactive, base + WIN0_VIR); 158 + break; 159 + } 160 + 161 + writel(V_ACT_WIDTH(hactive - 1) | V_ACT_HEIGHT(vactive - 1), 162 + base + WIN0_ACT_INFO); 163 + writel(V_DSP_WIDTH(hactive - 1) | V_DSP_HEIGHT(vactive - 1), 164 + base + WIN0_DSP_INFO); 165 + writel(V_DSP_XST(edid->hsync_len.typ + edid->hback_porch.typ) | 166 + V_DSP_YST(edid->vsync_len.typ + edid->vback_porch.typ), 167 + base + WIN0_DSP_ST); 168 + writel(fbbase, base + WIN0_YRGB_MST); 169 + 170 + /* SYS_CTRL: enable WIN0 with format (vendor: 0x11 for RGB565) */ 171 + writel(m_WIN0_EN | v_WIN0_FORMAT(vop_fmt), base + SYS_CTRL); 172 + 173 + /* Commit all shadow registers */ 174 + writel(0x01, base + REG_CFG_DONE); 175 + } 176 + 177 + static void rk3126_enable_output(struct udevice *dev, enum vop_modes mode) 178 + { 179 + /* Output enable is handled in rk3126_mode_set - nothing to do here */ 180 + } 181 + 182 + struct rkvop_driverdata rk3126_driverdata = { 183 + .mode_set = rk3126_mode_set, 184 + .enable = rk3126_enable, 185 + .enable_output = rk3126_enable_output, 186 + }; 187 + 188 + static const struct udevice_id rk3126_vop_ids[] = { 189 + { .compatible = "rockchip,rk3126-vop", 190 + .data = (ulong)&rk3126_driverdata }, 191 + { } 192 + }; 193 + 194 + static const struct video_ops rk3126_vop_ops = { 195 + }; 196 + 197 + U_BOOT_DRIVER(rockchip_rk3126_vop) = { 198 + .name = "rockchip_rk3126_vop", 199 + .id = UCLASS_VIDEO, 200 + .of_match = rk3126_vop_ids, 201 + .ops = &rk3126_vop_ops, 202 + .bind = rk_vop_bind, 203 + .probe = rk_vop_probe, 204 + .priv_auto = sizeof(struct rk_vop_priv), 205 + .flags = DM_FLAG_PRE_RELOC, 206 + };
+20 -5
drivers/video/rockchip/rk_vop.c
··· 43 43 const struct display_timing *edid, 44 44 struct reset_ctl *dclk_rst) 45 45 { 46 + struct rkvop_driverdata *data = 47 + (struct rkvop_driverdata *)dev_get_driver_data(dev); 46 48 struct rk_vop_priv *priv = dev_get_priv(dev); 47 49 struct rk3288_vop *regs = priv->regs; 48 50 struct rk3288_vop *win_regs = priv->regs + priv->win_offset; ··· 51 53 u32 hactive = edid->hactive.typ; 52 54 u32 vactive = edid->vactive.typ; 53 55 int ret; 56 + 57 + if (data->enable) { 58 + data->enable(dev, fbbase, fb_bits_per_pixel, edid, dclk_rst); 59 + return; 60 + } 54 61 55 62 writel(V_ACT_WIDTH(hactive - 1) | V_ACT_HEIGHT(vactive - 1), 56 63 &win_regs->win0_act_info); ··· 124 131 125 132 static void rkvop_enable_output(struct udevice *dev, enum vop_modes mode) 126 133 { 134 + struct rkvop_driverdata *data = 135 + (struct rkvop_driverdata *)dev_get_driver_data(dev); 127 136 struct rk_vop_priv *priv = dev_get_priv(dev); 128 137 struct rk3288_vop *regs = priv->regs; 129 138 139 + if (data->enable_output) { 140 + data->enable_output(dev, mode); 141 + return; 142 + } 143 + 130 144 /* remove from standby */ 131 145 clrbits_le32(&regs->sys_ctrl, V_STANDBY_EN(1)); 132 146 ··· 141 155 V_EDP_OUT_EN(1)); 142 156 break; 143 157 144 - #if defined(CONFIG_ROCKCHIP_RK3288) 145 158 case VOP_MODE_LVDS: 146 159 clrsetbits_le32(&regs->sys_ctrl, M_ALL_OUT_EN, 147 160 V_RGB_OUT_EN(1)); 148 161 break; 149 - #endif 150 162 151 163 case VOP_MODE_MIPI: 152 164 clrsetbits_le32(&regs->sys_ctrl, M_ALL_OUT_EN, ··· 167 179 struct rk3288_vop *dsp_regs = priv->regs + priv->dsp_offset; 168 180 struct rkvop_driverdata *data = 169 181 (struct rkvop_driverdata *)dev_get_driver_data(dev); 182 + 183 + if (data->mode_set) { 184 + data->mode_set(dev, edid, mode); 185 + return; 186 + } 170 187 171 188 u32 hactive = edid->hactive.typ; 172 189 u32 vactive = edid->vactive.typ; ··· 324 341 __func__, dev_read_name(dev), compat); 325 342 return -EINVAL; 326 343 } 327 - debug("vop_id=%d\n", vop_id); 344 + debug("vop mode=%d, compat=%s\n", vop_id, compat); 328 345 329 346 disp_uc_plat = dev_get_uclass_plat(disp); 330 347 debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat); ··· 360 377 /* Set bitwidth for vop display according to vop mode */ 361 378 switch (vop_id) { 362 379 case VOP_MODE_EDP: 363 - #if defined(CONFIG_ROCKCHIP_RK3288) 364 380 case VOP_MODE_LVDS: 365 - #endif 366 381 l2bpp = VIDEO_BPP16; 367 382 break; 368 383 case VOP_MODE_HDMI:
+6
drivers/video/rockchip/rk_vop.h
··· 26 26 u32 features; 27 27 /* block-specific setters/getters */ 28 28 void (*set_pin_polarity)(struct udevice *, enum vop_modes, u32); 29 + /* Optional overrides for SoCs with different register layouts */ 30 + void (*mode_set)(struct udevice *, const struct display_timing *, 31 + enum vop_modes); 32 + void (*enable)(struct udevice *, ulong, int, 33 + const struct display_timing *, struct reset_ctl *); 34 + void (*enable_output)(struct udevice *, enum vop_modes); 29 35 }; 30 36 31 37 /**