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 <asm/imx-common/dma.h>
20 #include "videomodes.h"
22 #define PS2KHZ(ps) (1000000000UL / (ps))
24 static GraphicDevice panel
;
25 struct mxs_dma_desc desc
;
28 * mxsfb_system_setup() - Fine-tune LCDIF configuration
30 * This function is used to adjust the LCDIF configuration. This is usually
31 * needed when driving the controller in System-Mode to operate an 8080 or
32 * 6800 connected SmartLCD.
34 __weak
void mxsfb_system_setup(void)
41 * video=ctfb:x:800,y:480,depth:18,mode:0,pclk:30066,
42 * le:0,ri:256,up:0,lo:45,hs:1,vs:1,sync:100663296,vmode:0
44 * Freescale mx23evk/mx28evk with a Seiko 4.3'' WVGA panel:
46 * video=ctfb:x:800,y:480,depth:24,mode:0,pclk:29851,
47 * le:89,ri:164,up:23,lo:10,hs:10,vs:10,sync:0,vmode:0
50 static void mxs_lcd_init(GraphicDevice
*panel
,
51 struct ctfb_res_modes
*mode
, int bpp
)
53 struct mxs_lcdif_regs
*regs
= (struct mxs_lcdif_regs
*)MXS_LCDIF_BASE
;
54 uint32_t word_len
= 0, bus_width
= 0;
55 uint8_t valid_data
= 0;
57 /* Kick in the LCDIF clock */
58 mxs_set_lcdclk(MXS_LCDIF_BASE
, PS2KHZ(mode
->pixclock
));
60 /* Restart the LCDIF block */
61 mxs_reset_block(®s
->hw_lcdif_ctrl_reg
);
65 word_len
= LCDIF_CTRL_WORD_LENGTH_24BIT
;
66 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_24BIT
;
70 word_len
= LCDIF_CTRL_WORD_LENGTH_24BIT
;
71 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT
;
75 word_len
= LCDIF_CTRL_WORD_LENGTH_16BIT
;
76 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_16BIT
;
80 word_len
= LCDIF_CTRL_WORD_LENGTH_8BIT
;
81 bus_width
= LCDIF_CTRL_LCD_DATABUS_WIDTH_8BIT
;
86 writel(bus_width
| word_len
| LCDIF_CTRL_DOTCLK_MODE
|
87 LCDIF_CTRL_BYPASS_COUNT
| LCDIF_CTRL_LCDIF_MASTER
,
88 ®s
->hw_lcdif_ctrl
);
90 writel(valid_data
<< LCDIF_CTRL1_BYTE_PACKING_FORMAT_OFFSET
,
91 ®s
->hw_lcdif_ctrl1
);
95 writel((mode
->yres
<< LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET
) | mode
->xres
,
96 ®s
->hw_lcdif_transfer_count
);
98 writel(LCDIF_VDCTRL0_ENABLE_PRESENT
| LCDIF_VDCTRL0_ENABLE_POL
|
99 LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT
|
100 LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT
|
101 mode
->vsync_len
, ®s
->hw_lcdif_vdctrl0
);
102 writel(mode
->upper_margin
+ mode
->lower_margin
+
103 mode
->vsync_len
+ mode
->yres
,
104 ®s
->hw_lcdif_vdctrl1
);
105 writel((mode
->hsync_len
<< LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_OFFSET
) |
106 (mode
->left_margin
+ mode
->right_margin
+
107 mode
->hsync_len
+ mode
->xres
),
108 ®s
->hw_lcdif_vdctrl2
);
109 writel(((mode
->left_margin
+ mode
->hsync_len
) <<
110 LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_OFFSET
) |
111 (mode
->upper_margin
+ mode
->vsync_len
),
112 ®s
->hw_lcdif_vdctrl3
);
113 writel((0 << LCDIF_VDCTRL4_DOTCLK_DLY_SEL_OFFSET
) | mode
->xres
,
114 ®s
->hw_lcdif_vdctrl4
);
116 writel(panel
->frameAdrs
, ®s
->hw_lcdif_cur_buf
);
117 writel(panel
->frameAdrs
, ®s
->hw_lcdif_next_buf
);
119 /* Flush FIFO first */
120 writel(LCDIF_CTRL1_FIFO_CLEAR
, ®s
->hw_lcdif_ctrl1_set
);
122 #ifndef CONFIG_VIDEO_MXS_MODE_SYSTEM
123 /* Sync signals ON */
124 setbits_le32(®s
->hw_lcdif_vdctrl4
, LCDIF_VDCTRL4_SYNC_SIGNALS_ON
);
128 writel(LCDIF_CTRL1_FIFO_CLEAR
, ®s
->hw_lcdif_ctrl1_clr
);
131 writel(LCDIF_CTRL_RUN
, ®s
->hw_lcdif_ctrl_set
);
134 void lcdif_power_down(void)
136 struct mxs_lcdif_regs
*regs
= (struct mxs_lcdif_regs
*)MXS_LCDIF_BASE
;
137 int timeout
= 1000000;
139 writel(panel
.frameAdrs
, ®s
->hw_lcdif_cur_buf_reg
);
140 writel(panel
.frameAdrs
, ®s
->hw_lcdif_next_buf_reg
);
141 writel(LCDIF_CTRL1_VSYNC_EDGE_IRQ
, ®s
->hw_lcdif_ctrl1_clr
);
143 if (readl(®s
->hw_lcdif_ctrl1_reg
) &
144 LCDIF_CTRL1_VSYNC_EDGE_IRQ
)
148 mxs_reset_block((struct mxs_register_32
*)®s
->hw_lcdif_ctrl_reg
);
151 void *video_hw_init(void)
156 struct ctfb_res_modes mode
;
160 /* Suck display configuration from "videomode" variable */
161 penv
= getenv("videomode");
163 puts("MXSFB: 'videomode' variable not set!\n");
167 bpp
= video_get_params(&mode
, penv
);
169 /* fill in Graphic device struct */
170 sprintf(panel
.modeIdent
, "%dx%dx%d",
171 mode
.xres
, mode
.yres
, bpp
);
173 panel
.winSizeX
= mode
.xres
;
174 panel
.winSizeY
= mode
.yres
;
175 panel
.plnSizeX
= mode
.xres
;
176 panel
.plnSizeY
= mode
.yres
;
181 panel
.gdfBytesPP
= 4;
182 panel
.gdfIndex
= GDF_32BIT_X888RGB
;
185 panel
.gdfBytesPP
= 2;
186 panel
.gdfIndex
= GDF_16BIT_565RGB
;
189 panel
.gdfBytesPP
= 1;
190 panel
.gdfIndex
= GDF__8BIT_INDEX
;
193 printf("MXSFB: Invalid BPP specified! (bpp = %i)\n", bpp
);
197 panel
.memSize
= mode
.xres
* mode
.yres
* panel
.gdfBytesPP
;
199 /* Allocate framebuffer */
200 fb
= memalign(ARCH_DMA_MINALIGN
,
201 roundup(panel
.memSize
, ARCH_DMA_MINALIGN
));
203 printf("MXSFB: Error allocating framebuffer!\n");
207 /* Wipe framebuffer */
208 memset(fb
, 0, panel
.memSize
);
210 panel
.frameAdrs
= (u32
)fb
;
212 printf("%s\n", panel
.modeIdent
);
214 /* Start framebuffer */
215 mxs_lcd_init(&panel
, &mode
, bpp
);
217 #ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM
219 * If the LCD runs in system mode, the LCD refresh has to be triggered
220 * manually by setting the RUN bit in HW_LCDIF_CTRL register. To avoid
221 * having to set this bit manually after every single change in the
222 * framebuffer memory, we set up specially crafted circular DMA, which
223 * sets the RUN bit, then waits until it gets cleared and repeats this
224 * infinitelly. This way, we get smooth continuous updates of the LCD.
226 struct mxs_lcdif_regs
*regs
= (struct mxs_lcdif_regs
*)MXS_LCDIF_BASE
;
228 memset(&desc
, 0, sizeof(struct mxs_dma_desc
));
229 desc
.address
= (dma_addr_t
)&desc
;
230 desc
.cmd
.data
= MXS_DMA_DESC_COMMAND_NO_DMAXFER
| MXS_DMA_DESC_CHAIN
|
231 MXS_DMA_DESC_WAIT4END
|
232 (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET
);
233 desc
.cmd
.pio_words
[0] = readl(®s
->hw_lcdif_ctrl
) | LCDIF_CTRL_RUN
;
234 desc
.cmd
.next
= (uint32_t)&desc
.cmd
;
236 /* Execute the DMA chain. */
237 mxs_dma_circ_start(MXS_DMA_CHANNEL_AHB_APBH_LCDIF
, &desc
);
240 return (void *)&panel
;