Commit 39920c81ce4431b7ea08f5e80feb5ec8b156864e

Authored by Hans de Goede
1 parent f6d9d32462

sunxi: display: Add composite video out support

Add composite video out support.

This only gets enabled on the Mele M3 for now, since that is were it
was tested. It will be enabled on more boards after testing.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>

Showing 4 changed files with 191 additions and 24 deletions Side-by-side Diff

... ... @@ -410,6 +410,13 @@
410 410 Set the enable pin for the external VGA DAC. This takes a string in the
411 411 format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
412 412  
  413 +config VIDEO_COMPOSITE
  414 + boolean "Composite video output support"
  415 + depends on VIDEO && (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I)
  416 + default n
  417 + ---help---
  418 + Say Y here to add support for outputting composite video.
  419 +
413 420 config VIDEO_LCD_MODE
414 421 string "LCD panel timing details"
415 422 depends on VIDEO
configs/Mele_M3_defconfig
... ... @@ -5,6 +5,7 @@
5 5 CONFIG_MMC0_CD_PIN="PH1"
6 6 CONFIG_MMC_SUNXI_SLOT_EXTRA=2
7 7 CONFIG_VIDEO_VGA=y
  8 +CONFIG_VIDEO_COMPOSITE=y
8 9 CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-m3"
9 10 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
10 11 CONFIG_SPL=y
... ... @@ -40,12 +40,15 @@
40 40  
41 41 The sunxi u-boot driver supports the following video-mode options:
42 42  
43   -- monitor=[none|dvi|hdmi|lcd] - Select the video output to use
  43 +- monitor=[none|dvi|hdmi|lcd|vga|composite-*] - Select the video output to use
44 44 none: Disable video output.
45 45 dvi/hdmi: Selects output over the hdmi connector with dvi resp. hdmi output
46 46 format, if edid is used the format is automatically selected.
47 47 lcd: Selects video output to a LCD screen.
48   - vga: Selects bideo output over the VGA connector.
  48 + vga: Selects video output over the VGA connector.
  49 + composite-pal/composite-ntsc/composite-pal-m/composite-pal-nc:
  50 + Selects composite video output, note the specified resolution is
  51 + ignored with composite video output.
49 52 Defaults to monitor=dvi.
50 53  
51 54 - hpd=[0|1] - Enable use of the hdmi HotPlug Detect feature
drivers/video/sunxi_display.c
... ... @@ -2,7 +2,7 @@
2 2 * Display driver for Allwinner SoCs.
3 3 *
4 4 * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
5   - * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
  5 + * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
6 6 *
7 7 * SPDX-License-Identifier: GPL-2.0+
8 8 */
9 9  
... ... @@ -40,8 +40,12 @@
40 40 sunxi_monitor_hdmi,
41 41 sunxi_monitor_lcd,
42 42 sunxi_monitor_vga,
  43 + sunxi_monitor_composite_pal,
  44 + sunxi_monitor_composite_ntsc,
  45 + sunxi_monitor_composite_pal_m,
  46 + sunxi_monitor_composite_pal_nc,
43 47 };
44   -#define SUNXI_MONITOR_LAST sunxi_monitor_vga
  48 +#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc
45 49  
46 50 struct sunxi_display {
47 51 GraphicDevice graphic_device;
... ... @@ -50,6 +54,12 @@
50 54 unsigned int fb_size;
51 55 } sunxi_display;
52 56  
  57 +const struct ctfb_res_modes composite_video_modes[2] = {
  58 + /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */
  59 + { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED },
  60 + { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED },
  61 +};
  62 +
53 63 #ifdef CONFIG_VIDEO_HDMI
54 64  
55 65 /*
... ... @@ -390,6 +400,25 @@
390 400 static void sunxi_frontend_enable(void) {}
391 401 #endif
392 402  
  403 +static bool sunxi_is_composite(void)
  404 +{
  405 + switch (sunxi_display.monitor) {
  406 + case sunxi_monitor_none:
  407 + case sunxi_monitor_dvi:
  408 + case sunxi_monitor_hdmi:
  409 + case sunxi_monitor_lcd:
  410 + case sunxi_monitor_vga:
  411 + return false;
  412 + case sunxi_monitor_composite_pal:
  413 + case sunxi_monitor_composite_ntsc:
  414 + case sunxi_monitor_composite_pal_m:
  415 + case sunxi_monitor_composite_pal_nc:
  416 + return true;
  417 + }
  418 +
  419 + return false; /* Never reached */
  420 +}
  421 +
