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

drm: rcar-du: lvds: Add R-Car Gen3 support

The LVDS encoder differs slightly in Gen3 SoCs in its PLL configuration.
Add support for the Gen3 LVDS PLL parameters and startup procedure.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

authored by

Koji Matsuoka and committed by
Laurent Pinchart
6bc2e15c 82e7c5e4

+123 -48
+1 -3
drivers/gpu/drm/rcar-du/Kconfig
··· 21 21 config DRM_RCAR_LVDS 22 22 bool "R-Car DU LVDS Encoder Support" 23 23 depends on DRM_RCAR_DU 24 - depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST 25 24 help 26 - Enable support for the R-Car Display Unit embedded LVDS encoders 27 - (currently only on R8A7790 and R8A7791). 25 + Enable support for the R-Car Display Unit embedded LVDS encoders. 28 26 29 27 config DRM_RCAR_VSP 30 28 bool "R-Car DU VSP Compositor Support"
+8 -2
drivers/gpu/drm/rcar-du/rcar_du_drv.c
··· 140 140 | RCAR_DU_FEATURE_VSP1_SOURCE, 141 141 .num_crtcs = 4, 142 142 .routes = { 143 - /* R8A7795 has one RGB output, and two HDMI and one LVDS 144 - * (currently unsupported) outputs 143 + /* R8A7795 has one RGB output, one LVDS output and two 144 + * (currently unsupported) HDMI outputs. 145 145 */ 146 146 [RCAR_DU_OUTPUT_DPAD0] = { 147 147 .possible_crtcs = BIT(3), 148 148 .encoder_type = DRM_MODE_ENCODER_NONE, 149 149 .port = 0, 150 150 }, 151 + [RCAR_DU_OUTPUT_LVDS0] = { 152 + .possible_crtcs = BIT(0), 153 + .encoder_type = DRM_MODE_ENCODER_LVDS, 154 + .port = 3, 155 + }, 151 156 }, 157 + .num_lvds = 1, 152 158 }; 153 159 154 160 static const struct of_device_id rcar_du_of_table[] = {
+97 -36
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
··· 38 38 iowrite32(data, lvds->mmio + reg); 39 39 } 40 40 41 - static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, 42 - struct rcar_du_crtc *rcrtc) 41 + static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds, 42 + struct rcar_du_crtc *rcrtc) 43 43 { 44 44 const struct drm_display_mode *mode = &rcrtc->crtc.mode; 45 45 unsigned int freq = mode->clock; 46 46 u32 lvdcr0; 47 - u32 lvdhcr; 48 47 u32 pllcr; 49 - int ret; 50 - 51 - if (lvds->enabled) 52 - return 0; 53 - 54 - ret = clk_prepare_enable(lvds->clock); 55 - if (ret < 0) 56 - return ret; 57 48 58 49 /* PLL clock configuration */ 59 50 if (freq < 39000) ··· 57 66 pllcr = LVDPLLCR_PLLDLYCNT_150M; 58 67 59 68 rcar_lvds_write(lvds, LVDPLLCR, pllcr); 69 + 70 + /* Select the input, hardcode mode 0, enable LVDS operation and turn 71 + * bias circuitry on. 72 + */ 73 + lvdcr0 = LVDCR0_BEN | LVDCR0_LVEN; 74 + if (rcrtc->index == 2) 75 + lvdcr0 |= LVDCR0_DUSEL; 76 + rcar_lvds_write(lvds, LVDCR0, lvdcr0); 77 + 78 + /* Turn all the channels on. */ 79 + rcar_lvds_write(lvds, LVDCR1, 80 + LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) | 81 + LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) | 82 + LVDCR1_CLKSTBY_GEN2); 83 + 84 + /* Turn the PLL on, wait for the startup delay, and turn the output 85 + * on. 86 + */ 87 + lvdcr0 |= LVDCR0_PLLON; 88 + rcar_lvds_write(lvds, LVDCR0, lvdcr0); 89 + 90 + usleep_range(100, 150); 91 + 92 + lvdcr0 |= LVDCR0_LVRES; 93 + rcar_lvds_write(lvds, LVDCR0, lvdcr0); 94 + } 95 + 96 + static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds, 97 + struct rcar_du_crtc *rcrtc) 98 + { 99 + const struct drm_display_mode *mode = &rcrtc->crtc.mode; 100 + unsigned int freq = mode->clock; 101 + u32 lvdcr0; 102 + u32 pllcr; 103 + 104 + /* PLL clock configuration */ 105 + if (freq < 42000) 106 + pllcr = LVDPLLCR_PLLDIVCNT_42M; 107 + else if (freq < 85000) 108 + pllcr = LVDPLLCR_PLLDIVCNT_85M; 109 + else if (freq < 128000) 110 + pllcr = LVDPLLCR_PLLDIVCNT_128M; 111 + else 112 + pllcr = LVDPLLCR_PLLDIVCNT_148M; 113 + 114 + rcar_lvds_write(lvds, LVDPLLCR, pllcr); 115 + 116 + /* Turn the PLL on, set it to LVDS normal mode, wait for the startup 117 + * delay and turn the output on. 118 + */ 119 + lvdcr0 = LVDCR0_PLLON; 120 + rcar_lvds_write(lvds, LVDCR0, lvdcr0); 121 + 122 + lvdcr0 |= LVDCR0_PWD; 123 + rcar_lvds_write(lvds, LVDCR0, lvdcr0); 124 + 125 + usleep_range(100, 150); 126 + 127 + lvdcr0 |= LVDCR0_LVRES; 128 + rcar_lvds_write(lvds, LVDCR0, lvdcr0); 129 + 130 + /* Turn all the channels on. */ 131 + rcar_lvds_write(lvds, LVDCR1, 132 + LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) | 133 + LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) | 134 + LVDCR1_CLKSTBY_GEN3); 135 + } 136 + 137 + static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, 138 + struct rcar_du_crtc *rcrtc) 139 + { 140 + u32 lvdhcr; 141 + int ret; 142 + 143 + if (lvds->enabled) 144 + return 0; 145 + 146 + ret = clk_prepare_enable(lvds->clock); 147 + if (ret < 0) 148 + return ret; 60 149 61 150 /* Hardcode the channels and control signals routing for now. 62 151 * ··· 158 87 159 88 rcar_lvds_write(lvds, LVDCHCR, lvdhcr); 160 89 161 - /* Select the input, hardcode mode 0, enable LVDS operation and turn 162 - * bias circuitry on. 163 - */ 164 - lvdcr0 = LVDCR0_BEN | LVDCR0_LVEN; 165 - if (rcrtc->index == 2) 166 - lvdcr0 |= LVDCR0_DUSEL; 167 - rcar_lvds_write(lvds, LVDCR0, lvdcr0); 168 - 169 - /* Turn all the channels on. */ 170 - rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) | 171 - LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY); 172 - 173 - /* Turn the PLL on, wait for the startup delay, and turn the output 174 - * on. 175 - */ 176 - lvdcr0 |= LVDCR0_PLLON; 177 - rcar_lvds_write(lvds, LVDCR0, lvdcr0); 178 - 179 - usleep_range(100, 150); 180 - 181 - lvdcr0 |= LVDCR0_LVRES; 182 - rcar_lvds_write(lvds, LVDCR0, lvdcr0); 90 + /* Perform generation-specific initialization. */ 91 + if (lvds->dev->info->gen < 3) 92 + rcar_du_lvdsenc_start_gen2(lvds, rcrtc); 93 + else 94 + rcar_du_lvdsenc_start_gen3(lvds, rcrtc); 183 95 184 96 lvds->enabled = true; 97 + 185 98 return 0; 186 99 } 187 100 ··· 198 143 void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds, 199 144 struct drm_display_mode *mode) 200 145 { 201 - /* The internal LVDS encoder has a clock frequency operating range of 202 - * 30MHz to 150MHz. Clamp the clock accordingly. 146 + struct rcar_du_device *rcdu = lvds->dev; 147 + 148 + /* The internal LVDS encoder has a restricted clock frequency operating 149 + * range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp 150 + * the clock accordingly. 203 151 */ 204 - mode->clock = clamp(mode->clock, 30000, 150000); 152 + if (rcdu->info->gen < 3) 153 + mode->clock = clamp(mode->clock, 30000, 150000); 154 + else 155 + mode->clock = clamp(mode->clock, 25175, 148500); 205 156 } 206 157 207 158 static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
+17 -7
drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
··· 1 1 /* 2 2 * rcar_lvds_regs.h -- R-Car LVDS Interface Registers Definitions 3 3 * 4 - * Copyright (C) 2013 Renesas Electronics Corporation 4 + * Copyright (C) 2013-2015 Renesas Electronics Corporation 5 5 * 6 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 7 7 * ··· 15 15 16 16 #define LVDCR0 0x0000 17 17 #define LVDCR0_DUSEL (1 << 15) 18 - #define LVDCR0_DMD (1 << 12) 18 + #define LVDCR0_DMD (1 << 12) /* Gen2 only */ 19 19 #define LVDCR0_LVMD_MASK (0xf << 8) 20 20 #define LVDCR0_LVMD_SHIFT 8 21 21 #define LVDCR0_PLLON (1 << 4) 22 - #define LVDCR0_BEN (1 << 2) 23 - #define LVDCR0_LVEN (1 << 1) 22 + #define LVDCR0_PWD (1 << 2) /* Gen3 only */ 23 + #define LVDCR0_BEN (1 << 2) /* Gen2 only */ 24 + #define LVDCR0_LVEN (1 << 1) /* Gen2 only */ 24 25 #define LVDCR0_LVRES (1 << 0) 25 26 26 27 #define LVDCR1 0x0004 27 - #define LVDCR1_CKSEL (1 << 15) 28 - #define LVDCR1_CHSTBY(n) (3 << (2 + (n) * 2)) 29 - #define LVDCR1_CLKSTBY (3 << 0) 28 + #define LVDCR1_CKSEL (1 << 15) /* Gen2 only */ 29 + #define LVDCR1_CHSTBY_GEN2(n) (3 << (2 + (n) * 2)) /* Gen2 only */ 30 + #define LVDCR1_CHSTBY_GEN3(n) (1 << (2 + (n) * 2)) /* Gen3 only */ 31 + #define LVDCR1_CLKSTBY_GEN2 (3 << 0) /* Gen2 only */ 32 + #define LVDCR1_CLKSTBY_GEN3 (1 << 0) /* Gen3 only */ 30 33 31 34 #define LVDPLLCR 0x0008 32 35 #define LVDPLLCR_CEEN (1 << 14) 33 36 #define LVDPLLCR_FBEN (1 << 13) 34 37 #define LVDPLLCR_COSEL (1 << 12) 38 + /* Gen2 */ 35 39 #define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0) 36 40 #define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0) 37 41 #define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0) 38 42 #define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0) 39 43 #define LVDPLLCR_PLLDLYCNT_MASK (0x7ff << 0) 44 + /* Gen3 */ 45 + #define LVDPLLCR_PLLDIVCNT_42M (0x014cb << 0) 46 + #define LVDPLLCR_PLLDIVCNT_85M (0x00a45 << 0) 47 + #define LVDPLLCR_PLLDIVCNT_128M (0x006c3 << 0) 48 + #define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) 49 + #define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0) 40 50 41 51 #define LVDCTRCR 0x000c 42 52 #define LVDCTRCR_CTR3SEL_ZERO (0 << 12)