@@ -61,12 +61,8 @@ __FBSDID("$FreeBSD$");
61
61
#include "fb_if.h"
62
62
#include "hdmi_if.h"
63
63
64
- #define EDID_DEBUG_not
65
-
66
64
static int have_ipu = 0 ;
67
65
68
- #define LDB_CLOCK_RATE 280000000
69
-
70
66
#define MODE_HBP (mode ) ((mode)->htotal - (mode)->hsync_end)
71
67
#define MODE_HFP (mode ) ((mode)->hsync_start - (mode)->hdisplay)
72
68
#define MODE_HSW (mode ) ((mode)->hsync_end - (mode)->hsync_start)
@@ -77,11 +73,6 @@ static int have_ipu = 0;
77
73
#define MODE_BPP 16
78
74
#define MODE_PIXEL_CLOCK_INVERT 1
79
75
80
- #define M (nm ,hr ,vr ,clk ,hs ,he ,ht ,vs ,ve ,vt ,f ) \
81
- { clk, hr, hs, he, ht, vr, vs, ve, vt, f, nm }
82
-
83
- static struct videomode mode1024x768 = M ("1024x768x60" ,1024 ,768 ,65000 ,1048 ,1184 ,1344 ,771 ,777 ,806 ,VID_NHSYNC |VID_PHSYNC );
84
-
85
76
#define DMA_CHANNEL 23
86
77
#define DC_CHAN5 5
87
78
#define DI_PORT 0
@@ -384,7 +375,7 @@ struct ipu_softc {
384
375
void * sc_intr_hl ;
385
376
struct mtx sc_mtx ;
386
377
struct fb_info sc_fb_info ;
387
- struct videomode * sc_mode ;
378
+ const struct videomode * sc_mode ;
388
379
389
380
/* Framebuffer */
390
381
bus_dma_tag_t sc_dma_tag ;
@@ -634,36 +625,49 @@ ipu_init_microcode_template(struct ipu_softc *sc, int di, int map)
634
625
}
635
626
}
636
627
628
+ static uint32_t
629
+ ipu_calc_divisor (uint32_t reference , uint32_t freq )
630
+ {
631
+ uint32_t div , i ;
632
+ uint32_t delta , min_delta ;
633
+
634
+ min_delta = freq ;
635
+ div = 255 ;
636
+
637
+ for (i = 1 ; i < 255 ; i ++ ) {
638
+ delta = abs (reference /i - freq );
639
+ if (delta < min_delta ) {
640
+ div = i ;
641
+ min_delta = delta ;
642
+ }
643
+ }
644
+
645
+ return (div );
646
+ }
647
+
637
648
static void
638
649
ipu_config_timing (struct ipu_softc * sc , int di )
639
650
{
640
- int div ;
651
+ uint32_t div ;
641
652
uint32_t di_scr_conf ;
642
653
uint32_t gen_offset , gen ;
643
654
uint32_t as_gen_offset , as_gen ;
644
655
uint32_t dw_gen_offset , dw_gen ;
645
656
uint32_t dw_set_offset , dw_set ;
646
657
uint32_t bs_clkgen_offset ;
647
658
int map ;
659
+ uint32_t freq ;
660
+
661
+ freq = sc -> sc_mode -> dot_clock * 1000 ;
648
662
649
- /* TODO: check mode restrictions / fixup */
650
- /* TODO: enable timers, get divisors */
651
- div = 1 ;
663
+ div = ipu_calc_divisor (imx_ccm_ipu_hz (), freq );
652
664
map = 0 ;
653
665
654
666
bs_clkgen_offset = di ? IPU_DI1_BS_CLKGEN0 : IPU_DI0_BS_CLKGEN0 ;
655
667
IPU_WRITE4 (sc , bs_clkgen_offset , DI_BS_CLKGEN0 (div , 0 ));
656
668
/* half of the divider */
657
669
IPU_WRITE4 (sc , bs_clkgen_offset + 4 , DI_BS_CLKGEN1_DOWN (div / 2 , div % 2 ));
658
670
659
- /*
660
- * TODO: Configure LLDB clock by changing following fields
661
- * in CCM fields:
662
- * CS2CDR_LDB_DI0_CLK_SEL
663
- * CSCMR2_LDB_DI0_IPU_DIV
664
- * CBCDR_MMDC_CH1_AXI_PODF
665
- */
666
-
667
671
/* Setup wave generator */
668
672
dw_gen_offset = di ? IPU_DI1_DW_GEN_0 : IPU_DI0_DW_GEN_0 ;
669
673
dw_gen = DW_GEN_DI_ACCESS_SIZE (div - 1 ) | DW_GEN_DI_COMPONENT_SIZE (div - 1 );
@@ -768,8 +772,6 @@ ipu_dc_enable(struct ipu_softc *sc)
768
772
conf &= ~WRITE_CH_CONF_PROG_CHAN_TYP_MASK ;
769
773
conf |= WRITE_CH_CONF_PROG_CHAN_NORMAL ;
770
774
IPU_WRITE4 (sc , DC_WRITE_CH_CONF_5 , conf );
771
-
772
- /* TODO: enable clock */
773
775
}
774
776
775
777
static void
@@ -1063,15 +1065,55 @@ ipu_init(struct ipu_softc *sc)
1063
1065
return (err );
1064
1066
}
1065
1067
1068
+ static int
1069
+ ipu_mode_is_valid (const struct videomode * mode )
1070
+ {
1071
+ if ((mode -> dot_clock < 13500 ) || (mode -> dot_clock > 216000 ))
1072
+ return (0 );
1073
+
1074
+ return (1 );
1075
+ }
1076
+
1077
+ static const struct videomode *
1078
+ ipu_pick_mode (struct edid_info * ei )
1079
+ {
1080
+ const struct videomode * videomode ;
1081
+ const struct videomode * m ;
1082
+ int n ;
1083
+
1084
+ videomode = NULL ;
1085
+
1086
+ /*
1087
+ * Pick a mode.
1088
+ */
1089
+ if (ei -> edid_preferred_mode != NULL ) {
1090
+ if (ipu_mode_is_valid (ei -> edid_preferred_mode ))
1091
+ videomode = ei -> edid_preferred_mode ;
1092
+ }
1093
+
1094
+ if (videomode == NULL ) {
1095
+ m = ei -> edid_modes ;
1096
+
1097
+ sort_modes (ei -> edid_modes ,
1098
+ & ei -> edid_preferred_mode ,
1099
+ ei -> edid_nmodes );
1100
+ for (n = 0 ; n < ei -> edid_nmodes ; n ++ )
1101
+ if (ipu_mode_is_valid (& m [n ])) {
1102
+ videomode = & m [n ];
1103
+ break ;
1104
+ }
1105
+ }
1106
+
1107
+ return videomode ;
1108
+ }
1109
+
1066
1110
static void
1067
1111
ipu_hdmi_event (void * arg , device_t hdmi_dev )
1068
1112
{
1069
1113
struct ipu_softc * sc ;
1070
1114
uint8_t * edid ;
1071
1115
uint32_t edid_len ;
1072
- #ifdef EDID_DEBUG
1073
1116
struct edid_info ei ;
1074
- #endif
1075
1117
const struct videomode * videomode ;
1076
1118
1077
1119
sc = arg ;
@@ -1084,14 +1126,28 @@ ipu_hdmi_event(void *arg, device_t hdmi_dev)
1084
1126
1085
1127
videomode = NULL ;
1086
1128
1087
- #ifdef EDID_DEBUG
1088
1129
if ( edid && (edid_parse (edid , & ei ) == 0 )) {
1089
- edid_print (& ei );
1130
+ if (bootverbose )
1131
+ edid_print (& ei );
1132
+ videomode = ipu_pick_mode (& ei );
1090
1133
} else
1091
1134
device_printf (sc -> sc_dev , "failed to parse EDID\n" );
1092
- #endif
1093
1135
1094
- sc -> sc_mode = & mode1024x768 ;
1136
+ /* Use standard VGA as fallback */
1137
+ if (videomode == NULL )
1138
+ videomode = pick_mode_by_ref (640 , 480 , 60 );
1139
+
1140
+ if (videomode == NULL ) {
1141
+ device_printf (sc -> sc_dev , "failed to find usable videomode\n" );
1142
+ return ;
1143
+ }
1144
+
1145
+ sc -> sc_mode = videomode ;
1146
+
1147
+ if (bootverbose )
1148
+ device_printf (sc -> sc_dev , "detected videomode: %dx%d\n" ,
1149
+ videomode -> hdisplay , videomode -> vdisplay );
1150
+
1095
1151
ipu_init (sc );
1096
1152
1097
1153
HDMI_SET_VIDEOMODE (hdmi_dev , sc -> sc_mode );
@@ -1145,9 +1201,22 @@ ipu_attach(device_t dev)
1145
1201
}
1146
1202
1147
1203
/* Enable IPU1 */
1204
+ if (imx_ccm_pll_video_enable () != 0 ) {
1205
+ bus_release_resource (dev , SYS_RES_MEMORY ,
1206
+ sc -> sc_mem_rid , sc -> sc_mem_res );
1207
+ bus_release_resource (dev , SYS_RES_IRQ ,
1208
+ sc -> sc_irq_rid , sc -> sc_irq_res );
1209
+ device_printf (dev , "failed to set up video PLL\n" );
1210
+ return (ENXIO );
1211
+ }
1212
+
1148
1213
imx_ccm_ipu_enable (1 );
1149
1214
1150
1215
if (src_reset_ipu () != 0 ) {
1216
+ bus_release_resource (dev , SYS_RES_MEMORY ,
1217
+ sc -> sc_mem_rid , sc -> sc_mem_res );
1218
+ bus_release_resource (dev , SYS_RES_IRQ ,
1219
+ sc -> sc_irq_rid , sc -> sc_irq_res );
1151
1220
device_printf (dev , "failed to reset IPU\n" );
1152
1221
return (ENXIO );
1153
1222
}
0 commit comments