393 422 /*
394 423 * This is the entity that mixes and matches the different layers and inputs.
395 424 * Allwinner calls it the back-end, but i like composer better.
396 425  
... ... @@ -423,11 +452,18 @@
423 452 setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE);
424 453 }
425 454  
  455 +static u32 sunxi_rgb2yuv_coef[12] = {
  456 + 0x00000107, 0x00000204, 0x00000064, 0x00000108,
  457 + 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
  458 + 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
  459 +};
  460 +
426 461 static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode,
427 462 unsigned int address)
428 463 {
429 464 struct sunxi_de_be_reg * const de_be =
430 465 (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE;
  466 + int i;
431 467  
432 468 sunxi_frontend_mode_set(mode, address);
433 469  
... ... @@ -449,6 +485,14 @@
449 485 setbits_le32(&de_be->mode,
450 486 SUNXI_DE_BE_MODE_DEFLICKER_ENABLE |
451 487 SUNXI_DE_BE_MODE_INTERLACE_ENABLE);
  488 +
  489 + if (sunxi_is_composite()) {
  490 + writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE,
  491 + &de_be->output_color_ctrl);
  492 + for (i = 0; i < 12; i++)
  493 + writel(sunxi_rgb2yuv_coef[i],
  494 + &de_be->output_color_coef[i]);
  495 + }
452 496 }
453 497  
454 498 static void sunxi_composer_enable(void)
... ... @@ -539,6 +583,9 @@
539 583 (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
540 584 CCM_LCD_CH1_CTRL_PLL3) |
541 585 CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
  586 + if (sunxi_is_composite())
  587 + setbits_le32(&ccm->lcd0_ch1_clk_cfg,
  588 + CCM_LCD_CH1_CTRL_HALF_SCLK1);
542 589 }
543 590  
544 591 *clk_div = best_m;
... ... @@ -766,7 +813,7 @@
766 813 writel(0, &lcdc->tcon0_io_tristate);
767 814 }
768 815  
769   -#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA
  816 +#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
770 817 static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
771 818 int *clk_div, int *clk_double,
772 819 bool use_portd_hvsync)
... ... @@ -827,7 +874,7 @@
827 874 }
828 875 sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
829 876 }
830   -#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */
  877 +#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */
831 878  
832 879 #ifdef CONFIG_VIDEO_HDMI
833 880  
834 881  
... ... @@ -941,9 +988,9 @@
941 988  
942 989 #endif /* CONFIG_VIDEO_HDMI */
943 990  
944   -#ifdef CONFIG_VIDEO_VGA
  991 +#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE
945 992  
946   -static void sunxi_vga_mode_set(void)
  993 +static void sunxi_tvencoder_mode_set(void)
947 994 {
948 995 struct sunxi_ccm_reg * const ccm =
949 996 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
950 997  
... ... @@ -953,16 +1000,75 @@
953 1000 /* Clock on */
954 1001 setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0);
955 1002  
956   - /* Set TVE in VGA mode */
957   - writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
958   - SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
959   - SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
960   - writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
961   - writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
962   - writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
  1003 + switch (sunxi_display.monitor) {
  1004 + case sunxi_monitor_vga:
  1005 + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
  1006 + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
  1007 + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
  1008 + writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
  1009 + writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
  1010 + writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
  1011 + break;
  1012 + case sunxi_monitor_composite_pal_nc:
  1013 + writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
  1014 + /* Fall through */
  1015 + case sunxi_monitor_composite_pal:
  1016 + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
  1017 + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
  1018 + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
  1019 + SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
  1020 + writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
  1021 + writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
  1022 + writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
  1023 + writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
  1024 + writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
  1025 + writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
  1026 + writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
  1027 + writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
  1028 + writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
  1029 + writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
  1030 + writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
  1031 + writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
  1032 + writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
  1033 + writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
  1034 + writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
  1035 + break;
  1036 + case sunxi_monitor_composite_pal_m:
  1037 + writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
  1038 + writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
  1039 + /* Fall through */
  1040 + case sunxi_monitor_composite_ntsc:
  1041 + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
  1042 + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
  1043 + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
  1044 + SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
  1045 + writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
  1046 + writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
  1047 + writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
  1048 + writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
  1049 + writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
  1050 + writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
  1051 + writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
  1052 + writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
  1053 + writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
  1054 + writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
  1055 + writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
  1056 + writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
  1057 + writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
  1058 + writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
  1059 + writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
  1060 + writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
  1061 + writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
  1062 + break;
  1063 + case sunxi_monitor_none:
  1064 + case sunxi_monitor_dvi:
  1065 + case sunxi_monitor_hdmi:
  1066 + case sunxi_monitor_lcd:
  1067 + break;
  1068 + }
963 1069 }
964 1070  
965   -static void sunxi_vga_enable(void)
  1071 +static void sunxi_tvencoder_enable(void)
