diff options
author | Dave Airlie <airlied@redhat.com> | 2018-02-20 16:03:35 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-02-20 16:03:35 -0500 |
commit | e53a2079f46aadb4c3d86ba2528e2b5b7eae49dc (patch) | |
tree | 6b51a69993df06abb40a61d0bd3a8c4e1ac8ef2b | |
parent | 933519a5a269d8460450545adefcb5caec622cac (diff) | |
parent | 871dfe7b48bdc56877826d6cf669e9eef0cf671b (diff) |
Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/media into drm-next
LVDS startup fixes, enable VSP compositor on GEN3
* 'drm/next/du' of git://linuxtv.org/pinchartl/media:
drm: rcar-du: lvds: Refactor LVDS startup
drm: rcar-du: lvds: Fix LVDS startup on R-Car Gen3
drm: rcar-du: lvds: Fix LVDS startup on R-Car Gen2
drm: rcar-du: lvds: Fix LVDS clock frequency range
drm: rcar-du: lvds: Fix LVDCR1 for R-Car gen3
drm: rcar-du: Enable VSP compositor by default on Gen3
drm: rcar-du: Calculate DPLLCR to be more small jitter
drm: rcar-du: Use 1000 to avoid misunderstanding in rcar_du_dpll_divider()
drm: rcar-du: Remove zpos field from rcar_du_vsp_plane_state structure
-rw-r--r-- | drivers/gpu/drm/rcar-du/Kconfig | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 140 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_vsp.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 6 |
5 files changed, 103 insertions, 99 deletions
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 8a50dab19e5c..5d0b4b7119af 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig | |||
@@ -26,7 +26,8 @@ config DRM_RCAR_LVDS | |||
26 | Enable support for the R-Car Display Unit embedded LVDS encoders. | 26 | Enable support for the R-Car Display Unit embedded LVDS encoders. |
27 | 27 | ||
28 | config DRM_RCAR_VSP | 28 | config DRM_RCAR_VSP |
29 | bool "R-Car DU VSP Compositor Support" | 29 | bool "R-Car DU VSP Compositor Support" if ARM |
30 | default y if ARM64 | ||
30 | depends on DRM_RCAR_DU | 31 | depends on DRM_RCAR_DU |
31 | depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m) | 32 | depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m) |
32 | help | 33 | help |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 5685d5af6998..c4420538ec85 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c | |||
@@ -125,14 +125,55 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc, | |||
125 | unsigned int m; | 125 | unsigned int m; |
126 | unsigned int n; | 126 | unsigned int n; |
127 | 127 | ||
128 | for (n = 39; n < 120; n++) { | 128 | /* |
129 | for (m = 0; m < 4; m++) { | 129 | * fin fvco fout fclkout |
130 | * in --> [1/M] --> |PD| -> [LPF] -> [VCO] -> [1/P] -+-> [1/FDPLL] -> out | ||
131 | * +-> | | | | ||
132 | * | | | ||
133 | * +---------------- [1/N] <------------+ | ||
134 | * | ||
135 | * fclkout = fvco / P / FDPLL -- (1) | ||
136 | * | ||
137 | * fin/M = fvco/P/N | ||
138 | * | ||
139 | * fvco = fin * P * N / M -- (2) | ||
140 | * | ||
141 | * (1) + (2) indicates | ||
142 | * | ||
143 | * fclkout = fin * N / M / FDPLL | ||
144 | * | ||
145 | * NOTES | ||
146 | * N : (n + 1) | ||
147 | * M : (m + 1) | ||
148 | * FDPLL : (fdpll + 1) | ||
149 | * P : 2 | ||
150 | * 2kHz < fvco < 4096MHz | ||
151 | * | ||
152 | * To minimize the jitter, | ||
153 | * N : as large as possible | ||
154 | * M : as small as possible | ||
155 | */ | ||
156 | for (m = 0; m < 4; m++) { | ||
157 | for (n = 119; n > 38; n--) { | ||
158 | /* | ||
159 | * This code only runs on 64-bit architectures, the | ||
160 | * unsigned long type can thus be used for 64-bit | ||
161 | * computation. It will still compile without any | ||
162 | * warning on 32-bit architectures. | ||
163 | * | ||
164 | * To optimize calculations, use fout instead of fvco | ||
165 | * to verify the VCO frequency constraint. | ||
166 | */ | ||
167 | unsigned long fout = input * (n + 1) / (m + 1); | ||
168 | |||
169 | if (fout < 1000 || fout > 2048 * 1000 * 1000U) | ||
170 | continue; | ||
171 | |||
130 | for (fdpll = 1; fdpll < 32; fdpll++) { | 172 | for (fdpll = 1; fdpll < 32; fdpll++) { |
131 | unsigned long output; | 173 | unsigned long output; |
132 | 174 | ||
133 | output = input * (n + 1) / (m + 1) | 175 | output = fout / (fdpll + 1); |
134 | / (fdpll + 1); | 176 | if (output >= 400 * 1000 * 1000) |
135 | if (output >= 400000000) | ||
136 | continue; | 177 | continue; |
137 | 178 | ||
138 | diff = abs((long)output - (long)target); | 179 | diff = abs((long)output - (long)target); |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c index 12d22f3db1af..4defa8123eb2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | |||
@@ -39,100 +39,37 @@ static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data) | |||
39 | iowrite32(data, lvds->mmio + reg); | 39 | iowrite32(data, lvds->mmio + reg); |
40 | } | 40 | } |
41 | 41 | ||
42 | static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds, | 42 | static u32 rcar_lvds_lvdpllcr_gen2(unsigned int freq) |
43 | struct rcar_du_crtc *rcrtc) | ||
44 | { | 43 | { |
45 | const struct drm_display_mode *mode = &rcrtc->crtc.mode; | ||
46 | unsigned int freq = mode->clock; | ||
47 | u32 lvdcr0; | ||
48 | u32 pllcr; | ||
49 | |||
50 | /* PLL clock configuration */ | ||
51 | if (freq < 39000) | 44 | if (freq < 39000) |
52 | pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M; | 45 | return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M; |
53 | else if (freq < 61000) | 46 | else if (freq < 61000) |
54 | pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M; | 47 | return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M; |
55 | else if (freq < 121000) | 48 | else if (freq < 121000) |
56 | pllcr = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M; | 49 | return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M; |
57 | else | 50 | else |
58 | pllcr = LVDPLLCR_PLLDLYCNT_150M; | 51 | return LVDPLLCR_PLLDLYCNT_150M; |
59 | |||
60 | rcar_lvds_write(lvds, LVDPLLCR, pllcr); | ||
61 | |||
62 | /* | ||
63 | * Select the input, hardcode mode 0, enable LVDS operation and turn | ||
64 | * bias circuitry on. | ||
65 | */ | ||
66 | lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN; | ||
67 | if (rcrtc->index == 2) | ||
68 | lvdcr0 |= LVDCR0_DUSEL; | ||
69 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
70 | |||
71 | /* Turn all the channels on. */ | ||
72 | rcar_lvds_write(lvds, LVDCR1, | ||
73 | LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) | | ||
74 | LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) | | ||
75 | LVDCR1_CLKSTBY_GEN2); | ||
76 | |||
77 | /* | ||
78 | * Turn the PLL on, wait for the startup delay, and turn the output | ||
79 | * on. | ||
80 | */ | ||
81 | lvdcr0 |= LVDCR0_PLLON; | ||
82 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
83 | |||
84 | usleep_range(100, 150); | ||
85 | |||
86 | lvdcr0 |= LVDCR0_LVRES; | ||
87 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
88 | } | 52 | } |
89 | 53 | ||
90 | static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds, | 54 | static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq) |
91 | struct rcar_du_crtc *rcrtc) | ||
92 | { | 55 | { |
93 | const struct drm_display_mode *mode = &rcrtc->crtc.mode; | ||
94 | unsigned int freq = mode->clock; | ||
95 | u32 lvdcr0; | ||
96 | u32 pllcr; | ||
97 | |||
98 | /* PLL clock configuration */ | ||
99 | if (freq < 42000) | 56 | if (freq < 42000) |
100 | pllcr = LVDPLLCR_PLLDIVCNT_42M; | 57 | return LVDPLLCR_PLLDIVCNT_42M; |
101 | else if (freq < 85000) | 58 | else if (freq < 85000) |
102 | pllcr = LVDPLLCR_PLLDIVCNT_85M; | 59 | return LVDPLLCR_PLLDIVCNT_85M; |
103 | else if (freq < 128000) | 60 | else if (freq < 128000) |
104 | pllcr = LVDPLLCR_PLLDIVCNT_128M; | 61 | return LVDPLLCR_PLLDIVCNT_128M; |
105 | else | 62 | else |
106 | pllcr = LVDPLLCR_PLLDIVCNT_148M; | 63 | return LVDPLLCR_PLLDIVCNT_148M; |
107 | |||
108 | rcar_lvds_write(lvds, LVDPLLCR, pllcr); | ||
109 | |||
110 | /* Turn all the channels on. */ | ||
111 | rcar_lvds_write(lvds, LVDCR1, | ||
112 | LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) | | ||
113 | LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) | | ||
114 | LVDCR1_CLKSTBY_GEN3); | ||
115 | |||
116 | /* | ||
117 | * Turn the PLL on, set it to LVDS normal mode, wait for the startup | ||
118 | * delay and turn the output on. | ||
119 | */ | ||
120 | lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON; | ||
121 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
122 | |||
123 | lvdcr0 |= LVDCR0_PWD; | ||
124 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
125 | |||
126 | usleep_range(100, 150); | ||
127 | |||
128 | lvdcr0 |= LVDCR0_LVRES; | ||
129 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
130 | } | 64 | } |
131 | 65 | ||
132 | static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, | 66 | static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, |
133 | struct rcar_du_crtc *rcrtc) | 67 | struct rcar_du_crtc *rcrtc) |
134 | { | 68 | { |
69 | const struct drm_display_mode *mode = &rcrtc->crtc.mode; | ||
70 | u32 lvdpllcr; | ||
135 | u32 lvdhcr; | 71 | u32 lvdhcr; |
72 | u32 lvdcr0; | ||
136 | int ret; | 73 | int ret; |
137 | 74 | ||
138 | if (lvds->enabled) | 75 | if (lvds->enabled) |
@@ -163,11 +100,46 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, | |||
163 | 100 | ||
164 | rcar_lvds_write(lvds, LVDCHCR, lvdhcr); | 101 | rcar_lvds_write(lvds, LVDCHCR, lvdhcr); |
165 | 102 | ||
166 | /* Perform generation-specific initialization. */ | 103 | /* PLL clock configuration. */ |
167 | if (lvds->dev->info->gen < 3) | 104 | if (lvds->dev->info->gen < 3) |
168 | rcar_du_lvdsenc_start_gen2(lvds, rcrtc); | 105 | lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock); |
169 | else | 106 | else |
170 | rcar_du_lvdsenc_start_gen3(lvds, rcrtc); | 107 | lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock); |
108 | rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr); | ||
109 | |||
110 | /* Set the LVDS mode and select the input. */ | ||
111 | lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT; | ||
112 | if (rcrtc->index == 2) | ||
113 | lvdcr0 |= LVDCR0_DUSEL; | ||
114 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
115 | |||
116 | /* Turn all the channels on. */ | ||
117 | rcar_lvds_write(lvds, LVDCR1, | ||
118 | LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) | | ||
119 | LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY); | ||
120 | |||
121 | if (lvds->dev->info->gen < 3) { | ||
122 | /* Enable LVDS operation and turn the bias circuitry on. */ | ||
123 | lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN; | ||
124 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
125 | } | ||
126 | |||
127 | /* Turn the PLL on. */ | ||
128 | lvdcr0 |= LVDCR0_PLLON; | ||
129 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
130 | |||
131 | if (lvds->dev->info->gen > 2) { | ||
132 | /* Set LVDS normal mode. */ | ||
133 | lvdcr0 |= LVDCR0_PWD; | ||
134 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
135 | } | ||
136 | |||
137 | /* Wait for the startup delay. */ | ||
138 | usleep_range(100, 150); | ||
139 | |||
140 | /* Turn the output on. */ | ||
141 | lvdcr0 |= LVDCR0_LVRES; | ||
142 | rcar_lvds_write(lvds, LVDCR0, lvdcr0); | ||
171 | 143 | ||
172 | lvds->enabled = true; | 144 | lvds->enabled = true; |
173 | 145 | ||
@@ -203,17 +175,11 @@ int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc, | |||
203 | void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds, | 175 | void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds, |
204 | struct drm_display_mode *mode) | 176 | struct drm_display_mode *mode) |
205 | { | 177 | { |
206 | struct rcar_du_device *rcdu = lvds->dev; | ||
207 | |||
208 | /* | 178 | /* |
209 | * The internal LVDS encoder has a restricted clock frequency operating | 179 | * The internal LVDS encoder has a restricted clock frequency operating |
210 | * range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp | 180 | * range (31MHz to 148.5MHz). Clamp the clock accordingly. |
211 | * the clock accordingly. | ||
212 | */ | 181 | */ |
213 | if (rcdu->info->gen < 3) | 182 | mode->clock = clamp(mode->clock, 31000, 148500); |
214 | mode->clock = clamp(mode->clock, 30000, 150000); | ||
215 | else | ||
216 | mode->clock = clamp(mode->clock, 25175, 148500); | ||
217 | } | 183 | } |
218 | 184 | ||
219 | void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds, | 185 | void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds, |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h index f876c512163c..4c5d7bbce6aa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h | |||
@@ -45,7 +45,6 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p) | |||
45 | * @format: information about the pixel format used by the plane | 45 | * @format: information about the pixel format used by the plane |
46 | * @sg_tables: scatter-gather tables for the frame buffer memory | 46 | * @sg_tables: scatter-gather tables for the frame buffer memory |
47 | * @alpha: value of the plane alpha property | 47 | * @alpha: value of the plane alpha property |
48 | * @zpos: value of the plane zpos property | ||
49 | */ | 48 | */ |
50 | struct rcar_du_vsp_plane_state { | 49 | struct rcar_du_vsp_plane_state { |
51 | struct drm_plane_state state; | 50 | struct drm_plane_state state; |
@@ -54,7 +53,6 @@ struct rcar_du_vsp_plane_state { | |||
54 | struct sg_table sg_tables[3]; | 53 | struct sg_table sg_tables[3]; |
55 | 54 | ||
56 | unsigned int alpha; | 55 | unsigned int alpha; |
57 | unsigned int zpos; | ||
58 | }; | 56 | }; |
59 | 57 | ||
60 | static inline struct rcar_du_vsp_plane_state * | 58 | static inline struct rcar_du_vsp_plane_state * |
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h index d7d294ba2dbe..2896835ca7e9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | |||
@@ -26,10 +26,8 @@ | |||
26 | 26 | ||
27 | #define LVDCR1 0x0004 | 27 | #define LVDCR1 0x0004 |
28 | #define LVDCR1_CKSEL (1 << 15) /* Gen2 only */ | 28 | #define LVDCR1_CKSEL (1 << 15) /* Gen2 only */ |
29 | #define LVDCR1_CHSTBY_GEN2(n) (3 << (2 + (n) * 2)) /* Gen2 only */ | 29 | #define LVDCR1_CHSTBY(n) (3 << (2 + (n) * 2)) |
30 | #define LVDCR1_CHSTBY_GEN3(n) (1 << (2 + (n) * 2)) /* Gen3 only */ | 30 | #define LVDCR1_CLKSTBY (3 << 0) |
31 | #define LVDCR1_CLKSTBY_GEN2 (3 << 0) /* Gen2 only */ | ||
32 | #define LVDCR1_CLKSTBY_GEN3 (1 << 0) /* Gen3 only */ | ||
33 | 31 | ||
34 | #define LVDPLLCR 0x0008 | 32 | #define LVDPLLCR 0x0008 |
35 | #define LVDPLLCR_CEEN (1 << 14) | 33 | #define LVDPLLCR_CEEN (1 << 14) |