aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoji Matsuoka <koji.matsuoka.xm@renesas.com>2015-07-28 07:12:43 -0400
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2016-02-23 02:34:32 -0500
commit6bc2e15cf21cd96eba69ac83ddd37a7994148b16 (patch)
tree1d54f430befed85fd0a96762ab06dd2f74b69cb0
parent82e7c5e4964545352accff4b44bbcaa2c38e7fc1 (diff)
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>
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig4
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c10
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c133
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds_regs.h24
4 files changed, 123 insertions, 48 deletions
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 2171a6f5a573..1f10fa0928b4 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -21,10 +21,8 @@ config DRM_RCAR_HDMI
21config DRM_RCAR_LVDS 21config DRM_RCAR_LVDS
22 bool "R-Car DU LVDS Encoder Support" 22 bool "R-Car DU LVDS Encoder Support"
23 depends on DRM_RCAR_DU 23 depends on DRM_RCAR_DU
24 depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
25 help 24 help
26 Enable support for the R-Car Display Unit embedded LVDS encoders 25 Enable support for the R-Car Display Unit embedded LVDS encoders.
27 (currently only on R8A7790 and R8A7791).
28 26
29config DRM_RCAR_VSP 27config DRM_RCAR_VSP
30 bool "R-Car DU VSP Compositor Support" 28 bool "R-Car DU VSP Compositor Support"
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 24265d75e7de..ed6006bf6bd8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -140,15 +140,21 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
140 | RCAR_DU_FEATURE_VSP1_SOURCE, 140 | RCAR_DU_FEATURE_VSP1_SOURCE,
141 .num_crtcs = 4, 141 .num_crtcs = 4,
142 .routes = { 142 .routes = {
143 /* R8A7795 has one RGB output, and two HDMI and one LVDS 143 /* R8A7795 has one RGB output, one LVDS output and two
144 * (currently unsupported) outputs 144 * (currently unsupported) HDMI outputs.
145 */ 145 */
146 [RCAR_DU_OUTPUT_DPAD0] = { 146 [RCAR_DU_OUTPUT_DPAD0] = {
147 .possible_crtcs = BIT(3), 147 .possible_crtcs = BIT(3),
148 .encoder_type = DRM_MODE_ENCODER_NONE, 148 .encoder_type = DRM_MODE_ENCODER_NONE,
149 .port = 0, 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
154static const struct of_device_id rcar_du_of_table[] = { 160static const struct of_device_id rcar_du_of_table[] = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
index 02acebadf7d6..ef3a50321ecc 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -38,22 +38,13 @@ static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
38 iowrite32(data, lvds->mmio + reg); 38 iowrite32(data, lvds->mmio + reg);
39} 39}
40 40
41static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, 41static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
42 struct rcar_du_crtc *rcrtc) 42 struct rcar_du_crtc *rcrtc)
43{ 43{
44 const struct drm_display_mode *mode = &rcrtc->crtc.mode; 44 const struct drm_display_mode *mode = &rcrtc->crtc.mode;
45 unsigned int freq = mode->clock; 45 unsigned int freq = mode->clock;
46 u32 lvdcr0; 46 u32 lvdcr0;
47 u32 lvdhcr;
48 u32 pllcr; 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 /* PLL clock configuration */ 49 /* PLL clock configuration */
59 if (freq < 39000) 50 if (freq < 39000)
@@ -67,26 +58,6 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
67 58
68 rcar_lvds_write(lvds, LVDPLLCR, pllcr); 59 rcar_lvds_write(lvds, LVDPLLCR, pllcr);
69 60
70 /* Hardcode the channels and control signals routing for now.
71 *
72 * HSYNC -> CTRL0
73 * VSYNC -> CTRL1
74 * DISP -> CTRL2
75 * 0 -> CTRL3
76 */
77 rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
78 LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
79 LVDCTRCR_CTR0SEL_HSYNC);
80
81 if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
82 lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
83 | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
84 else
85 lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
86 | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
87
88 rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
89
90 /* Select the input, hardcode mode 0, enable LVDS operation and turn 61 /* Select the input, hardcode mode 0, enable LVDS operation and turn
91 * bias circuitry on. 62 * bias circuitry on.
92 */ 63 */
@@ -96,8 +67,10 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
96 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 67 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
97 68
98 /* Turn all the channels on. */ 69 /* Turn all the channels on. */
99 rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) | 70 rcar_lvds_write(lvds, LVDCR1,
100 LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY); 71 LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) |
72 LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) |
73 LVDCR1_CLKSTBY_GEN2);
101 74
102 /* Turn the PLL on, wait for the startup delay, and turn the output 75 /* Turn the PLL on, wait for the startup delay, and turn the output
103 * on. 76 * on.
@@ -109,8 +82,90 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
109 82
110 lvdcr0 |= LVDCR0_LVRES; 83 lvdcr0 |= LVDCR0_LVRES;
111 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 84 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
85}
86
87static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
88 struct rcar_du_crtc *rcrtc)
89{
90 const struct drm_display_mode *mode = &rcrtc->crtc.mode;
91 unsigned int freq = mode->clock;
92 u32 lvdcr0;
93 u32 pllcr;
94
95 /* PLL clock configuration */
96 if (freq < 42000)
97 pllcr = LVDPLLCR_PLLDIVCNT_42M;
98 else if (freq < 85000)
99 pllcr = LVDPLLCR_PLLDIVCNT_85M;
100 else if (freq < 128000)
101 pllcr = LVDPLLCR_PLLDIVCNT_128M;
102 else
103 pllcr = LVDPLLCR_PLLDIVCNT_148M;
104
105 rcar_lvds_write(lvds, LVDPLLCR, pllcr);
106
107 /* Turn the PLL on, set it to LVDS normal mode, wait for the startup
108 * delay and turn the output on.
109 */
110 lvdcr0 = LVDCR0_PLLON;
111 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
112
113 lvdcr0 |= LVDCR0_PWD;
114 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
115
116 usleep_range(100, 150);
117
118 lvdcr0 |= LVDCR0_LVRES;
119 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
120
121 /* Turn all the channels on. */
122 rcar_lvds_write(lvds, LVDCR1,
123 LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
124 LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
125 LVDCR1_CLKSTBY_GEN3);
126}
127
128static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
129 struct rcar_du_crtc *rcrtc)
130{
131 u32 lvdhcr;
132 int ret;
133
134 if (lvds->enabled)
135 return 0;
136
137 ret = clk_prepare_enable(lvds->clock);
138 if (ret < 0)
139 return ret;
140
141 /* Hardcode the channels and control signals routing for now.
142 *
143 * HSYNC -> CTRL0
144 * VSYNC -> CTRL1
145 * DISP -> CTRL2
146 * 0 -> CTRL3
147 */
148 rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
149 LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
150 LVDCTRCR_CTR0SEL_HSYNC);
151
152 if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
153 lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
154 | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
155 else
156 lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
157 | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
158
159 rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
160
161 /* Perform generation-specific initialization. */
162 if (lvds->dev->info->gen < 3)
163 rcar_du_lvdsenc_start_gen2(lvds, rcrtc);
164 else
165 rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
112 166
113 lvds->enabled = true; 167 lvds->enabled = true;
168
114 return 0; 169 return 0;
115} 170}
116 171
@@ -143,10 +198,16 @@ int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
143void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds, 198void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
144 struct drm_display_mode *mode) 199 struct drm_display_mode *mode)
145{ 200{
146 /* The internal LVDS encoder has a clock frequency operating range of 201 struct rcar_du_device *rcdu = lvds->dev;
147 * 30MHz to 150MHz. Clamp the clock accordingly. 202
203 /* The internal LVDS encoder has a restricted clock frequency operating
204 * range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp
205 * the clock accordingly.
148 */ 206 */
149 mode->clock = clamp(mode->clock, 30000, 150000); 207 if (rcdu->info->gen < 3)
208 mode->clock = clamp(mode->clock, 30000, 150000);
209 else
210 mode->clock = clamp(mode->clock, 25175, 148500);
150} 211}
151 212
152static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds, 213static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
index b1eafd097a79..d7d294ba2dbe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * rcar_lvds_regs.h -- R-Car LVDS Interface Registers Definitions 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 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 * 7 *
@@ -15,28 +15,38 @@
15 15
16#define LVDCR0 0x0000 16#define LVDCR0 0x0000
17#define LVDCR0_DUSEL (1 << 15) 17#define LVDCR0_DUSEL (1 << 15)
18#define LVDCR0_DMD (1 << 12) 18#define LVDCR0_DMD (1 << 12) /* Gen2 only */
19#define LVDCR0_LVMD_MASK (0xf << 8) 19#define LVDCR0_LVMD_MASK (0xf << 8)
20#define LVDCR0_LVMD_SHIFT 8 20#define LVDCR0_LVMD_SHIFT 8
21#define LVDCR0_PLLON (1 << 4) 21#define LVDCR0_PLLON (1 << 4)
22#define LVDCR0_BEN (1 << 2) 22#define LVDCR0_PWD (1 << 2) /* Gen3 only */
23#define LVDCR0_LVEN (1 << 1) 23#define LVDCR0_BEN (1 << 2) /* Gen2 only */
24#define LVDCR0_LVEN (1 << 1) /* Gen2 only */
24#define LVDCR0_LVRES (1 << 0) 25#define LVDCR0_LVRES (1 << 0)
25 26
26#define LVDCR1 0x0004 27#define LVDCR1 0x0004
27#define LVDCR1_CKSEL (1 << 15) 28#define LVDCR1_CKSEL (1 << 15) /* Gen2 only */
28#define LVDCR1_CHSTBY(n) (3 << (2 + (n) * 2)) 29#define LVDCR1_CHSTBY_GEN2(n) (3 << (2 + (n) * 2)) /* Gen2 only */
29#define LVDCR1_CLKSTBY (3 << 0) 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#define LVDPLLCR 0x0008 34#define LVDPLLCR 0x0008
32#define LVDPLLCR_CEEN (1 << 14) 35#define LVDPLLCR_CEEN (1 << 14)
33#define LVDPLLCR_FBEN (1 << 13) 36#define LVDPLLCR_FBEN (1 << 13)
34#define LVDPLLCR_COSEL (1 << 12) 37#define LVDPLLCR_COSEL (1 << 12)
38/* Gen2 */
35#define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0) 39#define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0)
36#define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0) 40#define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0)
37#define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0) 41#define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0)
38#define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0) 42#define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0)
39#define LVDPLLCR_PLLDLYCNT_MASK (0x7ff << 0) 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#define LVDCTRCR 0x000c 51#define LVDCTRCR 0x000c
42#define LVDCTRCR_CTR3SEL_ZERO (0 << 12) 52#define LVDCTRCR_CTR3SEL_ZERO (0 << 12)