2 * Freescale i.MX23/i.MX28 LCDIF driver
4 * Copyright (C) 2011-2013 Marek Vasut <marex@denx.de>
6 * SPDX-License-Identifier: GPL-2.0+
12 #include <asm/arch/imx-regs.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/sys_proto.h>
15 #include <asm/errno.h>
18 #include "videomodes.h"
20 #define PS2KHZ(ps) (1000000000UL / (ps))
22 static GraphicDevice panel
;
27 * video=ctfb:x:800,y:480,depth:18,mode:0,pclk:30066,
28 * le:0,ri:256,up:0,lo:45,hs:1,vs:1,sync:100663296,vmode:0
30 * Freescale mx23evk/mx28evk with a Seiko 4.3'' WVGA panel:
32 * video=ctfb:x:800,y:480,depth:24,mode:0,pclk:29851,
33 * le:89,ri:164,up:23,lo:10,hs:10,vs:10,sync:0,vmode:0
36 static void mxs_lcd_init(GraphicDevice
*panel
,
37 struct ctfb_res_modes
*mode
, int bpp
)
39 struct mxs_lcdif_regs
*regs
= (struct mxs_lcdif_regs
*)MXS_LCDIF_BASE
;
40 uint32_t word_len
= 0, bus_width
= 0;
41 uint8_t valid_data
= 0;
43 /* Kick in the LCDIF clock */
44 mxs_set_lcdclk(PS2KHZ(mode
->pixclock
));
46 /* Restart the LCDIF block */
47 mxs_reset_block(®s
->hw_lcdif_ctrl_reg
);
51 word_len
= LCDIF_CTRL_WORD_LENGTH_24BIT
;
52 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_24BIT
;
56 word_len
= LCDIF_CTRL_WORD_LENGTH_24BIT
;
57 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT
;
61 word_len
= LCDIF_CTRL_WORD_LENGTH_16BIT
;
62 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_16BIT
;
66 word_len
= LCDIF_CTRL_WORD_LENGTH_8BIT
;
67 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_8BIT
;
72 writel(bus_width
| word_len
| LCDIF_CTRL_DOTCLK_MODE
|
73 LCDIF_CTRL_BYPASS_COUNT
| LCDIF_CTRL_LCDIF_MASTER
,
74 ®s
->hw_lcdif_ctrl
);
76 writel(valid_data
<< LCDIF_CTRL1_BYTE_PACKING_FORMAT_OFFSET
,
77 ®s
->hw_lcdif_ctrl1
);
78 writel((mode
->yres
<< LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET
) | mode
->xres
,
79 ®s
->hw_lcdif_transfer_count
);
81 writel(LCDIF_VDCTRL0_ENABLE_PRESENT
| LCDIF_VDCTRL0_ENABLE_POL
|
82 LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT
|
83 LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT
|
84 mode
->vsync_len
, ®s
->hw_lcdif_vdctrl0
);
85 writel(mode
->upper_margin
+ mode
->lower_margin
+
86 mode
->vsync_len
+ mode
->yres
,
87 ®s
->hw_lcdif_vdctrl1
);
88 writel((mode
->hsync_len
<< LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_OFFSET
) |
89 (mode
->left_margin
+ mode
->right_margin
+
90 mode
->hsync_len
+ mode
->xres
),
91 ®s
->hw_lcdif_vdctrl2
);
92 writel(((mode
->left_margin
+ mode
->hsync_len
) <<
93 LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_OFFSET
) |
94 (mode
->upper_margin
+ mode
->vsync_len
),
95 ®s
->hw_lcdif_vdctrl3
);
96 writel((0 << LCDIF_VDCTRL4_DOTCLK_DLY_SEL_OFFSET
) | mode
->xres
,
97 ®s
->hw_lcdif_vdctrl4
);
99 writel(panel
->frameAdrs
, ®s
->hw_lcdif_cur_buf
);
100 writel(panel
->frameAdrs
, ®s
->hw_lcdif_next_buf
);
102 /* Flush FIFO first */
103 writel(LCDIF_CTRL1_FIFO_CLEAR
, ®s
->hw_lcdif_ctrl1_set
);
105 /* Sync signals ON */
106 setbits_le32(®s
->hw_lcdif_vdctrl4
, LCDIF_VDCTRL4_SYNC_SIGNALS_ON
);
109 writel(LCDIF_CTRL1_FIFO_CLEAR
, ®s
->hw_lcdif_ctrl1_clr
);
112 writel(LCDIF_CTRL_RUN
, ®s
->hw_lcdif_ctrl_set
);
115 void *video_hw_init(void)
120 struct ctfb_res_modes mode
;
124 /* Suck display configuration from "videomode" variable */
125 penv
= getenv("videomode");
127 puts("MXSFB: 'videomode' variable not set!\n");
131 bpp
= video_get_params(&mode
, penv
);
133 /* fill in Graphic device struct */
134 sprintf(panel
.modeIdent
, "%dx%dx%d",
135 mode
.xres
, mode
.yres
, bpp
);
137 panel
.winSizeX
= mode
.xres
;
138 panel
.winSizeY
= mode
.yres
;
139 panel
.plnSizeX
= mode
.xres
;
140 panel
.plnSizeY
= mode
.yres
;
145 panel
.gdfBytesPP
= 4;
146 panel
.gdfIndex
= GDF_32BIT_X888RGB
;
149 panel
.gdfBytesPP
= 2;
150 panel
.gdfIndex
= GDF_16BIT_565RGB
;
153 panel
.gdfBytesPP
= 1;
154 panel
.gdfIndex
= GDF__8BIT_INDEX
;
157 printf("MXSFB: Invalid BPP specified! (bpp = %i)\n", bpp
);
161 panel
.memSize
= mode
.xres
* mode
.yres
* panel
.gdfBytesPP
;
163 /* Allocate framebuffer */
164 fb
= memalign(ARCH_DMA_MINALIGN
,
165 roundup(panel
.memSize
, ARCH_DMA_MINALIGN
));
167 printf("MXSFB: Error allocating framebuffer!\n");
171 /* Wipe framebuffer */
172 memset(fb
, 0, panel
.memSize
);
174 panel
.frameAdrs
= (u32
)fb
;
176 printf("%s\n", panel
.modeIdent
);
178 /* Start framebuffer */
179 mxs_lcd_init(&panel
, &mode
, bpp
);
181 return (void *)&panel
;