966 1072 {
967 1073 struct sunxi_tve_reg * const tve =
968 1074 (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
... ... @@ -970,7 +1076,7 @@
970 1076 setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
971 1077 }
972 1078  
973   -#endif /* CONFIG_VIDEO_VGA */
  1079 +#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
974 1080  
975 1081 static void sunxi_drc_init(void)
976 1082 {
977 1083  
... ... @@ -1085,10 +1191,10 @@
1085 1191 #ifdef CONFIG_VIDEO_VGA
1086 1192 sunxi_composer_mode_set(mode, address);
1087 1193 sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1);
1088   - sunxi_vga_mode_set();
  1194 + sunxi_tvencoder_mode_set();
1089 1195 sunxi_composer_enable();
1090 1196 sunxi_lcdc_enable();
1091   - sunxi_vga_enable();
  1197 + sunxi_tvencoder_enable();
1092 1198 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1093 1199 sunxi_composer_mode_set(mode, address);
1094 1200 sunxi_lcdc_tcon0_mode_set(mode, true);
1095 1201  
... ... @@ -1097,17 +1203,34 @@
1097 1203 sunxi_vga_external_dac_enable();
1098 1204 #endif
1099 1205 break;
  1206 + case sunxi_monitor_composite_pal:
  1207 + case sunxi_monitor_composite_ntsc:
  1208 + case sunxi_monitor_composite_pal_m:
  1209 + case sunxi_monitor_composite_pal_nc:
  1210 +#ifdef CONFIG_VIDEO_COMPOSITE
  1211 + sunxi_composer_mode_set(mode, address);
  1212 + sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0);
  1213 + sunxi_tvencoder_mode_set();
  1214 + sunxi_composer_enable();
  1215 + sunxi_lcdc_enable();
  1216 + sunxi_tvencoder_enable();
  1217 +#endif
  1218 + break;
1100 1219 }
1101 1220 }
1102 1221  
1103 1222 static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
1104 1223 {
1105 1224 switch (monitor) {
1106   - case sunxi_monitor_none: return "none";
1107   - case sunxi_monitor_dvi: return "dvi";
1108   - case sunxi_monitor_hdmi: return "hdmi";
1109   - case sunxi_monitor_lcd: return "lcd";
1110   - case sunxi_monitor_vga: return "vga";
  1225 + case sunxi_monitor_none: return "none";
  1226 + case sunxi_monitor_dvi: return "dvi";
  1227 + case sunxi_monitor_hdmi: return "hdmi";
  1228 + case sunxi_monitor_lcd: return "lcd";
  1229 + case sunxi_monitor_vga: return "vga";
  1230 + case sunxi_monitor_composite_pal: return "composite-pal";
  1231 + case sunxi_monitor_composite_ntsc: return "composite-ntsc";
  1232 + case sunxi_monitor_composite_pal_m: return "composite-pal-m";
  1233 + case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
1111 1234 }
1112 1235 return NULL; /* never reached */
1113 1236 }
... ... @@ -1142,6 +1265,15 @@
1142 1265 #endif
1143 1266 }
1144 1267  
  1268 +static bool sunxi_has_composite(void)
  1269 +{
  1270 +#ifdef CONFIG_VIDEO_COMPOSITE
  1271 + return true;
  1272 +#else
  1273 + return false;
  1274 +#endif
  1275 +}
  1276 +
1145 1277 static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi)
1146 1278 {
1147 1279 if (allow_hdmi && sunxi_has_hdmi())
... ... @@ -1150,6 +1282,8 @@
1150 1282 return sunxi_monitor_lcd;
1151 1283 else if (sunxi_has_vga())
1152 1284 return sunxi_monitor_vga;
  1285 + else if (sunxi_has_composite())
  1286 + return sunxi_monitor_composite_pal;
1153 1287 else
1154 1288 return sunxi_monitor_none;
1155 1289 }
... ... @@ -1234,6 +1368,22 @@
1234 1368 }
1235 1369 sunxi_display.depth = 18;
1236 1370 break;
  1371 + case sunxi_monitor_composite_pal:
  1372 + case sunxi_monitor_composite_ntsc:
  1373 + case sunxi_monitor_composite_pal_m:
  1374 + case sunxi_monitor_composite_pal_nc:
  1375 + if (!sunxi_has_composite()) {
  1376 + printf("Composite video not supported on this board\n");
  1377 + sunxi_display.monitor = sunxi_monitor_none;
  1378 + return NULL;
  1379 + }
  1380 + if (sunxi_display.monitor == sunxi_monitor_composite_pal ||
  1381 + sunxi_display.monitor == sunxi_monitor_composite_pal_nc)
  1382 + mode = &composite_video_modes[0];
  1383 + else
  1384 + mode = &composite_video_modes[1];
  1385 + sunxi_display.depth = 24;
  1386 + break;
1237 1387 }
1238 1388  
1239 1389 sunxi_display.fb_size =
... ... @@ -1301,6 +1451,12 @@
1301 1451 #elif defined CONFIG_VIDEO_VGA_VIA_LCD
1302 1452 pipeline = PIPELINE_PREFIX "de_be0-lcd0";
1303 1453 #endif
  1454 + break;
  1455 + case sunxi_monitor_composite_pal:
  1456 + case sunxi_monitor_composite_ntsc:
  1457 + case sunxi_monitor_composite_pal_m:
  1458 + case sunxi_monitor_composite_pal_nc:
  1459 + pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0";
1304 1460 break;
1305 1461 }
1306 1462