aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2011-12-01 08:58:52 -0500
committerVinod Koul <vinod.koul@linux.intel.com>2011-12-08 02:29:03 -0500
commitf910fb8fcd1c97788f2291c8646597bcd87ee061 (patch)
treeb13f6aef306f3c708a6338bdbdaa3268d62d0508 /drivers/video
parentc99e78435342a65a6a0bf9b86f87fd05831858d2 (diff)
video i.MX IPU: Fix display connections
The IPU internally works on 32bit colors. It can arbitrarily map between pixel formats and internal representation and also between internal representation and the physical connection to the display. The driver used to change the mapping between internal representation and display connection depending on the user selected bpp which is wrong. Instead, the mapping is specified by the hardware, so an additional field in platform data is added to describe the connection between i.MX and the display. The default for this field is RGB666 which seems to be the only configuration which works without this patch, so I assumed that all in Kernel boards are connected this way. This patch has been tested on a RGB666 connected display and a RGB888 connected display in both 16bpp and 32bpp modes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/mx3fb.c61
1 files changed, 22 insertions, 39 deletions
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 1981e3665d07..727a5149d818 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -245,6 +245,7 @@ struct mx3fb_data {
245 245
246 uint32_t h_start_width; 246 uint32_t h_start_width;
247 uint32_t v_start_width; 247 uint32_t v_start_width;
248 enum disp_data_mapping disp_data_fmt;
248}; 249};
249 250
250struct dma_chan_request { 251struct dma_chan_request {
@@ -287,11 +288,14 @@ static void mx3fb_write_reg(struct mx3fb_data *mx3fb, u32 value, unsigned long r
287 __raw_writel(value, mx3fb->reg_base + reg); 288 __raw_writel(value, mx3fb->reg_base + reg);
288} 289}
289 290
290static const uint32_t di_mappings[] = { 291struct di_mapping {
291 0x1600AAAA, 0x00E05555, 0x00070000, 3, /* RGB888 */ 292 uint32_t b0, b1, b2;
292 0x0005000F, 0x000B000F, 0x0011000F, 1, /* RGB666 */ 293};
293 0x0011000F, 0x000B000F, 0x0005000F, 1, /* BGR666 */ 294
294 0x0004003F, 0x000A000F, 0x000F003F, 1 /* RGB565 */ 295static const struct di_mapping di_mappings[] = {
296 [IPU_DISP_DATA_MAPPING_RGB666] = { 0x0005000f, 0x000b000f, 0x0011000f },
297 [IPU_DISP_DATA_MAPPING_RGB565] = { 0x0004003f, 0x000a000f, 0x000f003f },
298 [IPU_DISP_DATA_MAPPING_RGB888] = { 0x00070000, 0x000f0000, 0x00170000 },
295}; 299};
296 300
297static void sdc_fb_init(struct mx3fb_info *fbi) 301static void sdc_fb_init(struct mx3fb_info *fbi)
@@ -425,7 +429,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
425 * @pixel_clk: desired pixel clock frequency in Hz. 429 * @pixel_clk: desired pixel clock frequency in Hz.
426 * @width: width of panel in pixels. 430 * @width: width of panel in pixels.
427 * @height: height of panel in pixels. 431 * @height: height of panel in pixels.
428 * @pixel_fmt: pixel format of buffer as FOURCC ASCII code.
429 * @h_start_width: number of pixel clocks between the HSYNC signal pulse 432 * @h_start_width: number of pixel clocks between the HSYNC signal pulse
430 * and the start of valid data. 433 * and the start of valid data.
431 * @h_sync_width: width of the HSYNC signal in units of pixel clocks. 434 * @h_sync_width: width of the HSYNC signal in units of pixel clocks.
@@ -442,7 +445,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
442static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, 445static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
443 uint32_t pixel_clk, 446 uint32_t pixel_clk,
444 uint16_t width, uint16_t height, 447 uint16_t width, uint16_t height,
445 enum pixel_fmt pixel_fmt,
446 uint16_t h_start_width, uint16_t h_sync_width, 448 uint16_t h_start_width, uint16_t h_sync_width,
447 uint16_t h_end_width, uint16_t v_start_width, 449 uint16_t h_end_width, uint16_t v_start_width,
448 uint16_t v_sync_width, uint16_t v_end_width, 450 uint16_t v_sync_width, uint16_t v_end_width,
@@ -453,6 +455,7 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
453 uint32_t old_conf; 455 uint32_t old_conf;
454 uint32_t div; 456 uint32_t div;
455 struct clk *ipu_clk; 457 struct clk *ipu_clk;
458 const struct di_mapping *map;
456 459
457 dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height); 460 dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height);
458 461
@@ -540,36 +543,10 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
540 sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT; 543 sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT;
541 mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL); 544 mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL);
542 545
543 switch (pixel_fmt) { 546 map = &di_mappings[mx3fb->disp_data_fmt];
544 case IPU_PIX_FMT_RGB24: 547 mx3fb_write_reg(mx3fb, map->b0, DI_DISP3_B0_MAP);
545 mx3fb_write_reg(mx3fb, di_mappings[0], DI_DISP3_B0_MAP); 548 mx3fb_write_reg(mx3fb, map->b1, DI_DISP3_B1_MAP);
546 mx3fb_write_reg(mx3fb, di_mappings[1], DI_DISP3_B1_MAP); 549 mx3fb_write_reg(mx3fb, map->b2, DI_DISP3_B2_MAP);
547 mx3fb_write_reg(mx3fb, di_mappings[2], DI_DISP3_B2_MAP);
548 mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
549 ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC);
550 break;
551 case IPU_PIX_FMT_RGB666:
552 mx3fb_write_reg(mx3fb, di_mappings[4], DI_DISP3_B0_MAP);
553 mx3fb_write_reg(mx3fb, di_mappings[5], DI_DISP3_B1_MAP);
554 mx3fb_write_reg(mx3fb, di_mappings[6], DI_DISP3_B2_MAP);
555 mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
556 ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC);
557 break;
558 case IPU_PIX_FMT_BGR666:
559 mx3fb_write_reg(mx3fb, di_mappings[8], DI_DISP3_B0_MAP);
560 mx3fb_write_reg(mx3fb, di_mappings[9], DI_DISP3_B1_MAP);
561 mx3fb_write_reg(mx3fb, di_mappings[10], DI_DISP3_B2_MAP);
562 mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
563 ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC);
564 break;
565 default:
566 mx3fb_write_reg(mx3fb, di_mappings[12], DI_DISP3_B0_MAP);
567 mx3fb_write_reg(mx3fb, di_mappings[13], DI_DISP3_B1_MAP);
568 mx3fb_write_reg(mx3fb, di_mappings[14], DI_DISP3_B2_MAP);
569 mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
570 ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC);
571 break;
572 }
573 550
574 spin_unlock_irqrestore(&mx3fb->lock, lock_flags); 551 spin_unlock_irqrestore(&mx3fb->lock, lock_flags);
575 552
@@ -780,8 +757,6 @@ static int __set_par(struct fb_info *fbi, bool lock)
780 if (sdc_init_panel(mx3fb, mode, 757 if (sdc_init_panel(mx3fb, mode,
781 (PICOS2KHZ(fbi->var.pixclock)) * 1000UL, 758 (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
782 fbi->var.xres, fbi->var.yres, 759 fbi->var.xres, fbi->var.yres,
783 (fbi->var.sync & FB_SYNC_SWAP_RGB) ?
784 IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666,
785 fbi->var.left_margin, 760 fbi->var.left_margin,
786 fbi->var.hsync_len, 761 fbi->var.hsync_len,
787 fbi->var.right_margin + 762 fbi->var.right_margin +
@@ -1349,6 +1324,12 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
1349 const struct fb_videomode *mode; 1324 const struct fb_videomode *mode;
1350 int ret, num_modes; 1325 int ret, num_modes;
1351 1326
1327 if (mx3fb_pdata->disp_data_fmt >= ARRAY_SIZE(di_mappings)) {
1328 dev_err(dev, "Illegal display data format %d\n",
1329 mx3fb_pdata->disp_data_fmt);
1330 return -EINVAL;
1331 }
1332
1352 ichan->client = mx3fb; 1333 ichan->client = mx3fb;
1353 irq = ichan->eof_irq; 1334 irq = ichan->eof_irq;
1354 1335
@@ -1402,6 +1383,8 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
1402 mx3fbi->mx3fb = mx3fb; 1383 mx3fbi->mx3fb = mx3fb;
1403 mx3fbi->blank = FB_BLANK_NORMAL; 1384 mx3fbi->blank = FB_BLANK_NORMAL;
1404 1385
1386 mx3fb->disp_data_fmt = mx3fb_pdata->disp_data_fmt;
1387
1405 init_completion(&mx3fbi->flip_cmpl); 1388 init_completion(&mx3fbi->flip_cmpl);
1406 disable_irq(ichan->eof_irq); 1389 disable_irq(ichan->eof_irq);
1407 dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq); 1390 dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq);