1111#include <linux/delay.h>
1212#include <linux/interrupt.h>
1313#include <linux/platform_device.h>
14- #include <linux/printk.h>
1514#include <drm/drm_fourcc.h>
1615#include <drm/drm_print.h>
1716#include <drm/drm_vblank.h>
@@ -82,13 +81,13 @@ static const struct rp1vec_ipixfmt my_formats[] = {
8281/*
8382 * Hardware mode descriptions (@ 108 MHz clock rate).
8483 * These rely largely on "canned" register settings.
85- * TODO: Port the generating software from FP to integer,
86- * or better factorize the differences between modes.
8784 */
8885
8986struct rp1vec_hwmode {
90- u16 total_cols ; /* active columns, plus padding for filter context */
87+ u16 total_cols ; /* max active columns incl. padding and windowing */
9188 u16 rows_per_field ; /* active lines per field (including partial ones) */
89+ u16 ref_hfp ; /* nominal (hsync_start - hdisplay) when max width */
90+ u16 ref_vfp ; /* nominal (vsync_start - vdisplay) when max height */
9291 bool interlaced ; /* set for interlaced */
9392 bool first_field_odd ; /* set for interlaced and 30fps */
9493 u32 yuv_scaling ; /* three 10-bit fields {Y, U, V} in 2.8 format */
@@ -103,6 +102,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
103102 {
104103 .total_cols = 724 ,
105104 .rows_per_field = 240 ,
105+ .ref_hfp = 12 ,
106+ .ref_vfp = 2 ,
106107 .interlaced = false,
107108 .first_field_odd = false,
108109 .yuv_scaling = 0x1071d0cf ,
@@ -118,6 +119,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
118119 }, {
119120 .total_cols = 815 ,
120121 .rows_per_field = 240 ,
122+ .ref_hfp = 16 ,
123+ .ref_vfp = 2 ,
121124 .interlaced = false,
122125 .first_field_odd = false,
123126 .yuv_scaling = 0x1c131962 ,
@@ -135,6 +138,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
135138 {
136139 .total_cols = 724 ,
137140 .rows_per_field = 243 ,
141+ .ref_hfp = 12 ,
142+ .ref_vfp = 3 ,
138143 .interlaced = true,
139144 .first_field_odd = true,
140145 .yuv_scaling = 0x1071d0cf ,
@@ -150,6 +155,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
150155 }, {
151156 .total_cols = 815 ,
152157 .rows_per_field = 243 ,
158+ .ref_hfp = 16 ,
159+ .ref_vfp = 3 ,
153160 .interlaced = true,
154161 .first_field_odd = true,
155162 .yuv_scaling = 0x1c131962 ,
@@ -170,6 +177,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
170177 {
171178 .total_cols = 724 ,
172179 .rows_per_field = 288 ,
180+ .ref_hfp = 16 ,
181+ .ref_vfp = 2 ,
173182 .interlaced = false,
174183 .first_field_odd = false,
175184 .yuv_scaling = 0x11c1f8e0 ,
@@ -185,6 +194,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
185194 }, {
186195 .total_cols = 804 ,
187196 .rows_per_field = 288 ,
197+ .ref_hfp = 24 ,
198+ .ref_vfp = 2 ,
188199 .interlaced = false,
189200 .first_field_odd = false,
190201 .yuv_scaling = 0x1e635d7f ,
@@ -202,6 +213,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
202213 {
203214 .total_cols = 724 ,
204215 .rows_per_field = 288 ,
216+ .ref_hfp = 16 ,
217+ .ref_vfp = 5 ,
205218 .interlaced = true,
206219 .first_field_odd = false,
207220 .yuv_scaling = 0x11c1f8e0 ,
@@ -217,6 +230,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
217230 }, {
218231 .total_cols = 804 ,
219232 .rows_per_field = 288 ,
233+ .ref_hfp = 24 ,
234+ .ref_vfp = 5 ,
220235 .interlaced = true,
221236 .first_field_odd = false,
222237 .yuv_scaling = 0x1e635d7f ,
@@ -237,6 +252,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
237252 {
238253 .total_cols = 724 ,
239254 .rows_per_field = 240 ,
255+ .ref_hfp = 12 ,
256+ .ref_vfp = 2 ,
240257 .interlaced = false,
241258 .first_field_odd = false,
242259 .yuv_scaling = 0x11c1f8e0 ,
@@ -252,6 +269,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
252269 }, {
253270 .total_cols = 815 ,
254271 .rows_per_field = 240 ,
272+ .ref_hfp = 16 ,
273+ .ref_vfp = 2 ,
255274 .interlaced = false,
256275 .first_field_odd = false,
257276 .yuv_scaling = 0x1e635d7f ,
@@ -269,6 +288,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
269288 {
270289 .total_cols = 724 ,
271290 .rows_per_field = 243 ,
291+ .ref_hfp = 12 ,
292+ .ref_vfp = 3 ,
272293 .interlaced = true,
273294 .first_field_odd = true,
274295 .yuv_scaling = 0x11c1f8e0 ,
@@ -284,6 +305,8 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2][2] = {
284305 }, {
285306 .total_cols = 815 ,
286307 .rows_per_field = 243 ,
308+ .ref_hfp = 16 ,
309+ .ref_vfp = 3 ,
287310 .interlaced = true,
288311 .first_field_odd = true,
289312 .yuv_scaling = 0x1e635d7f ,
@@ -308,11 +331,11 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
308331{
309332 unsigned int i , mode_family , mode_ilaced , mode_narrow ;
310333 const struct rp1vec_hwmode * hwm ;
311- unsigned int w , h ;
334+ int w , h , hpad , vpad ;
312335
313336 /* Pick the appropriate "base" mode, which we may modify */
314337 mode_ilaced = !!(mode -> flags & DRM_MODE_FLAG_INTERLACE );
315- if (mode -> vtotal > 263 * (1 + mode_ilaced ))
338+ if (mode -> vtotal >= 272 * (1 + mode_ilaced ))
316339 mode_family = 1 ;
317340 else
318341 mode_family = (tvstd == RP1VEC_TVSTD_PAL_M || tvstd == RP1VEC_TVSTD_PAL60 ) ? 2 : 0 ;
@@ -326,13 +349,28 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
326349 tvstd , rp1vec_tvstd_names [tvstd ]);
327350
328351 w = mode -> hdisplay ;
329- h = mode -> vdisplay ;
330- if (mode_ilaced )
331- h >>= 1 ;
352+ h = mode -> vdisplay >> mode_ilaced ;
332353 if (w > hwm -> total_cols )
333354 w = hwm -> total_cols ;
334355 if (h > hwm -> rows_per_field )
335- w = hwm -> rows_per_field ;
356+ h = hwm -> rows_per_field ;
357+
358+ /*
359+ * Add padding so a framebuffer with the given dimensions and
360+ * [hv]sync_start can be displayed in the chosen hardware mode.
361+ *
362+ * |<----- mode->hsync_start ----->|
363+ * |<------ w ------>| |
364+ * | | >|--|< ref_hfp
365+ * |<- hpad ->|
366+ * |<------------ total_cols ----------->|
367+ * ________FRAMEBUFFERCONTENTS__________
368+ * ' `--\____/-<\/\/\>-'
369+ */
370+ hpad = max (0 , mode -> hsync_start - hwm -> ref_hfp - w );
371+ hpad = min (hpad , hwm -> total_cols - w );
372+ vpad = max (0 , ((mode -> vsync_start - hwm -> ref_vfp ) >> mode_ilaced ) - h );
373+ vpad = min (vpad , hwm -> rows_per_field - h );
336374
337375 /* Configure the hardware */
338376 VEC_WRITE (VEC_APB_TIMEOUT , 0x38 );
@@ -347,18 +385,18 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
347385 BITS (VEC_DMA_AREA_ROWS_PER_FIELD_MINUS1 , h - 1 ));
348386 VEC_WRITE (VEC_YUV_SCALING , hwm -> yuv_scaling );
349387 VEC_WRITE (VEC_BACK_PORCH ,
350- BITS (VEC_BACK_PORCH_HBP_MINUS1 , ( hwm -> total_cols - w - 1 ) >> 1 ) |
351- BITS (VEC_BACK_PORCH_VBP_MINUS1 , ( hwm -> rows_per_field - h - 1 ) >> 1 ));
388+ BITS (VEC_BACK_PORCH_HBP_MINUS1 , hwm -> total_cols - w - hpad - 1 ) |
389+ BITS (VEC_BACK_PORCH_VBP_MINUS1 , hwm -> rows_per_field - h - vpad - 1 ));
352390 VEC_WRITE (VEC_FRONT_PORCH ,
353- BITS (VEC_FRONT_PORCH_HFP_MINUS1 , ( hwm -> total_cols - w - 2 ) >> 1 ) |
354- BITS (VEC_FRONT_PORCH_VFP_MINUS1 , ( hwm -> rows_per_field - h - 2 ) >> 1 ));
391+ BITS (VEC_FRONT_PORCH_HFP_MINUS1 , hpad - 1 ) |
392+ BITS (VEC_FRONT_PORCH_VFP_MINUS1 , vpad - 1 ));
355393 VEC_WRITE (VEC_MODE ,
356394 BITS (VEC_MODE_HIGH_WATER , 0xE0 ) |
357395 BITS (VEC_MODE_ALIGN16 , !((w | mode -> hdisplay ) & 15 )) |
358- BITS (VEC_MODE_VFP_EN , (hwm -> rows_per_field > h + 1 )) |
359- BITS (VEC_MODE_VBP_EN , (hwm -> rows_per_field > h )) |
360- BITS (VEC_MODE_HFP_EN , (hwm -> total_cols > w + 1 )) |
361- BITS (VEC_MODE_HBP_EN , (hwm -> total_cols > w )) |
396+ BITS (VEC_MODE_VFP_EN , (vpad > 0 )) |
397+ BITS (VEC_MODE_VBP_EN , (hwm -> rows_per_field > h + vpad )) |
398+ BITS (VEC_MODE_HFP_EN , (hpad > 0 )) |
399+ BITS (VEC_MODE_HBP_EN , (hwm -> total_cols > w + hpad )) |
362400 BITS (VEC_MODE_FIELDS_PER_FRAME_MINUS1 , hwm -> interlaced ) |
363401 BITS (VEC_MODE_FIRST_FIELD_ODD , hwm -> first_field_odd ));
364402 for (i = 0 ; i < ARRAY_SIZE (hwm -> back_end_regs ); ++ i ) {
0 commit comments