diff options
Diffstat (limited to 'drivers/gpu/drm/sti/sti_tvout.c')
-rw-r--r-- | drivers/gpu/drm/sti/sti_tvout.c | 104 |
1 files changed, 59 insertions, 45 deletions
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index b8afe490356a..cb924aa2b321 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <drm/drm_crtc_helper.h> | 17 | #include <drm/drm_crtc_helper.h> |
18 | 18 | ||
19 | #include "sti_drm_crtc.h" | ||
20 | |||
19 | /* glue registers */ | 21 | /* glue registers */ |
20 | #define TVO_CSC_MAIN_M0 0x000 | 22 | #define TVO_CSC_MAIN_M0 0x000 |
21 | #define TVO_CSC_MAIN_M1 0x004 | 23 | #define TVO_CSC_MAIN_M1 0x004 |
@@ -96,7 +98,7 @@ | |||
96 | 98 | ||
97 | #define TVO_SYNC_HD_DCS_SHIFT 8 | 99 | #define TVO_SYNC_HD_DCS_SHIFT 8 |
98 | 100 | ||
99 | #define ENCODER_MAIN_CRTC_MASK BIT(0) | 101 | #define ENCODER_CRTC_MASK (BIT(0) | BIT(1)) |
100 | 102 | ||
101 | /* enum listing the supported output data format */ | 103 | /* enum listing the supported output data format */ |
102 | enum sti_tvout_video_out_type { | 104 | enum sti_tvout_video_out_type { |
@@ -149,14 +151,15 @@ static void tvout_write(struct sti_tvout *tvout, u32 val, int offset) | |||
149 | * Set the clipping mode of a VIP | 151 | * Set the clipping mode of a VIP |
150 | * | 152 | * |
151 | * @tvout: tvout structure | 153 | * @tvout: tvout structure |
154 | * @reg: register to set | ||
152 | * @cr_r: | 155 | * @cr_r: |
153 | * @y_g: | 156 | * @y_g: |
154 | * @cb_b: | 157 | * @cb_b: |
155 | */ | 158 | */ |
156 | static void tvout_vip_set_color_order(struct sti_tvout *tvout, | 159 | static void tvout_vip_set_color_order(struct sti_tvout *tvout, int reg, |
157 | u32 cr_r, u32 y_g, u32 cb_b) | 160 | u32 cr_r, u32 y_g, u32 cb_b) |
158 | { | 161 | { |
159 | u32 val = tvout_read(tvout, TVO_VIP_HDMI); | 162 | u32 val = tvout_read(tvout, reg); |
160 | 163 | ||
161 | val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT); | 164 | val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT); |
162 | val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT); | 165 | val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT); |
@@ -165,52 +168,58 @@ static void tvout_vip_set_color_order(struct sti_tvout *tvout, | |||
165 | val |= y_g << TVO_VIP_REORDER_G_SHIFT; | 168 | val |= y_g << TVO_VIP_REORDER_G_SHIFT; |
166 | val |= cb_b << TVO_VIP_REORDER_B_SHIFT; | 169 | val |= cb_b << TVO_VIP_REORDER_B_SHIFT; |
167 | 170 | ||
168 | tvout_write(tvout, val, TVO_VIP_HDMI); | 171 | tvout_write(tvout, val, reg); |
169 | } | 172 | } |
170 | 173 | ||
171 | /** | 174 | /** |
172 | * Set the clipping mode of a VIP | 175 | * Set the clipping mode of a VIP |
173 | * | 176 | * |
174 | * @tvout: tvout structure | 177 | * @tvout: tvout structure |
178 | * @reg: register to set | ||
175 | * @range: clipping range | 179 | * @range: clipping range |
176 | */ | 180 | */ |
177 | static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, u32 range) | 181 | static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, int reg, u32 range) |
178 | { | 182 | { |
179 | u32 val = tvout_read(tvout, TVO_VIP_HDMI); | 183 | u32 val = tvout_read(tvout, reg); |
180 | 184 | ||
181 | val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT); | 185 | val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT); |
182 | val |= range << TVO_VIP_CLIP_SHIFT; | 186 | val |= range << TVO_VIP_CLIP_SHIFT; |
183 | tvout_write(tvout, val, TVO_VIP_HDMI); | 187 | tvout_write(tvout, val, reg); |
184 | } | 188 | } |
185 | 189 | ||
186 | /** | 190 | /** |
187 | * Set the rounded value of a VIP | 191 | * Set the rounded value of a VIP |
188 | * | 192 | * |
189 | * @tvout: tvout structure | 193 | * @tvout: tvout structure |
194 | * @reg: register to set | ||
190 | * @rnd: rounded val per component | 195 | * @rnd: rounded val per component |
191 | */ | 196 | */ |
192 | static void tvout_vip_set_rnd(struct sti_tvout *tvout, u32 rnd) | 197 | static void tvout_vip_set_rnd(struct sti_tvout *tvout, int reg, u32 rnd) |
193 | { | 198 | { |
194 | u32 val = tvout_read(tvout, TVO_VIP_HDMI); | 199 | u32 val = tvout_read(tvout, reg); |
195 | 200 | ||
196 | val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT); | 201 | val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT); |
197 | val |= rnd << TVO_VIP_RND_SHIFT; | 202 | val |= rnd << TVO_VIP_RND_SHIFT; |
198 | tvout_write(tvout, val, TVO_VIP_HDMI); | 203 | tvout_write(tvout, val, reg); |
199 | } | 204 | } |
200 | 205 | ||
201 | /** | 206 | /** |
202 | * Select the VIP input | 207 | * Select the VIP input |
203 | * | 208 | * |
204 | * @tvout: tvout structure | 209 | * @tvout: tvout structure |
210 | * @reg: register to set | ||
211 | * @main_path: main or auxiliary path | ||
212 | * @sel_input_logic_inverted: need to invert the logic | ||
205 | * @sel_input: selected_input (main/aux + conv) | 213 | * @sel_input: selected_input (main/aux + conv) |
206 | */ | 214 | */ |
207 | static void tvout_vip_set_sel_input(struct sti_tvout *tvout, | 215 | static void tvout_vip_set_sel_input(struct sti_tvout *tvout, |
216 | int reg, | ||
208 | bool main_path, | 217 | bool main_path, |
209 | bool sel_input_logic_inverted, | 218 | bool sel_input_logic_inverted, |
210 | enum sti_tvout_video_out_type video_out) | 219 | enum sti_tvout_video_out_type video_out) |
211 | { | 220 | { |
212 | u32 sel_input; | 221 | u32 sel_input; |
213 | u32 val = tvout_read(tvout, TVO_VIP_HDMI); | 222 | u32 val = tvout_read(tvout, reg); |
214 | 223 | ||
215 | if (main_path) | 224 | if (main_path) |
216 | sel_input = TVO_VIP_SEL_INPUT_MAIN; | 225 | sel_input = TVO_VIP_SEL_INPUT_MAIN; |
@@ -232,22 +241,24 @@ static void tvout_vip_set_sel_input(struct sti_tvout *tvout, | |||
232 | 241 | ||
233 | val &= ~TVO_VIP_SEL_INPUT_MASK; | 242 | val &= ~TVO_VIP_SEL_INPUT_MASK; |
234 | val |= sel_input; | 243 | val |= sel_input; |
235 | tvout_write(tvout, val, TVO_VIP_HDMI); | 244 | tvout_write(tvout, val, reg); |
236 | } | 245 | } |
237 | 246 | ||
238 | /** | 247 | /** |
239 | * Select the input video signed or unsigned | 248 | * Select the input video signed or unsigned |
240 | * | 249 | * |
241 | * @tvout: tvout structure | 250 | * @tvout: tvout structure |
251 | * @reg: register to set | ||
242 | * @in_vid_signed: used video input format | 252 | * @in_vid_signed: used video input format |
243 | */ | 253 | */ |
244 | static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, u32 in_vid_fmt) | 254 | static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, |
255 | int reg, u32 in_vid_fmt) | ||
245 | { | 256 | { |
246 | u32 val = tvout_read(tvout, TVO_VIP_HDMI); | 257 | u32 val = tvout_read(tvout, reg); |
247 | 258 | ||
248 | val &= ~TVO_IN_FMT_SIGNED; | 259 | val &= ~TVO_IN_FMT_SIGNED; |
249 | val |= in_vid_fmt; | 260 | val |= in_vid_fmt; |
250 | tvout_write(tvout, val, TVO_MAIN_IN_VID_FORMAT); | 261 | tvout_write(tvout, val, reg); |
251 | } | 262 | } |
252 | 263 | ||
253 | /** | 264 | /** |
@@ -261,6 +272,7 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path) | |||
261 | { | 272 | { |
262 | struct device_node *node = tvout->dev->of_node; | 273 | struct device_node *node = tvout->dev->of_node; |
263 | bool sel_input_logic_inverted = false; | 274 | bool sel_input_logic_inverted = false; |
275 | u32 tvo_in_vid_format; | ||
264 | 276 | ||
265 | dev_dbg(tvout->dev, "%s\n", __func__); | 277 | dev_dbg(tvout->dev, "%s\n", __func__); |
266 | 278 | ||
@@ -268,33 +280,36 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path) | |||
268 | DRM_DEBUG_DRIVER("main vip for hdmi\n"); | 280 | DRM_DEBUG_DRIVER("main vip for hdmi\n"); |
269 | /* select the input sync for hdmi = VTG set 1 */ | 281 | /* select the input sync for hdmi = VTG set 1 */ |
270 | tvout_write(tvout, TVO_SYNC_MAIN_VTG_SET_1, TVO_HDMI_SYNC_SEL); | 282 | tvout_write(tvout, TVO_SYNC_MAIN_VTG_SET_1, TVO_HDMI_SYNC_SEL); |
283 | tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; | ||
271 | } else { | 284 | } else { |
272 | DRM_DEBUG_DRIVER("aux vip for hdmi\n"); | 285 | DRM_DEBUG_DRIVER("aux vip for hdmi\n"); |
273 | /* select the input sync for hdmi = VTG set 1 */ | 286 | /* select the input sync for hdmi = VTG set 1 */ |
274 | tvout_write(tvout, TVO_SYNC_AUX_VTG_SET_1, TVO_HDMI_SYNC_SEL); | 287 | tvout_write(tvout, TVO_SYNC_AUX_VTG_SET_1, TVO_HDMI_SYNC_SEL); |
288 | tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; | ||
275 | } | 289 | } |
276 | 290 | ||
277 | /* set color channel order */ | 291 | /* set color channel order */ |
278 | tvout_vip_set_color_order(tvout, | 292 | tvout_vip_set_color_order(tvout, TVO_VIP_HDMI, |
279 | TVO_VIP_REORDER_CR_R_SEL, | 293 | TVO_VIP_REORDER_CR_R_SEL, |
280 | TVO_VIP_REORDER_Y_G_SEL, | 294 | TVO_VIP_REORDER_Y_G_SEL, |
281 | TVO_VIP_REORDER_CB_B_SEL); | 295 | TVO_VIP_REORDER_CB_B_SEL); |
282 | 296 | ||
283 | /* set clipping mode (Limited range RGB/Y) */ | 297 | /* set clipping mode (Limited range RGB/Y) */ |
284 | tvout_vip_set_clip_mode(tvout, TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); | 298 | tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, |
299 | TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); | ||
285 | 300 | ||
286 | /* set round mode (rounded to 8-bit per component) */ | 301 | /* set round mode (rounded to 8-bit per component) */ |
287 | tvout_vip_set_rnd(tvout, TVO_VIP_RND_8BIT_ROUNDED); | 302 | tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED); |
288 | 303 | ||
289 | if (of_device_is_compatible(node, "st,stih407-tvout")) { | 304 | if (of_device_is_compatible(node, "st,stih407-tvout")) { |
290 | /* set input video format */ | 305 | /* set input video format */ |
291 | tvout_vip_set_in_vid_fmt(tvout->regs + TVO_MAIN_IN_VID_FORMAT, | 306 | tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format, |
292 | TVO_IN_FMT_SIGNED); | 307 | TVO_IN_FMT_SIGNED); |
293 | sel_input_logic_inverted = true; | 308 | sel_input_logic_inverted = true; |
294 | } | 309 | } |
295 | 310 | ||
296 | /* input selection */ | 311 | /* input selection */ |
297 | tvout_vip_set_sel_input(tvout, main_path, | 312 | tvout_vip_set_sel_input(tvout, TVO_VIP_HDMI, main_path, |
298 | sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB); | 313 | sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB); |
299 | } | 314 | } |
300 | 315 | ||
@@ -309,48 +324,47 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path) | |||
309 | { | 324 | { |
310 | struct device_node *node = tvout->dev->of_node; | 325 | struct device_node *node = tvout->dev->of_node; |
311 | bool sel_input_logic_inverted = false; | 326 | bool sel_input_logic_inverted = false; |
327 | u32 tvo_in_vid_format; | ||
328 | int val; | ||
312 | 329 | ||
313 | dev_dbg(tvout->dev, "%s\n", __func__); | 330 | dev_dbg(tvout->dev, "%s\n", __func__); |
314 | 331 | ||
315 | if (!main_path) { | 332 | if (main_path) { |
316 | DRM_ERROR("HD Analog on aux not implemented\n"); | 333 | val = TVO_SYNC_MAIN_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT; |
317 | return; | 334 | val |= TVO_SYNC_MAIN_VTG_SET_3; |
335 | tvout_write(tvout, val, TVO_HD_SYNC_SEL); | ||
336 | tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT; | ||
337 | } else { | ||
338 | val = TVO_SYNC_AUX_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT; | ||
339 | val |= TVO_SYNC_AUX_VTG_SET_3; | ||
340 | tvout_write(tvout, val, TVO_HD_SYNC_SEL); | ||
341 | tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT; | ||
318 | } | 342 | } |
319 | 343 | ||
320 | DRM_DEBUG_DRIVER("main vip for HDF\n"); | ||
321 | |||
322 | /* set color channel order */ | 344 | /* set color channel order */ |
323 | tvout_vip_set_color_order(tvout->regs + TVO_VIP_HDF, | 345 | tvout_vip_set_color_order(tvout, TVO_VIP_HDF, |
324 | TVO_VIP_REORDER_CR_R_SEL, | 346 | TVO_VIP_REORDER_CR_R_SEL, |
325 | TVO_VIP_REORDER_Y_G_SEL, | 347 | TVO_VIP_REORDER_Y_G_SEL, |
326 | TVO_VIP_REORDER_CB_B_SEL); | 348 | TVO_VIP_REORDER_CB_B_SEL); |
327 | 349 | ||
328 | /* set clipping mode (Limited range RGB/Y) */ | 350 | /* set clipping mode (EAV/SAV clipping) */ |
329 | tvout_vip_set_clip_mode(tvout->regs + TVO_VIP_HDF, | 351 | tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_EAV_SAV); |
330 | TVO_VIP_CLIP_LIMITED_RANGE_CB_CR); | ||
331 | 352 | ||
332 | /* set round mode (rounded to 10-bit per component) */ | 353 | /* set round mode (rounded to 10-bit per component) */ |
333 | tvout_vip_set_rnd(tvout->regs + TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED); | 354 | tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED); |
334 | 355 | ||
335 | if (of_device_is_compatible(node, "st,stih407-tvout")) { | 356 | if (of_device_is_compatible(node, "st,stih407-tvout")) { |
336 | /* set input video format */ | 357 | /* set input video format */ |
337 | tvout_vip_set_in_vid_fmt(tvout, TVO_IN_FMT_SIGNED); | 358 | tvout_vip_set_in_vid_fmt(tvout, |
359 | tvo_in_vid_format, TVO_IN_FMT_SIGNED); | ||
338 | sel_input_logic_inverted = true; | 360 | sel_input_logic_inverted = true; |
339 | } | 361 | } |
340 | 362 | ||
341 | /* Input selection */ | 363 | /* Input selection */ |
342 | tvout_vip_set_sel_input(tvout->regs + TVO_VIP_HDF, | 364 | tvout_vip_set_sel_input(tvout, TVO_VIP_HDF, main_path, |
343 | main_path, | ||
344 | sel_input_logic_inverted, | 365 | sel_input_logic_inverted, |
345 | STI_TVOUT_VIDEO_OUT_YUV); | 366 | STI_TVOUT_VIDEO_OUT_YUV); |
346 | 367 | ||
347 | /* select the input sync for HD analog = VTG set 3 | ||
348 | * and HD DCS = VTG set 2 */ | ||
349 | tvout_write(tvout, | ||
350 | (TVO_SYNC_MAIN_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT) | ||
351 | | TVO_SYNC_MAIN_VTG_SET_3, | ||
352 | TVO_HD_SYNC_SEL); | ||
353 | |||
354 | /* power up HD DAC */ | 368 | /* power up HD DAC */ |
355 | tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); | 369 | tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); |
356 | } | 370 | } |
@@ -392,7 +406,7 @@ static void sti_hda_encoder_commit(struct drm_encoder *encoder) | |||
392 | { | 406 | { |
393 | struct sti_tvout *tvout = to_sti_tvout(encoder); | 407 | struct sti_tvout *tvout = to_sti_tvout(encoder); |
394 | 408 | ||
395 | tvout_hda_start(tvout, true); | 409 | tvout_hda_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); |
396 | } | 410 | } |
397 | 411 | ||
398 | static void sti_hda_encoder_disable(struct drm_encoder *encoder) | 412 | static void sti_hda_encoder_disable(struct drm_encoder *encoder) |
@@ -429,7 +443,7 @@ static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, | |||
429 | 443 | ||
430 | drm_encoder = (struct drm_encoder *) encoder; | 444 | drm_encoder = (struct drm_encoder *) encoder; |
431 | 445 | ||
432 | drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK; | 446 | drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; |
433 | drm_encoder->possible_clones = 1 << 0; | 447 | drm_encoder->possible_clones = 1 << 0; |
434 | 448 | ||
435 | drm_encoder_init(dev, drm_encoder, | 449 | drm_encoder_init(dev, drm_encoder, |
@@ -444,7 +458,7 @@ static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) | |||
444 | { | 458 | { |
445 | struct sti_tvout *tvout = to_sti_tvout(encoder); | 459 | struct sti_tvout *tvout = to_sti_tvout(encoder); |
446 | 460 | ||
447 | tvout_hdmi_start(tvout, true); | 461 | tvout_hdmi_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); |
448 | } | 462 | } |
449 | 463 | ||
450 | static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) | 464 | static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) |
@@ -478,7 +492,7 @@ static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev, | |||
478 | 492 | ||
479 | drm_encoder = (struct drm_encoder *) encoder; | 493 | drm_encoder = (struct drm_encoder *) encoder; |
480 | 494 | ||
481 | drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK; | 495 | drm_encoder->possible_crtcs = ENCODER_CRTC_MASK; |
482 | drm_encoder->possible_clones = 1 << 1; | 496 | drm_encoder->possible_clones = 1 << 1; |
483 | 497 | ||
484 | drm_encoder_init(dev, drm_encoder, | 498 | drm_encoder_init(dev, drm_encoder, |