1f95ec3c6SRalf Baechle /*
2f95ec3c6SRalf Baechle * BRIEF MODULE DESCRIPTION
3f95ec3c6SRalf Baechle * Au1200 LCD Driver.
4f95ec3c6SRalf Baechle *
5f95ec3c6SRalf Baechle * Copyright 2004-2005 AMD
6f95ec3c6SRalf Baechle * Author: AMD
7f95ec3c6SRalf Baechle *
8f95ec3c6SRalf Baechle * Based on:
9f95ec3c6SRalf Baechle * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
10f95ec3c6SRalf Baechle * Created 28 Dec 1997 by Geert Uytterhoeven
11f95ec3c6SRalf Baechle *
12f95ec3c6SRalf Baechle * This program is free software; you can redistribute it and/or modify it
13f95ec3c6SRalf Baechle * under the terms of the GNU General Public License as published by the
14f95ec3c6SRalf Baechle * Free Software Foundation; either version 2 of the License, or (at your
15f95ec3c6SRalf Baechle * option) any later version.
16f95ec3c6SRalf Baechle *
17f95ec3c6SRalf Baechle * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18f95ec3c6SRalf Baechle * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19f95ec3c6SRalf Baechle * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
20f95ec3c6SRalf Baechle * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21f95ec3c6SRalf Baechle * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22f95ec3c6SRalf Baechle * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23f95ec3c6SRalf Baechle * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24f95ec3c6SRalf Baechle * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25f95ec3c6SRalf Baechle * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26f95ec3c6SRalf Baechle * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27f95ec3c6SRalf Baechle *
28f95ec3c6SRalf Baechle * You should have received a copy of the GNU General Public License along
29f95ec3c6SRalf Baechle * with this program; if not, write to the Free Software Foundation, Inc.,
30f95ec3c6SRalf Baechle * 675 Mass Ave, Cambridge, MA 02139, USA.
31f95ec3c6SRalf Baechle */
32f95ec3c6SRalf Baechle
33ecc2ea3bSManuel Lauss #include <linux/clk.h>
34f95ec3c6SRalf Baechle #include <linux/module.h>
35f95ec3c6SRalf Baechle #include <linux/platform_device.h>
36f95ec3c6SRalf Baechle #include <linux/kernel.h>
37f95ec3c6SRalf Baechle #include <linux/errno.h>
38f95ec3c6SRalf Baechle #include <linux/string.h>
39f95ec3c6SRalf Baechle #include <linux/mm.h>
40f95ec3c6SRalf Baechle #include <linux/fb.h>
41f95ec3c6SRalf Baechle #include <linux/init.h>
42f95ec3c6SRalf Baechle #include <linux/interrupt.h>
43f95ec3c6SRalf Baechle #include <linux/ctype.h>
44f95ec3c6SRalf Baechle #include <linux/dma-mapping.h>
455a0e3ad6STejun Heo #include <linux/slab.h>
4629abfbd9SAl Viro #include <linux/uaccess.h>
47f95ec3c6SRalf Baechle
48f95ec3c6SRalf Baechle #include <asm/mach-au1x00/au1000.h>
49a9b71a8fSManuel Lauss #include <asm/mach-au1x00/au1200fb.h> /* platform_data */
50f95ec3c6SRalf Baechle #include "au1200fb.h"
51f95ec3c6SRalf Baechle
52f95ec3c6SRalf Baechle #define DRIVER_NAME "au1200fb"
53f95ec3c6SRalf Baechle #define DRIVER_DESC "LCD controller driver for AU1200 processors"
54f95ec3c6SRalf Baechle
55f49446ebSManuel Lauss #define DEBUG 0
56f95ec3c6SRalf Baechle
57f95ec3c6SRalf Baechle #define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
58f95ec3c6SRalf Baechle #define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
59f95ec3c6SRalf Baechle #define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
60f95ec3c6SRalf Baechle
61f95ec3c6SRalf Baechle #if DEBUG
62f95ec3c6SRalf Baechle #define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
63f95ec3c6SRalf Baechle #else
64f95ec3c6SRalf Baechle #define print_dbg(f, arg...) do {} while (0)
65f95ec3c6SRalf Baechle #endif
66f95ec3c6SRalf Baechle
67f95ec3c6SRalf Baechle
68f95ec3c6SRalf Baechle #define AU1200_LCD_FB_IOCTL 0x46FF
69f95ec3c6SRalf Baechle
70f95ec3c6SRalf Baechle #define AU1200_LCD_SET_SCREEN 1
71f95ec3c6SRalf Baechle #define AU1200_LCD_GET_SCREEN 2
72f95ec3c6SRalf Baechle #define AU1200_LCD_SET_WINDOW 3
73f95ec3c6SRalf Baechle #define AU1200_LCD_GET_WINDOW 4
74f95ec3c6SRalf Baechle #define AU1200_LCD_SET_PANEL 5
75f95ec3c6SRalf Baechle #define AU1200_LCD_GET_PANEL 6
76f95ec3c6SRalf Baechle
77f95ec3c6SRalf Baechle #define SCREEN_SIZE (1<< 1)
78f95ec3c6SRalf Baechle #define SCREEN_BACKCOLOR (1<< 2)
79f95ec3c6SRalf Baechle #define SCREEN_BRIGHTNESS (1<< 3)
80f95ec3c6SRalf Baechle #define SCREEN_COLORKEY (1<< 4)
81f95ec3c6SRalf Baechle #define SCREEN_MASK (1<< 5)
82f95ec3c6SRalf Baechle
83f95ec3c6SRalf Baechle struct au1200_lcd_global_regs_t {
84f95ec3c6SRalf Baechle unsigned int flags;
85f95ec3c6SRalf Baechle unsigned int xsize;
86f95ec3c6SRalf Baechle unsigned int ysize;
87f95ec3c6SRalf Baechle unsigned int backcolor;
88f95ec3c6SRalf Baechle unsigned int brightness;
89f95ec3c6SRalf Baechle unsigned int colorkey;
90f95ec3c6SRalf Baechle unsigned int mask;
91f95ec3c6SRalf Baechle unsigned int panel_choice;
92f95ec3c6SRalf Baechle char panel_desc[80];
93f95ec3c6SRalf Baechle
94f95ec3c6SRalf Baechle };
95f95ec3c6SRalf Baechle
96f95ec3c6SRalf Baechle #define WIN_POSITION (1<< 0)
97f95ec3c6SRalf Baechle #define WIN_ALPHA_COLOR (1<< 1)
98f95ec3c6SRalf Baechle #define WIN_ALPHA_MODE (1<< 2)
99f95ec3c6SRalf Baechle #define WIN_PRIORITY (1<< 3)
100f95ec3c6SRalf Baechle #define WIN_CHANNEL (1<< 4)
101f95ec3c6SRalf Baechle #define WIN_BUFFER_FORMAT (1<< 5)
102f95ec3c6SRalf Baechle #define WIN_COLOR_ORDER (1<< 6)
103f95ec3c6SRalf Baechle #define WIN_PIXEL_ORDER (1<< 7)
104f95ec3c6SRalf Baechle #define WIN_SIZE (1<< 8)
105f95ec3c6SRalf Baechle #define WIN_COLORKEY_MODE (1<< 9)
106f95ec3c6SRalf Baechle #define WIN_DOUBLE_BUFFER_MODE (1<< 10)
107f95ec3c6SRalf Baechle #define WIN_RAM_ARRAY_MODE (1<< 11)
108f95ec3c6SRalf Baechle #define WIN_BUFFER_SCALE (1<< 12)
109f95ec3c6SRalf Baechle #define WIN_ENABLE (1<< 13)
110f95ec3c6SRalf Baechle
111f95ec3c6SRalf Baechle struct au1200_lcd_window_regs_t {
112f95ec3c6SRalf Baechle unsigned int flags;
113f95ec3c6SRalf Baechle unsigned int xpos;
114f95ec3c6SRalf Baechle unsigned int ypos;
115f95ec3c6SRalf Baechle unsigned int alpha_color;
116f95ec3c6SRalf Baechle unsigned int alpha_mode;
117f95ec3c6SRalf Baechle unsigned int priority;
118f95ec3c6SRalf Baechle unsigned int channel;
119f95ec3c6SRalf Baechle unsigned int buffer_format;
120f95ec3c6SRalf Baechle unsigned int color_order;
121f95ec3c6SRalf Baechle unsigned int pixel_order;
122f95ec3c6SRalf Baechle unsigned int xsize;
123f95ec3c6SRalf Baechle unsigned int ysize;
124f95ec3c6SRalf Baechle unsigned int colorkey_mode;
125f95ec3c6SRalf Baechle unsigned int double_buffer_mode;
126f95ec3c6SRalf Baechle unsigned int ram_array_mode;
127f95ec3c6SRalf Baechle unsigned int xscale;
128f95ec3c6SRalf Baechle unsigned int yscale;
129f95ec3c6SRalf Baechle unsigned int enable;
130f95ec3c6SRalf Baechle };
131f95ec3c6SRalf Baechle
132f95ec3c6SRalf Baechle
133f95ec3c6SRalf Baechle struct au1200_lcd_iodata_t {
134f95ec3c6SRalf Baechle unsigned int subcmd;
135f95ec3c6SRalf Baechle struct au1200_lcd_global_regs_t global;
136f95ec3c6SRalf Baechle struct au1200_lcd_window_regs_t window;
137f95ec3c6SRalf Baechle };
138f95ec3c6SRalf Baechle
139f95ec3c6SRalf Baechle #if defined(__BIG_ENDIAN)
140f95ec3c6SRalf Baechle #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
141f95ec3c6SRalf Baechle #else
142f95ec3c6SRalf Baechle #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
143f95ec3c6SRalf Baechle #endif
144f95ec3c6SRalf Baechle #define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
145f95ec3c6SRalf Baechle
146f95ec3c6SRalf Baechle /* Private, per-framebuffer management information (independent of the panel itself) */
147f95ec3c6SRalf Baechle struct au1200fb_device {
148c329f606SManuel Lauss struct fb_info *fb_info; /* FB driver info record */
149a9b71a8fSManuel Lauss struct au1200fb_platdata *pd;
150e0b29902SChristoph Hellwig struct device *dev;
151f95ec3c6SRalf Baechle
152f95ec3c6SRalf Baechle int plane;
153f95ec3c6SRalf Baechle unsigned char* fb_mem; /* FrameBuffer memory map */
154f95ec3c6SRalf Baechle unsigned int fb_len;
155f95ec3c6SRalf Baechle dma_addr_t fb_phys;
156f95ec3c6SRalf Baechle };
157f95ec3c6SRalf Baechle
158f95ec3c6SRalf Baechle /********************************************************************/
159f95ec3c6SRalf Baechle
160f95ec3c6SRalf Baechle /* LCD controller restrictions */
161f95ec3c6SRalf Baechle #define AU1200_LCD_MAX_XRES 1280
162f95ec3c6SRalf Baechle #define AU1200_LCD_MAX_YRES 1024
163f95ec3c6SRalf Baechle #define AU1200_LCD_MAX_BPP 32
164f95ec3c6SRalf Baechle #define AU1200_LCD_MAX_CLK 96000000 /* fixme: this needs to go away ? */
165f95ec3c6SRalf Baechle #define AU1200_LCD_NBR_PALETTE_ENTRIES 256
166f95ec3c6SRalf Baechle
167f95ec3c6SRalf Baechle /* Default number of visible screen buffer to allocate */
168f95ec3c6SRalf Baechle #define AU1200FB_NBR_VIDEO_BUFFERS 1
169f95ec3c6SRalf Baechle
1708be90b07SManuel Lauss /* Default maximum number of fb devices to create */
1718be90b07SManuel Lauss #define MAX_DEVICE_COUNT 4
1728be90b07SManuel Lauss
1738be90b07SManuel Lauss /* Default window configuration entry to use (see windows[]) */
1748be90b07SManuel Lauss #define DEFAULT_WINDOW_INDEX 2
1758be90b07SManuel Lauss
176f95ec3c6SRalf Baechle /********************************************************************/
177f95ec3c6SRalf Baechle
1788be90b07SManuel Lauss static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT];
179f95ec3c6SRalf Baechle static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
1808be90b07SManuel Lauss static int device_count = MAX_DEVICE_COUNT;
1818be90b07SManuel Lauss static int window_index = DEFAULT_WINDOW_INDEX; /* default is zero */
182f95ec3c6SRalf Baechle static int panel_index = 2; /* default is zero */
183f95ec3c6SRalf Baechle static struct window_settings *win;
184f95ec3c6SRalf Baechle static struct panel_settings *panel;
185f95ec3c6SRalf Baechle static int noblanking = 1;
186f95ec3c6SRalf Baechle static int nohwcursor = 0;
187f95ec3c6SRalf Baechle
188f95ec3c6SRalf Baechle struct window_settings {
189f95ec3c6SRalf Baechle unsigned char name[64];
190f95ec3c6SRalf Baechle uint32 mode_backcolor;
191f95ec3c6SRalf Baechle uint32 mode_colorkey;
192f95ec3c6SRalf Baechle uint32 mode_colorkeymsk;
193f95ec3c6SRalf Baechle struct {
194f95ec3c6SRalf Baechle int xres;
195f95ec3c6SRalf Baechle int yres;
196f95ec3c6SRalf Baechle int xpos;
197f95ec3c6SRalf Baechle int ypos;
198f95ec3c6SRalf Baechle uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
199f95ec3c6SRalf Baechle uint32 mode_winenable;
200f95ec3c6SRalf Baechle } w[4];
201f95ec3c6SRalf Baechle };
202f95ec3c6SRalf Baechle
203f95ec3c6SRalf Baechle #if defined(__BIG_ENDIAN)
204f95ec3c6SRalf Baechle #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
205f95ec3c6SRalf Baechle #else
206f95ec3c6SRalf Baechle #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
207f95ec3c6SRalf Baechle #endif
208f95ec3c6SRalf Baechle
209f95ec3c6SRalf Baechle /*
210f95ec3c6SRalf Baechle * Default window configurations
211f95ec3c6SRalf Baechle */
212f95ec3c6SRalf Baechle static struct window_settings windows[] = {
213f95ec3c6SRalf Baechle { /* Index 0 */
214f95ec3c6SRalf Baechle "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
215f95ec3c6SRalf Baechle /* mode_backcolor */ 0x006600ff,
216f95ec3c6SRalf Baechle /* mode_colorkey,msk*/ 0, 0,
217f95ec3c6SRalf Baechle {
218f95ec3c6SRalf Baechle {
219f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
220f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
221f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP,
222f95ec3c6SRalf Baechle /* mode_winenable*/ LCD_WINENABLE_WEN0,
223f95ec3c6SRalf Baechle },
224f95ec3c6SRalf Baechle {
225f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 100, 100, 100, 100,
226f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
227f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP |
228f95ec3c6SRalf Baechle LCD_WINCTRL1_PIPE,
229f95ec3c6SRalf Baechle /* mode_winenable*/ LCD_WINENABLE_WEN1,
230f95ec3c6SRalf Baechle },
231f95ec3c6SRalf Baechle {
232f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
233f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
234f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP,
235f95ec3c6SRalf Baechle /* mode_winenable*/ 0,
236f95ec3c6SRalf Baechle },
237f95ec3c6SRalf Baechle {
238f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
239f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
240f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP |
241f95ec3c6SRalf Baechle LCD_WINCTRL1_PIPE,
242f95ec3c6SRalf Baechle /* mode_winenable*/ 0,
243f95ec3c6SRalf Baechle },
244f95ec3c6SRalf Baechle },
245f95ec3c6SRalf Baechle },
246f95ec3c6SRalf Baechle
247f95ec3c6SRalf Baechle { /* Index 1 */
248f95ec3c6SRalf Baechle "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
249f95ec3c6SRalf Baechle /* mode_backcolor */ 0x006600ff,
250f95ec3c6SRalf Baechle /* mode_colorkey,msk*/ 0, 0,
251f95ec3c6SRalf Baechle {
252f95ec3c6SRalf Baechle {
253f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 320, 240, 5, 5,
254f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
255f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_00,
256f95ec3c6SRalf Baechle /* mode_winenable*/ LCD_WINENABLE_WEN0,
257f95ec3c6SRalf Baechle },
258f95ec3c6SRalf Baechle {
259f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
260f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
261f95ec3c6SRalf Baechle | LCD_WINCTRL1_PO_16BPP,
262f95ec3c6SRalf Baechle /* mode_winenable*/ 0,
263f95ec3c6SRalf Baechle },
264f95ec3c6SRalf Baechle {
265f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 100, 100, 0, 0,
266f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
267f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP |
268f95ec3c6SRalf Baechle LCD_WINCTRL1_PIPE,
269f95ec3c6SRalf Baechle /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
270f95ec3c6SRalf Baechle },
271f95ec3c6SRalf Baechle {
272f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 200, 25, 0, 0,
273f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
274f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP |
275f95ec3c6SRalf Baechle LCD_WINCTRL1_PIPE,
276f95ec3c6SRalf Baechle /* mode_winenable*/ 0,
277f95ec3c6SRalf Baechle },
278f95ec3c6SRalf Baechle },
279f95ec3c6SRalf Baechle },
280f95ec3c6SRalf Baechle { /* Index 2 */
281f95ec3c6SRalf Baechle "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
282f95ec3c6SRalf Baechle /* mode_backcolor */ 0x006600ff,
283f95ec3c6SRalf Baechle /* mode_colorkey,msk*/ 0, 0,
284f95ec3c6SRalf Baechle {
285f95ec3c6SRalf Baechle {
286f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
287f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
288f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP,
289f95ec3c6SRalf Baechle /* mode_winenable*/ LCD_WINENABLE_WEN0,
290f95ec3c6SRalf Baechle },
291f95ec3c6SRalf Baechle {
292f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
293f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
294f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP,
295f95ec3c6SRalf Baechle /* mode_winenable*/ 0,
296f95ec3c6SRalf Baechle },
297f95ec3c6SRalf Baechle {
298f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
299f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
300f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
301f95ec3c6SRalf Baechle /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
302f95ec3c6SRalf Baechle },
303f95ec3c6SRalf Baechle {
304f95ec3c6SRalf Baechle /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
305f95ec3c6SRalf Baechle /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
306f95ec3c6SRalf Baechle LCD_WINCTRL1_PO_16BPP |
307f95ec3c6SRalf Baechle LCD_WINCTRL1_PIPE,
308f95ec3c6SRalf Baechle /* mode_winenable*/ 0,
309f95ec3c6SRalf Baechle },
310f95ec3c6SRalf Baechle },
311f95ec3c6SRalf Baechle },
312f95ec3c6SRalf Baechle /* Need VGA 640 @ 24bpp, @ 32bpp */
313f95ec3c6SRalf Baechle /* Need VGA 800 @ 24bpp, @ 32bpp */
314f95ec3c6SRalf Baechle /* Need VGA 1024 @ 24bpp, @ 32bpp */
315f95ec3c6SRalf Baechle };
316f95ec3c6SRalf Baechle
317f95ec3c6SRalf Baechle /*
318f95ec3c6SRalf Baechle * Controller configurations for various panels.
319f95ec3c6SRalf Baechle */
320f95ec3c6SRalf Baechle
321f95ec3c6SRalf Baechle struct panel_settings
322f95ec3c6SRalf Baechle {
323f95ec3c6SRalf Baechle const char name[25]; /* Full name <vendor>_<model> */
324f95ec3c6SRalf Baechle
325f95ec3c6SRalf Baechle struct fb_monspecs monspecs; /* FB monitor specs */
326f95ec3c6SRalf Baechle
327f95ec3c6SRalf Baechle /* panel timings */
328f95ec3c6SRalf Baechle uint32 mode_screen;
329f95ec3c6SRalf Baechle uint32 mode_horztiming;
330f95ec3c6SRalf Baechle uint32 mode_verttiming;
331f95ec3c6SRalf Baechle uint32 mode_clkcontrol;
332f95ec3c6SRalf Baechle uint32 mode_pwmdiv;
333f95ec3c6SRalf Baechle uint32 mode_pwmhi;
334f95ec3c6SRalf Baechle uint32 mode_outmask;
335f95ec3c6SRalf Baechle uint32 mode_fifoctrl;
336f95ec3c6SRalf Baechle uint32 mode_backlight;
337ecc2ea3bSManuel Lauss uint32 lcdclk;
338f95ec3c6SRalf Baechle #define Xres min_xres
339f95ec3c6SRalf Baechle #define Yres min_yres
340f95ec3c6SRalf Baechle u32 min_xres; /* Minimum horizontal resolution */
341f95ec3c6SRalf Baechle u32 max_xres; /* Maximum horizontal resolution */
342f95ec3c6SRalf Baechle u32 min_yres; /* Minimum vertical resolution */
343f95ec3c6SRalf Baechle u32 max_yres; /* Maximum vertical resolution */
344f95ec3c6SRalf Baechle };
345f95ec3c6SRalf Baechle
346f95ec3c6SRalf Baechle /********************************************************************/
347f95ec3c6SRalf Baechle /* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
348f95ec3c6SRalf Baechle
349f95ec3c6SRalf Baechle /* List of panels known to work with the AU1200 LCD controller.
350f95ec3c6SRalf Baechle * To add a new panel, enter the same specifications as the
351f95ec3c6SRalf Baechle * Generic_TFT one, and MAKE SURE that it doesn't conflicts
352f95ec3c6SRalf Baechle * with the controller restrictions. Restrictions are:
353f95ec3c6SRalf Baechle *
354f95ec3c6SRalf Baechle * STN color panels: max_bpp <= 12
355f95ec3c6SRalf Baechle * STN mono panels: max_bpp <= 4
356f95ec3c6SRalf Baechle * TFT panels: max_bpp <= 16
357f95ec3c6SRalf Baechle * max_xres <= 800
358f95ec3c6SRalf Baechle * max_yres <= 600
359f95ec3c6SRalf Baechle */
360f95ec3c6SRalf Baechle static struct panel_settings known_lcd_panels[] =
361f95ec3c6SRalf Baechle {
362f95ec3c6SRalf Baechle [0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
363f95ec3c6SRalf Baechle .name = "QVGA_320x240",
364f95ec3c6SRalf Baechle .monspecs = {
365f95ec3c6SRalf Baechle .modedb = NULL,
366f95ec3c6SRalf Baechle .modedb_len = 0,
367f95ec3c6SRalf Baechle .hfmin = 30000,
368f95ec3c6SRalf Baechle .hfmax = 70000,
369f95ec3c6SRalf Baechle .vfmin = 60,
370f95ec3c6SRalf Baechle .vfmax = 60,
371f95ec3c6SRalf Baechle .dclkmin = 6000000,
372f95ec3c6SRalf Baechle .dclkmax = 28000000,
373f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
374f95ec3c6SRalf Baechle },
375f95ec3c6SRalf Baechle .mode_screen = LCD_SCREEN_SX_N(320) |
376f95ec3c6SRalf Baechle LCD_SCREEN_SY_N(240),
377f95ec3c6SRalf Baechle .mode_horztiming = 0x00c4623b,
378f95ec3c6SRalf Baechle .mode_verttiming = 0x00502814,
379f95ec3c6SRalf Baechle .mode_clkcontrol = 0x00020002, /* /4=24Mhz */
380f95ec3c6SRalf Baechle .mode_pwmdiv = 0x00000000,
381f95ec3c6SRalf Baechle .mode_pwmhi = 0x00000000,
382f95ec3c6SRalf Baechle .mode_outmask = 0x00FFFFFF,
383f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
384f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
385ecc2ea3bSManuel Lauss .lcdclk = 96,
386f95ec3c6SRalf Baechle 320, 320,
387f95ec3c6SRalf Baechle 240, 240,
388f95ec3c6SRalf Baechle },
389f95ec3c6SRalf Baechle
390f95ec3c6SRalf Baechle [1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
391f95ec3c6SRalf Baechle .name = "VGA_640x480",
392f95ec3c6SRalf Baechle .monspecs = {
393f95ec3c6SRalf Baechle .modedb = NULL,
394f95ec3c6SRalf Baechle .modedb_len = 0,
395f95ec3c6SRalf Baechle .hfmin = 30000,
396f95ec3c6SRalf Baechle .hfmax = 70000,
397f95ec3c6SRalf Baechle .vfmin = 60,
398f95ec3c6SRalf Baechle .vfmax = 60,
399f95ec3c6SRalf Baechle .dclkmin = 6000000,
400f95ec3c6SRalf Baechle .dclkmax = 28000000,
401f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
402f95ec3c6SRalf Baechle },
403f95ec3c6SRalf Baechle .mode_screen = 0x13f9df80,
404f95ec3c6SRalf Baechle .mode_horztiming = 0x003c5859,
405f95ec3c6SRalf Baechle .mode_verttiming = 0x00741201,
406f95ec3c6SRalf Baechle .mode_clkcontrol = 0x00020001, /* /4=24Mhz */
407f95ec3c6SRalf Baechle .mode_pwmdiv = 0x00000000,
408f95ec3c6SRalf Baechle .mode_pwmhi = 0x00000000,
409f95ec3c6SRalf Baechle .mode_outmask = 0x00FFFFFF,
410f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
411f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
412ecc2ea3bSManuel Lauss .lcdclk = 96,
413f95ec3c6SRalf Baechle 640, 480,
414f95ec3c6SRalf Baechle 640, 480,
415f95ec3c6SRalf Baechle },
416f95ec3c6SRalf Baechle
417f95ec3c6SRalf Baechle [2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
418f95ec3c6SRalf Baechle .name = "SVGA_800x600",
419f95ec3c6SRalf Baechle .monspecs = {
420f95ec3c6SRalf Baechle .modedb = NULL,
421f95ec3c6SRalf Baechle .modedb_len = 0,
422f95ec3c6SRalf Baechle .hfmin = 30000,
423f95ec3c6SRalf Baechle .hfmax = 70000,
424f95ec3c6SRalf Baechle .vfmin = 60,
425f95ec3c6SRalf Baechle .vfmax = 60,
426f95ec3c6SRalf Baechle .dclkmin = 6000000,
427f95ec3c6SRalf Baechle .dclkmax = 28000000,
428f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
429f95ec3c6SRalf Baechle },
430f95ec3c6SRalf Baechle .mode_screen = 0x18fa5780,
431f95ec3c6SRalf Baechle .mode_horztiming = 0x00dc7e77,
432f95ec3c6SRalf Baechle .mode_verttiming = 0x00584805,
433f95ec3c6SRalf Baechle .mode_clkcontrol = 0x00020000, /* /2=48Mhz */
434f95ec3c6SRalf Baechle .mode_pwmdiv = 0x00000000,
435f95ec3c6SRalf Baechle .mode_pwmhi = 0x00000000,
436f95ec3c6SRalf Baechle .mode_outmask = 0x00FFFFFF,
437f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
438f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
439ecc2ea3bSManuel Lauss .lcdclk = 96,
440f95ec3c6SRalf Baechle 800, 800,
441f95ec3c6SRalf Baechle 600, 600,
442f95ec3c6SRalf Baechle },
443f95ec3c6SRalf Baechle
444f95ec3c6SRalf Baechle [3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
445f95ec3c6SRalf Baechle .name = "XVGA_1024x768",
446f95ec3c6SRalf Baechle .monspecs = {
447f95ec3c6SRalf Baechle .modedb = NULL,
448f95ec3c6SRalf Baechle .modedb_len = 0,
449f95ec3c6SRalf Baechle .hfmin = 30000,
450f95ec3c6SRalf Baechle .hfmax = 70000,
451f95ec3c6SRalf Baechle .vfmin = 60,
452f95ec3c6SRalf Baechle .vfmax = 60,
453f95ec3c6SRalf Baechle .dclkmin = 6000000,
454f95ec3c6SRalf Baechle .dclkmax = 28000000,
455f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
456f95ec3c6SRalf Baechle },
457f95ec3c6SRalf Baechle .mode_screen = 0x1ffaff80,
458f95ec3c6SRalf Baechle .mode_horztiming = 0x007d0e57,
459f95ec3c6SRalf Baechle .mode_verttiming = 0x00740a01,
460f95ec3c6SRalf Baechle .mode_clkcontrol = 0x000A0000, /* /1 */
461f95ec3c6SRalf Baechle .mode_pwmdiv = 0x00000000,
462f95ec3c6SRalf Baechle .mode_pwmhi = 0x00000000,
463f95ec3c6SRalf Baechle .mode_outmask = 0x00FFFFFF,
464f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
465f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
466ecc2ea3bSManuel Lauss .lcdclk = 72,
467f95ec3c6SRalf Baechle 1024, 1024,
468f95ec3c6SRalf Baechle 768, 768,
469f95ec3c6SRalf Baechle },
470f95ec3c6SRalf Baechle
471f95ec3c6SRalf Baechle [4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
472f95ec3c6SRalf Baechle .name = "XVGA_1280x1024",
473f95ec3c6SRalf Baechle .monspecs = {
474f95ec3c6SRalf Baechle .modedb = NULL,
475f95ec3c6SRalf Baechle .modedb_len = 0,
476f95ec3c6SRalf Baechle .hfmin = 30000,
477f95ec3c6SRalf Baechle .hfmax = 70000,
478f95ec3c6SRalf Baechle .vfmin = 60,
479f95ec3c6SRalf Baechle .vfmax = 60,
480f95ec3c6SRalf Baechle .dclkmin = 6000000,
481f95ec3c6SRalf Baechle .dclkmax = 28000000,
482f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
483f95ec3c6SRalf Baechle },
484f95ec3c6SRalf Baechle .mode_screen = 0x27fbff80,
485f95ec3c6SRalf Baechle .mode_horztiming = 0x00cdb2c7,
486f95ec3c6SRalf Baechle .mode_verttiming = 0x00600002,
487f95ec3c6SRalf Baechle .mode_clkcontrol = 0x000A0000, /* /1 */
488f95ec3c6SRalf Baechle .mode_pwmdiv = 0x00000000,
489f95ec3c6SRalf Baechle .mode_pwmhi = 0x00000000,
490f95ec3c6SRalf Baechle .mode_outmask = 0x00FFFFFF,
491f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
492f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
493ecc2ea3bSManuel Lauss .lcdclk = 120,
494f95ec3c6SRalf Baechle 1280, 1280,
495f95ec3c6SRalf Baechle 1024, 1024,
496f95ec3c6SRalf Baechle },
497f95ec3c6SRalf Baechle
498f95ec3c6SRalf Baechle [5] = { /* Samsung 1024x768 TFT */
499f95ec3c6SRalf Baechle .name = "Samsung_1024x768_TFT",
500f95ec3c6SRalf Baechle .monspecs = {
501f95ec3c6SRalf Baechle .modedb = NULL,
502f95ec3c6SRalf Baechle .modedb_len = 0,
503f95ec3c6SRalf Baechle .hfmin = 30000,
504f95ec3c6SRalf Baechle .hfmax = 70000,
505f95ec3c6SRalf Baechle .vfmin = 60,
506f95ec3c6SRalf Baechle .vfmax = 60,
507f95ec3c6SRalf Baechle .dclkmin = 6000000,
508f95ec3c6SRalf Baechle .dclkmax = 28000000,
509f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
510f95ec3c6SRalf Baechle },
511f95ec3c6SRalf Baechle .mode_screen = 0x1ffaff80,
512f95ec3c6SRalf Baechle .mode_horztiming = 0x018cc677,
513f95ec3c6SRalf Baechle .mode_verttiming = 0x00241217,
514f95ec3c6SRalf Baechle .mode_clkcontrol = 0x00000000, /* SCB 0x1 /4=24Mhz */
515f95ec3c6SRalf Baechle .mode_pwmdiv = 0x8000063f, /* SCB 0x0 */
516f95ec3c6SRalf Baechle .mode_pwmhi = 0x03400000, /* SCB 0x0 */
517f95ec3c6SRalf Baechle .mode_outmask = 0x00FFFFFF,
518f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
519f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
520ecc2ea3bSManuel Lauss .lcdclk = 96,
521f95ec3c6SRalf Baechle 1024, 1024,
522f95ec3c6SRalf Baechle 768, 768,
523f95ec3c6SRalf Baechle },
524f95ec3c6SRalf Baechle
525f95ec3c6SRalf Baechle [6] = { /* Toshiba 640x480 TFT */
526f95ec3c6SRalf Baechle .name = "Toshiba_640x480_TFT",
527f95ec3c6SRalf Baechle .monspecs = {
528f95ec3c6SRalf Baechle .modedb = NULL,
529f95ec3c6SRalf Baechle .modedb_len = 0,
530f95ec3c6SRalf Baechle .hfmin = 30000,
531f95ec3c6SRalf Baechle .hfmax = 70000,
532f95ec3c6SRalf Baechle .vfmin = 60,
533f95ec3c6SRalf Baechle .vfmax = 60,
534f95ec3c6SRalf Baechle .dclkmin = 6000000,
535f95ec3c6SRalf Baechle .dclkmax = 28000000,
536f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
537f95ec3c6SRalf Baechle },
538f95ec3c6SRalf Baechle .mode_screen = LCD_SCREEN_SX_N(640) |
539f95ec3c6SRalf Baechle LCD_SCREEN_SY_N(480),
540f95ec3c6SRalf Baechle .mode_horztiming = LCD_HORZTIMING_HPW_N(96) |
541f95ec3c6SRalf Baechle LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
542f95ec3c6SRalf Baechle .mode_verttiming = LCD_VERTTIMING_VPW_N(2) |
543f95ec3c6SRalf Baechle LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
544f95ec3c6SRalf Baechle .mode_clkcontrol = 0x00000000, /* /4=24Mhz */
545f95ec3c6SRalf Baechle .mode_pwmdiv = 0x8000063f,
546f95ec3c6SRalf Baechle .mode_pwmhi = 0x03400000,
547f95ec3c6SRalf Baechle .mode_outmask = 0x00fcfcfc,
548f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
549f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
550ecc2ea3bSManuel Lauss .lcdclk = 96,
551f95ec3c6SRalf Baechle 640, 480,
552f95ec3c6SRalf Baechle 640, 480,
553f95ec3c6SRalf Baechle },
554f95ec3c6SRalf Baechle
555f95ec3c6SRalf Baechle [7] = { /* Sharp 320x240 TFT */
556f95ec3c6SRalf Baechle .name = "Sharp_320x240_TFT",
557f95ec3c6SRalf Baechle .monspecs = {
558f95ec3c6SRalf Baechle .modedb = NULL,
559f95ec3c6SRalf Baechle .modedb_len = 0,
560f95ec3c6SRalf Baechle .hfmin = 12500,
561f95ec3c6SRalf Baechle .hfmax = 20000,
562f95ec3c6SRalf Baechle .vfmin = 38,
563f95ec3c6SRalf Baechle .vfmax = 81,
564f95ec3c6SRalf Baechle .dclkmin = 4500000,
565f95ec3c6SRalf Baechle .dclkmax = 6800000,
566f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
567f95ec3c6SRalf Baechle },
568f95ec3c6SRalf Baechle .mode_screen = LCD_SCREEN_SX_N(320) |
569f95ec3c6SRalf Baechle LCD_SCREEN_SY_N(240),
570f95ec3c6SRalf Baechle .mode_horztiming = LCD_HORZTIMING_HPW_N(60) |
571f95ec3c6SRalf Baechle LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
572f95ec3c6SRalf Baechle .mode_verttiming = LCD_VERTTIMING_VPW_N(2) |
573f95ec3c6SRalf Baechle LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
574f95ec3c6SRalf Baechle .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
575f95ec3c6SRalf Baechle .mode_pwmdiv = 0x8000063f,
576f95ec3c6SRalf Baechle .mode_pwmhi = 0x03400000,
577f95ec3c6SRalf Baechle .mode_outmask = 0x00fcfcfc,
578f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
579f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
580ecc2ea3bSManuel Lauss .lcdclk = 96, /* 96MHz AUXPLL */
581f95ec3c6SRalf Baechle 320, 320,
582f95ec3c6SRalf Baechle 240, 240,
583f95ec3c6SRalf Baechle },
584f95ec3c6SRalf Baechle
585f95ec3c6SRalf Baechle [8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
586f95ec3c6SRalf Baechle .name = "Toppoly_TD070WGCB2",
587f95ec3c6SRalf Baechle .monspecs = {
588f95ec3c6SRalf Baechle .modedb = NULL,
589f95ec3c6SRalf Baechle .modedb_len = 0,
590f95ec3c6SRalf Baechle .hfmin = 30000,
591f95ec3c6SRalf Baechle .hfmax = 70000,
592f95ec3c6SRalf Baechle .vfmin = 60,
593f95ec3c6SRalf Baechle .vfmax = 60,
594f95ec3c6SRalf Baechle .dclkmin = 6000000,
595f95ec3c6SRalf Baechle .dclkmax = 28000000,
596f95ec3c6SRalf Baechle .input = FB_DISP_RGB,
597f95ec3c6SRalf Baechle },
598f95ec3c6SRalf Baechle .mode_screen = LCD_SCREEN_SX_N(856) |
599f95ec3c6SRalf Baechle LCD_SCREEN_SY_N(480),
600f95ec3c6SRalf Baechle .mode_horztiming = LCD_HORZTIMING_HND2_N(43) |
601f95ec3c6SRalf Baechle LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
602f95ec3c6SRalf Baechle .mode_verttiming = LCD_VERTTIMING_VND2_N(20) |
603f95ec3c6SRalf Baechle LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
604f95ec3c6SRalf Baechle .mode_clkcontrol = 0x00020001, /* /4=24Mhz */
605f95ec3c6SRalf Baechle .mode_pwmdiv = 0x8000063f,
606f95ec3c6SRalf Baechle .mode_pwmhi = 0x03400000,
607f95ec3c6SRalf Baechle .mode_outmask = 0x00fcfcfc,
608f95ec3c6SRalf Baechle .mode_fifoctrl = 0x2f2f2f2f,
609f95ec3c6SRalf Baechle .mode_backlight = 0x00000000,
610ecc2ea3bSManuel Lauss .lcdclk = 96,
611f95ec3c6SRalf Baechle 856, 856,
612f95ec3c6SRalf Baechle 480, 480,
613f95ec3c6SRalf Baechle },
61464cd04d0SManuel Lauss [9] = {
61564cd04d0SManuel Lauss .name = "DB1300_800x480",
61664cd04d0SManuel Lauss .monspecs = {
61764cd04d0SManuel Lauss .modedb = NULL,
61864cd04d0SManuel Lauss .modedb_len = 0,
61964cd04d0SManuel Lauss .hfmin = 30000,
62064cd04d0SManuel Lauss .hfmax = 70000,
62164cd04d0SManuel Lauss .vfmin = 60,
62264cd04d0SManuel Lauss .vfmax = 60,
62364cd04d0SManuel Lauss .dclkmin = 6000000,
62464cd04d0SManuel Lauss .dclkmax = 28000000,
62564cd04d0SManuel Lauss .input = FB_DISP_RGB,
62664cd04d0SManuel Lauss },
62764cd04d0SManuel Lauss .mode_screen = LCD_SCREEN_SX_N(800) |
62864cd04d0SManuel Lauss LCD_SCREEN_SY_N(480),
62964cd04d0SManuel Lauss .mode_horztiming = LCD_HORZTIMING_HPW_N(5) |
63064cd04d0SManuel Lauss LCD_HORZTIMING_HND1_N(16) |
63164cd04d0SManuel Lauss LCD_HORZTIMING_HND2_N(8),
63264cd04d0SManuel Lauss .mode_verttiming = LCD_VERTTIMING_VPW_N(4) |
63364cd04d0SManuel Lauss LCD_VERTTIMING_VND1_N(8) |
63464cd04d0SManuel Lauss LCD_VERTTIMING_VND2_N(5),
63564cd04d0SManuel Lauss .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(1) |
63664cd04d0SManuel Lauss LCD_CLKCONTROL_IV |
63764cd04d0SManuel Lauss LCD_CLKCONTROL_IH,
63864cd04d0SManuel Lauss .mode_pwmdiv = 0x00000000,
63964cd04d0SManuel Lauss .mode_pwmhi = 0x00000000,
64064cd04d0SManuel Lauss .mode_outmask = 0x00FFFFFF,
64164cd04d0SManuel Lauss .mode_fifoctrl = 0x2f2f2f2f,
64264cd04d0SManuel Lauss .mode_backlight = 0x00000000,
643ecc2ea3bSManuel Lauss .lcdclk = 96,
64464cd04d0SManuel Lauss 800, 800,
64564cd04d0SManuel Lauss 480, 480,
64664cd04d0SManuel Lauss },
647f95ec3c6SRalf Baechle };
648f95ec3c6SRalf Baechle
649f95ec3c6SRalf Baechle #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
650f95ec3c6SRalf Baechle
651f95ec3c6SRalf Baechle /********************************************************************/
652f95ec3c6SRalf Baechle
winbpp(unsigned int winctrl1)653f95ec3c6SRalf Baechle static int winbpp (unsigned int winctrl1)
654f95ec3c6SRalf Baechle {
655f95ec3c6SRalf Baechle int bits = 0;
656f95ec3c6SRalf Baechle
657f95ec3c6SRalf Baechle /* how many bits are needed for each pixel format */
658f95ec3c6SRalf Baechle switch (winctrl1 & LCD_WINCTRL1_FRM) {
659f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_1BPP:
660f95ec3c6SRalf Baechle bits = 1;
661f95ec3c6SRalf Baechle break;
662f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_2BPP:
663f95ec3c6SRalf Baechle bits = 2;
664f95ec3c6SRalf Baechle break;
665f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_4BPP:
666f95ec3c6SRalf Baechle bits = 4;
667f95ec3c6SRalf Baechle break;
668f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_8BPP:
669f95ec3c6SRalf Baechle bits = 8;
670f95ec3c6SRalf Baechle break;
671f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_12BPP:
672f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPP655:
673f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPP565:
674f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPP556:
675f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPPI1555:
676f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPPI5551:
677f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPPA1555:
678f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_16BPPA5551:
679f95ec3c6SRalf Baechle bits = 16;
680f95ec3c6SRalf Baechle break;
681f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_24BPP:
682f95ec3c6SRalf Baechle case LCD_WINCTRL1_FRM_32BPP:
683f95ec3c6SRalf Baechle bits = 32;
684f95ec3c6SRalf Baechle break;
685f95ec3c6SRalf Baechle }
686f95ec3c6SRalf Baechle
687f95ec3c6SRalf Baechle return bits;
688f95ec3c6SRalf Baechle }
689f95ec3c6SRalf Baechle
fbinfo2index(struct fb_info * fb_info)690f95ec3c6SRalf Baechle static int fbinfo2index (struct fb_info *fb_info)
691f95ec3c6SRalf Baechle {
692f95ec3c6SRalf Baechle int i;
693f95ec3c6SRalf Baechle
6948be90b07SManuel Lauss for (i = 0; i < device_count; ++i) {
695c329f606SManuel Lauss if (fb_info == _au1200fb_infos[i])
696f95ec3c6SRalf Baechle return i;
697f95ec3c6SRalf Baechle }
698f95ec3c6SRalf Baechle printk("au1200fb: ERROR: fbinfo2index failed!\n");
699f95ec3c6SRalf Baechle return -1;
700f95ec3c6SRalf Baechle }
701f95ec3c6SRalf Baechle
au1200_setlocation(struct au1200fb_device * fbdev,int plane,int xpos,int ypos)702f95ec3c6SRalf Baechle static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
703f95ec3c6SRalf Baechle int xpos, int ypos)
704f95ec3c6SRalf Baechle {
705f95ec3c6SRalf Baechle uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
706f95ec3c6SRalf Baechle int xsz, ysz;
707f95ec3c6SRalf Baechle
708f95ec3c6SRalf Baechle /* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
709f95ec3c6SRalf Baechle
710f95ec3c6SRalf Baechle winctrl0 = lcd->window[plane].winctrl0;
711f95ec3c6SRalf Baechle winctrl1 = lcd->window[plane].winctrl1;
712f95ec3c6SRalf Baechle winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
713f95ec3c6SRalf Baechle winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
714f95ec3c6SRalf Baechle
715f95ec3c6SRalf Baechle /* Check for off-screen adjustments */
716f95ec3c6SRalf Baechle xsz = win->w[plane].xres;
717f95ec3c6SRalf Baechle ysz = win->w[plane].yres;
718f95ec3c6SRalf Baechle if ((xpos + win->w[plane].xres) > panel->Xres) {
719f95ec3c6SRalf Baechle /* Off-screen to the right */
720f95ec3c6SRalf Baechle xsz = panel->Xres - xpos; /* off by 1 ??? */
721f95ec3c6SRalf Baechle /*printk("off screen right\n");*/
722f95ec3c6SRalf Baechle }
723f95ec3c6SRalf Baechle
724f95ec3c6SRalf Baechle if ((ypos + win->w[plane].yres) > panel->Yres) {
725f95ec3c6SRalf Baechle /* Off-screen to the bottom */
726f95ec3c6SRalf Baechle ysz = panel->Yres - ypos; /* off by 1 ??? */
727f95ec3c6SRalf Baechle /*printk("off screen bottom\n");*/
728f95ec3c6SRalf Baechle }
729f95ec3c6SRalf Baechle
730f95ec3c6SRalf Baechle if (xpos < 0) {
731f95ec3c6SRalf Baechle /* Off-screen to the left */
732f95ec3c6SRalf Baechle xsz = win->w[plane].xres + xpos;
733f95ec3c6SRalf Baechle fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
734f95ec3c6SRalf Baechle xpos = 0;
735f95ec3c6SRalf Baechle /*printk("off screen left\n");*/
736f95ec3c6SRalf Baechle }
737f95ec3c6SRalf Baechle
738f95ec3c6SRalf Baechle if (ypos < 0) {
739f95ec3c6SRalf Baechle /* Off-screen to the top */
740f95ec3c6SRalf Baechle ysz = win->w[plane].yres + ypos;
741f95ec3c6SRalf Baechle /* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
742f95ec3c6SRalf Baechle ypos = 0;
743f95ec3c6SRalf Baechle /*printk("off screen top\n");*/
744f95ec3c6SRalf Baechle }
745f95ec3c6SRalf Baechle
746f95ec3c6SRalf Baechle /* record settings */
747f95ec3c6SRalf Baechle win->w[plane].xpos = xpos;
748f95ec3c6SRalf Baechle win->w[plane].ypos = ypos;
749f95ec3c6SRalf Baechle
750f95ec3c6SRalf Baechle xsz -= 1;
751f95ec3c6SRalf Baechle ysz -= 1;
752f95ec3c6SRalf Baechle winctrl0 |= (xpos << 21);
753f95ec3c6SRalf Baechle winctrl0 |= (ypos << 10);
754f95ec3c6SRalf Baechle winctrl1 |= (xsz << 11);
755f95ec3c6SRalf Baechle winctrl1 |= (ysz << 0);
756f95ec3c6SRalf Baechle
757f95ec3c6SRalf Baechle /* Disable the window while making changes, then restore WINEN */
758f95ec3c6SRalf Baechle winenable = lcd->winenable & (1 << plane);
7592f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
760f95ec3c6SRalf Baechle lcd->winenable &= ~(1 << plane);
761f95ec3c6SRalf Baechle lcd->window[plane].winctrl0 = winctrl0;
762f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = winctrl1;
763f95ec3c6SRalf Baechle lcd->window[plane].winbuf0 =
764f95ec3c6SRalf Baechle lcd->window[plane].winbuf1 = fbdev->fb_phys;
765f95ec3c6SRalf Baechle lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
766f95ec3c6SRalf Baechle lcd->winenable |= winenable;
7672f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
768f95ec3c6SRalf Baechle
769f95ec3c6SRalf Baechle return 0;
770f95ec3c6SRalf Baechle }
771f95ec3c6SRalf Baechle
au1200_setpanel(struct panel_settings * newpanel,struct au1200fb_platdata * pd)772a9b71a8fSManuel Lauss static void au1200_setpanel(struct panel_settings *newpanel,
773a9b71a8fSManuel Lauss struct au1200fb_platdata *pd)
774f95ec3c6SRalf Baechle {
775f95ec3c6SRalf Baechle /*
776f95ec3c6SRalf Baechle * Perform global setup/init of LCD controller
777f95ec3c6SRalf Baechle */
778f95ec3c6SRalf Baechle uint32 winenable;
779f95ec3c6SRalf Baechle
780f95ec3c6SRalf Baechle /* Make sure all windows disabled */
781f95ec3c6SRalf Baechle winenable = lcd->winenable;
782f95ec3c6SRalf Baechle lcd->winenable = 0;
7832f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
784f95ec3c6SRalf Baechle /*
785f95ec3c6SRalf Baechle * Ensure everything is disabled before reconfiguring
786f95ec3c6SRalf Baechle */
787f95ec3c6SRalf Baechle if (lcd->screen & LCD_SCREEN_SEN) {
788f95ec3c6SRalf Baechle /* Wait for vertical sync period */
789f95ec3c6SRalf Baechle lcd->intstatus = LCD_INT_SS;
7902f73bfbeSManuel Lauss while ((lcd->intstatus & LCD_INT_SS) == 0)
7912f73bfbeSManuel Lauss ;
792f95ec3c6SRalf Baechle
793f95ec3c6SRalf Baechle lcd->screen &= ~LCD_SCREEN_SEN; /*disable the controller*/
794f95ec3c6SRalf Baechle
795f95ec3c6SRalf Baechle do {
796f95ec3c6SRalf Baechle lcd->intstatus = lcd->intstatus; /*clear interrupts*/
7972f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
798f95ec3c6SRalf Baechle /*wait for controller to shut down*/
799f95ec3c6SRalf Baechle } while ((lcd->intstatus & LCD_INT_SD) == 0);
800f95ec3c6SRalf Baechle
801f95ec3c6SRalf Baechle /* Call shutdown of current panel (if up) */
802f95ec3c6SRalf Baechle /* this must occur last, because if an external clock is driving
803f95ec3c6SRalf Baechle the controller, the clock cannot be turned off before first
804f95ec3c6SRalf Baechle shutting down the controller.
805f95ec3c6SRalf Baechle */
806a9b71a8fSManuel Lauss if (pd->panel_shutdown)
807a9b71a8fSManuel Lauss pd->panel_shutdown();
808f95ec3c6SRalf Baechle }
809f95ec3c6SRalf Baechle
810f95ec3c6SRalf Baechle /* Newpanel == NULL indicates a shutdown operation only */
811f95ec3c6SRalf Baechle if (newpanel == NULL)
812f95ec3c6SRalf Baechle return;
813f95ec3c6SRalf Baechle
814f95ec3c6SRalf Baechle panel = newpanel;
815f95ec3c6SRalf Baechle
816f95ec3c6SRalf Baechle printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
817f95ec3c6SRalf Baechle
818f95ec3c6SRalf Baechle /*
819f95ec3c6SRalf Baechle * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
820f95ec3c6SRalf Baechle */
821f95ec3c6SRalf Baechle if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
822f95ec3c6SRalf Baechle {
823ecc2ea3bSManuel Lauss struct clk *c = clk_get(NULL, "lcd_intclk");
824ecc2ea3bSManuel Lauss long r, pc = panel->lcdclk * 1000000;
825ecc2ea3bSManuel Lauss
826ecc2ea3bSManuel Lauss if (!IS_ERR(c)) {
827ecc2ea3bSManuel Lauss r = clk_round_rate(c, pc);
828ecc2ea3bSManuel Lauss if ((pc - r) < (pc / 10)) { /* 10% slack */
829ecc2ea3bSManuel Lauss clk_set_rate(c, r);
830ecc2ea3bSManuel Lauss clk_prepare_enable(c);
831ecc2ea3bSManuel Lauss }
832ecc2ea3bSManuel Lauss clk_put(c);
833ecc2ea3bSManuel Lauss }
834f95ec3c6SRalf Baechle }
835f95ec3c6SRalf Baechle
836f95ec3c6SRalf Baechle /*
837f95ec3c6SRalf Baechle * Configure panel timings
838f95ec3c6SRalf Baechle */
839f95ec3c6SRalf Baechle lcd->screen = panel->mode_screen;
840f95ec3c6SRalf Baechle lcd->horztiming = panel->mode_horztiming;
841f95ec3c6SRalf Baechle lcd->verttiming = panel->mode_verttiming;
842f95ec3c6SRalf Baechle lcd->clkcontrol = panel->mode_clkcontrol;
843f95ec3c6SRalf Baechle lcd->pwmdiv = panel->mode_pwmdiv;
844f95ec3c6SRalf Baechle lcd->pwmhi = panel->mode_pwmhi;
845f95ec3c6SRalf Baechle lcd->outmask = panel->mode_outmask;
846f95ec3c6SRalf Baechle lcd->fifoctrl = panel->mode_fifoctrl;
8472f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
848f95ec3c6SRalf Baechle
849f95ec3c6SRalf Baechle /* fixme: Check window settings to make sure still valid
850f95ec3c6SRalf Baechle * for new geometry */
851f95ec3c6SRalf Baechle #if 0
852f95ec3c6SRalf Baechle au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
853f95ec3c6SRalf Baechle au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
854f95ec3c6SRalf Baechle au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
855f95ec3c6SRalf Baechle au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
856f95ec3c6SRalf Baechle #endif
857f95ec3c6SRalf Baechle lcd->winenable = winenable;
858f95ec3c6SRalf Baechle
859f95ec3c6SRalf Baechle /*
860f95ec3c6SRalf Baechle * Re-enable screen now that it is configured
861f95ec3c6SRalf Baechle */
862f95ec3c6SRalf Baechle lcd->screen |= LCD_SCREEN_SEN;
8632f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
864f95ec3c6SRalf Baechle
865f95ec3c6SRalf Baechle /* Call init of panel */
866a9b71a8fSManuel Lauss if (pd->panel_init)
867a9b71a8fSManuel Lauss pd->panel_init();
868f95ec3c6SRalf Baechle
869f95ec3c6SRalf Baechle /* FIX!!!! not appropriate on panel change!!! Global setup/init */
870f95ec3c6SRalf Baechle lcd->intenable = 0;
871f95ec3c6SRalf Baechle lcd->intstatus = ~0;
872f95ec3c6SRalf Baechle lcd->backcolor = win->mode_backcolor;
873f95ec3c6SRalf Baechle
874f95ec3c6SRalf Baechle /* Setup Color Key - FIX!!! */
875f95ec3c6SRalf Baechle lcd->colorkey = win->mode_colorkey;
876f95ec3c6SRalf Baechle lcd->colorkeymsk = win->mode_colorkeymsk;
877f95ec3c6SRalf Baechle
878f95ec3c6SRalf Baechle /* Setup HWCursor - FIX!!! Need to support this eventually */
879f95ec3c6SRalf Baechle lcd->hwc.cursorctrl = 0;
880f95ec3c6SRalf Baechle lcd->hwc.cursorpos = 0;
881f95ec3c6SRalf Baechle lcd->hwc.cursorcolor0 = 0;
882f95ec3c6SRalf Baechle lcd->hwc.cursorcolor1 = 0;
883f95ec3c6SRalf Baechle lcd->hwc.cursorcolor2 = 0;
884f95ec3c6SRalf Baechle lcd->hwc.cursorcolor3 = 0;
885f95ec3c6SRalf Baechle
886f95ec3c6SRalf Baechle
887f95ec3c6SRalf Baechle #if 0
888f95ec3c6SRalf Baechle #define D(X) printk("%25s: %08X\n", #X, X)
889f95ec3c6SRalf Baechle D(lcd->screen);
890f95ec3c6SRalf Baechle D(lcd->horztiming);
891f95ec3c6SRalf Baechle D(lcd->verttiming);
892f95ec3c6SRalf Baechle D(lcd->clkcontrol);
893f95ec3c6SRalf Baechle D(lcd->pwmdiv);
894f95ec3c6SRalf Baechle D(lcd->pwmhi);
895f95ec3c6SRalf Baechle D(lcd->outmask);
896f95ec3c6SRalf Baechle D(lcd->fifoctrl);
897f95ec3c6SRalf Baechle D(lcd->window[0].winctrl0);
898f95ec3c6SRalf Baechle D(lcd->window[0].winctrl1);
899f95ec3c6SRalf Baechle D(lcd->window[0].winctrl2);
900f95ec3c6SRalf Baechle D(lcd->window[0].winbuf0);
901f95ec3c6SRalf Baechle D(lcd->window[0].winbuf1);
902f95ec3c6SRalf Baechle D(lcd->window[0].winbufctrl);
903f95ec3c6SRalf Baechle D(lcd->window[1].winctrl0);
904f95ec3c6SRalf Baechle D(lcd->window[1].winctrl1);
905f95ec3c6SRalf Baechle D(lcd->window[1].winctrl2);
906f95ec3c6SRalf Baechle D(lcd->window[1].winbuf0);
907f95ec3c6SRalf Baechle D(lcd->window[1].winbuf1);
908f95ec3c6SRalf Baechle D(lcd->window[1].winbufctrl);
909f95ec3c6SRalf Baechle D(lcd->window[2].winctrl0);
910f95ec3c6SRalf Baechle D(lcd->window[2].winctrl1);
911f95ec3c6SRalf Baechle D(lcd->window[2].winctrl2);
912f95ec3c6SRalf Baechle D(lcd->window[2].winbuf0);
913f95ec3c6SRalf Baechle D(lcd->window[2].winbuf1);
914f95ec3c6SRalf Baechle D(lcd->window[2].winbufctrl);
915f95ec3c6SRalf Baechle D(lcd->window[3].winctrl0);
916f95ec3c6SRalf Baechle D(lcd->window[3].winctrl1);
917f95ec3c6SRalf Baechle D(lcd->window[3].winctrl2);
918f95ec3c6SRalf Baechle D(lcd->window[3].winbuf0);
919f95ec3c6SRalf Baechle D(lcd->window[3].winbuf1);
920f95ec3c6SRalf Baechle D(lcd->window[3].winbufctrl);
921f95ec3c6SRalf Baechle D(lcd->winenable);
922f95ec3c6SRalf Baechle D(lcd->intenable);
923f95ec3c6SRalf Baechle D(lcd->intstatus);
924f95ec3c6SRalf Baechle D(lcd->backcolor);
925f95ec3c6SRalf Baechle D(lcd->winenable);
926f95ec3c6SRalf Baechle D(lcd->colorkey);
927f95ec3c6SRalf Baechle D(lcd->colorkeymsk);
928f95ec3c6SRalf Baechle D(lcd->hwc.cursorctrl);
929f95ec3c6SRalf Baechle D(lcd->hwc.cursorpos);
930f95ec3c6SRalf Baechle D(lcd->hwc.cursorcolor0);
931f95ec3c6SRalf Baechle D(lcd->hwc.cursorcolor1);
932f95ec3c6SRalf Baechle D(lcd->hwc.cursorcolor2);
933f95ec3c6SRalf Baechle D(lcd->hwc.cursorcolor3);
934f95ec3c6SRalf Baechle #endif
935f95ec3c6SRalf Baechle }
936f95ec3c6SRalf Baechle
au1200_setmode(struct au1200fb_device * fbdev)937f95ec3c6SRalf Baechle static void au1200_setmode(struct au1200fb_device *fbdev)
938f95ec3c6SRalf Baechle {
939f95ec3c6SRalf Baechle int plane = fbdev->plane;
940f95ec3c6SRalf Baechle /* Window/plane setup */
941f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = ( 0
942f95ec3c6SRalf Baechle | LCD_WINCTRL1_PRI_N(plane)
943f95ec3c6SRalf Baechle | win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
944f95ec3c6SRalf Baechle ) ;
945f95ec3c6SRalf Baechle
946f95ec3c6SRalf Baechle au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
947f95ec3c6SRalf Baechle
948f95ec3c6SRalf Baechle lcd->window[plane].winctrl2 = ( 0
949f95ec3c6SRalf Baechle | LCD_WINCTRL2_CKMODE_00
950f95ec3c6SRalf Baechle | LCD_WINCTRL2_DBM
951c329f606SManuel Lauss | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length)
952f95ec3c6SRalf Baechle | LCD_WINCTRL2_SCX_1
953f95ec3c6SRalf Baechle | LCD_WINCTRL2_SCY_1
954f95ec3c6SRalf Baechle ) ;
955f95ec3c6SRalf Baechle lcd->winenable |= win->w[plane].mode_winenable;
9562f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
957f95ec3c6SRalf Baechle }
958f95ec3c6SRalf Baechle
959f95ec3c6SRalf Baechle
960f95ec3c6SRalf Baechle /* Inline helpers */
961f95ec3c6SRalf Baechle
962f95ec3c6SRalf Baechle /*#define panel_is_dual(panel) ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
963f95ec3c6SRalf Baechle /*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
964f95ec3c6SRalf Baechle
965f95ec3c6SRalf Baechle #define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
966f95ec3c6SRalf Baechle
967f95ec3c6SRalf Baechle /* Bitfields format supported by the controller. */
968f95ec3c6SRalf Baechle static struct fb_bitfield rgb_bitfields[][4] = {
969f95ec3c6SRalf Baechle /* Red, Green, Blue, Transp */
970f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPP655 >> 25] =
971f95ec3c6SRalf Baechle { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
972f95ec3c6SRalf Baechle
973f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPP565 >> 25] =
974f95ec3c6SRalf Baechle { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
975f95ec3c6SRalf Baechle
976f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPP556 >> 25] =
977f95ec3c6SRalf Baechle { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
978f95ec3c6SRalf Baechle
979f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
980f95ec3c6SRalf Baechle { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
981f95ec3c6SRalf Baechle
982f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
983f95ec3c6SRalf Baechle { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
984f95ec3c6SRalf Baechle
985f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
986f95ec3c6SRalf Baechle { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
987f95ec3c6SRalf Baechle
988f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
989f95ec3c6SRalf Baechle { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
990f95ec3c6SRalf Baechle
991f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_24BPP >> 25] =
992f95ec3c6SRalf Baechle { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
993f95ec3c6SRalf Baechle
994f95ec3c6SRalf Baechle [LCD_WINCTRL1_FRM_32BPP >> 25] =
995f95ec3c6SRalf Baechle { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
996f95ec3c6SRalf Baechle };
997f95ec3c6SRalf Baechle
998f95ec3c6SRalf Baechle /*-------------------------------------------------------------------------*/
999f95ec3c6SRalf Baechle
1000f95ec3c6SRalf Baechle /* Helpers */
1001f95ec3c6SRalf Baechle
au1200fb_update_fbinfo(struct fb_info * fbi)1002f95ec3c6SRalf Baechle static void au1200fb_update_fbinfo(struct fb_info *fbi)
1003f95ec3c6SRalf Baechle {
1004f95ec3c6SRalf Baechle /* FIX!!!! This also needs to take the window pixel format into account!!! */
1005f95ec3c6SRalf Baechle
1006f95ec3c6SRalf Baechle /* Update var-dependent FB info */
1007f95ec3c6SRalf Baechle if (panel_is_color(panel)) {
1008f95ec3c6SRalf Baechle if (fbi->var.bits_per_pixel <= 8) {
1009f95ec3c6SRalf Baechle /* palettized */
1010f95ec3c6SRalf Baechle fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
1011f95ec3c6SRalf Baechle fbi->fix.line_length = fbi->var.xres_virtual /
1012f95ec3c6SRalf Baechle (8/fbi->var.bits_per_pixel);
1013f95ec3c6SRalf Baechle } else {
1014f95ec3c6SRalf Baechle /* non-palettized */
1015f95ec3c6SRalf Baechle fbi->fix.visual = FB_VISUAL_TRUECOLOR;
1016f95ec3c6SRalf Baechle fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
1017f95ec3c6SRalf Baechle }
1018f95ec3c6SRalf Baechle } else {
1019f95ec3c6SRalf Baechle /* mono FIX!!! mono 8 and 4 bits */
1020f95ec3c6SRalf Baechle fbi->fix.visual = FB_VISUAL_MONO10;
1021f95ec3c6SRalf Baechle fbi->fix.line_length = fbi->var.xres_virtual / 8;
1022f95ec3c6SRalf Baechle }
1023f95ec3c6SRalf Baechle
1024f95ec3c6SRalf Baechle fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
1025f95ec3c6SRalf Baechle print_dbg("line length: %d\n", fbi->fix.line_length);
1026f95ec3c6SRalf Baechle print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
1027f95ec3c6SRalf Baechle }
1028f95ec3c6SRalf Baechle
1029f95ec3c6SRalf Baechle /*-------------------------------------------------------------------------*/
1030f95ec3c6SRalf Baechle
1031f95ec3c6SRalf Baechle /* AU1200 framebuffer driver */
1032f95ec3c6SRalf Baechle
1033f95ec3c6SRalf Baechle /* fb_check_var
1034f95ec3c6SRalf Baechle * Validate var settings with hardware restrictions and modify it if necessary
1035f95ec3c6SRalf Baechle */
au1200fb_fb_check_var(struct fb_var_screeninfo * var,struct fb_info * fbi)1036f95ec3c6SRalf Baechle static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
1037f95ec3c6SRalf Baechle struct fb_info *fbi)
1038f95ec3c6SRalf Baechle {
1039c329f606SManuel Lauss struct au1200fb_device *fbdev = fbi->par;
1040f95ec3c6SRalf Baechle u32 pixclock;
1041f95ec3c6SRalf Baechle int screen_size, plane;
1042f95ec3c6SRalf Baechle
104344a3b36bSWei Chen if (!var->pixclock)
104444a3b36bSWei Chen return -EINVAL;
104544a3b36bSWei Chen
1046f95ec3c6SRalf Baechle plane = fbdev->plane;
1047f95ec3c6SRalf Baechle
1048f95ec3c6SRalf Baechle /* Make sure that the mode respect all LCD controller and
1049f95ec3c6SRalf Baechle * panel restrictions. */
1050f95ec3c6SRalf Baechle var->xres = win->w[plane].xres;
1051f95ec3c6SRalf Baechle var->yres = win->w[plane].yres;
1052f95ec3c6SRalf Baechle
1053f95ec3c6SRalf Baechle /* No need for virtual resolution support */
1054f95ec3c6SRalf Baechle var->xres_virtual = var->xres;
1055f95ec3c6SRalf Baechle var->yres_virtual = var->yres;
1056f95ec3c6SRalf Baechle
1057f95ec3c6SRalf Baechle var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
1058f95ec3c6SRalf Baechle
1059f95ec3c6SRalf Baechle screen_size = var->xres_virtual * var->yres_virtual;
1060f95ec3c6SRalf Baechle if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
1061f95ec3c6SRalf Baechle else screen_size /= (8/var->bits_per_pixel);
1062f95ec3c6SRalf Baechle
1063f95ec3c6SRalf Baechle if (fbdev->fb_len < screen_size)
1064f95ec3c6SRalf Baechle return -EINVAL; /* Virtual screen is to big, abort */
1065f95ec3c6SRalf Baechle
1066f95ec3c6SRalf Baechle /* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
1067f95ec3c6SRalf Baechle /* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
1068f95ec3c6SRalf Baechle * clock can only be obtain by dividing this value by an even integer.
1069f95ec3c6SRalf Baechle * Fallback to a slower pixel clock if necessary. */
1070f95ec3c6SRalf Baechle pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
1071732eacc0SHagen Paul Pfeifer pixclock = min3(pixclock, fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2);
1072f95ec3c6SRalf Baechle
1073f95ec3c6SRalf Baechle if (AU1200_LCD_MAX_CLK % pixclock) {
1074f95ec3c6SRalf Baechle int diff = AU1200_LCD_MAX_CLK % pixclock;
1075f95ec3c6SRalf Baechle pixclock -= diff;
1076f95ec3c6SRalf Baechle }
1077f95ec3c6SRalf Baechle
1078f95ec3c6SRalf Baechle var->pixclock = KHZ2PICOS(pixclock/1000);
1079f95ec3c6SRalf Baechle #if 0
1080f95ec3c6SRalf Baechle if (!panel_is_active(panel)) {
1081f95ec3c6SRalf Baechle int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
1082f95ec3c6SRalf Baechle
1083f95ec3c6SRalf Baechle if (!panel_is_color(panel)
1084f95ec3c6SRalf Baechle && (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
1085f95ec3c6SRalf Baechle /* STN 8bit mono panel support is up to 6MHz pixclock */
1086f95ec3c6SRalf Baechle var->pixclock = KHZ2PICOS(6000);
1087f95ec3c6SRalf Baechle } else if (!pcd) {
1088f95ec3c6SRalf Baechle /* Other STN panel support is up to 12MHz */
1089f95ec3c6SRalf Baechle var->pixclock = KHZ2PICOS(12000);
1090f95ec3c6SRalf Baechle }
1091f95ec3c6SRalf Baechle }
1092f95ec3c6SRalf Baechle #endif
1093f95ec3c6SRalf Baechle /* Set bitfield accordingly */
1094f95ec3c6SRalf Baechle switch (var->bits_per_pixel) {
1095f95ec3c6SRalf Baechle case 16:
1096f95ec3c6SRalf Baechle {
1097f95ec3c6SRalf Baechle /* 16bpp True color.
1098f95ec3c6SRalf Baechle * These must be set to MATCH WINCTRL[FORM] */
1099f95ec3c6SRalf Baechle int idx;
1100f95ec3c6SRalf Baechle idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
1101f95ec3c6SRalf Baechle var->red = rgb_bitfields[idx][0];
1102f95ec3c6SRalf Baechle var->green = rgb_bitfields[idx][1];
1103f95ec3c6SRalf Baechle var->blue = rgb_bitfields[idx][2];
1104f95ec3c6SRalf Baechle var->transp = rgb_bitfields[idx][3];
1105f95ec3c6SRalf Baechle break;
1106f95ec3c6SRalf Baechle }
1107f95ec3c6SRalf Baechle
1108f95ec3c6SRalf Baechle case 32:
1109f95ec3c6SRalf Baechle {
1110f95ec3c6SRalf Baechle /* 32bpp True color.
1111f95ec3c6SRalf Baechle * These must be set to MATCH WINCTRL[FORM] */
1112f95ec3c6SRalf Baechle int idx;
1113f95ec3c6SRalf Baechle idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
1114f95ec3c6SRalf Baechle var->red = rgb_bitfields[idx][0];
1115f95ec3c6SRalf Baechle var->green = rgb_bitfields[idx][1];
1116f95ec3c6SRalf Baechle var->blue = rgb_bitfields[idx][2];
1117f95ec3c6SRalf Baechle var->transp = rgb_bitfields[idx][3];
1118f95ec3c6SRalf Baechle break;
1119f95ec3c6SRalf Baechle }
1120f95ec3c6SRalf Baechle default:
1121f95ec3c6SRalf Baechle print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
1122f95ec3c6SRalf Baechle return -EINVAL;
1123f95ec3c6SRalf Baechle }
1124f95ec3c6SRalf Baechle
1125f95ec3c6SRalf Baechle return 0;
1126f95ec3c6SRalf Baechle }
1127f95ec3c6SRalf Baechle
1128f95ec3c6SRalf Baechle /* fb_set_par
1129f95ec3c6SRalf Baechle * Set hardware with var settings. This will enable the controller with a
1130f95ec3c6SRalf Baechle * specific mode, normally validated with the fb_check_var method
1131f95ec3c6SRalf Baechle */
au1200fb_fb_set_par(struct fb_info * fbi)1132f95ec3c6SRalf Baechle static int au1200fb_fb_set_par(struct fb_info *fbi)
1133f95ec3c6SRalf Baechle {
1134c329f606SManuel Lauss struct au1200fb_device *fbdev = fbi->par;
1135f95ec3c6SRalf Baechle
1136f95ec3c6SRalf Baechle au1200fb_update_fbinfo(fbi);
1137f95ec3c6SRalf Baechle au1200_setmode(fbdev);
1138f95ec3c6SRalf Baechle
1139f95ec3c6SRalf Baechle return 0;
1140f95ec3c6SRalf Baechle }
1141f95ec3c6SRalf Baechle
1142f95ec3c6SRalf Baechle /* fb_setcolreg
1143f95ec3c6SRalf Baechle * Set color in LCD palette.
1144f95ec3c6SRalf Baechle */
au1200fb_fb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * fbi)1145f95ec3c6SRalf Baechle static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
1146f95ec3c6SRalf Baechle unsigned blue, unsigned transp, struct fb_info *fbi)
1147f95ec3c6SRalf Baechle {
1148f95ec3c6SRalf Baechle volatile u32 *palette = lcd->palette;
1149f95ec3c6SRalf Baechle u32 value;
1150f95ec3c6SRalf Baechle
1151f95ec3c6SRalf Baechle if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
1152f95ec3c6SRalf Baechle return -EINVAL;
1153f95ec3c6SRalf Baechle
1154f95ec3c6SRalf Baechle if (fbi->var.grayscale) {
1155f95ec3c6SRalf Baechle /* Convert color to grayscale */
1156f95ec3c6SRalf Baechle red = green = blue =
1157f95ec3c6SRalf Baechle (19595 * red + 38470 * green + 7471 * blue) >> 16;
1158f95ec3c6SRalf Baechle }
1159f95ec3c6SRalf Baechle
1160f95ec3c6SRalf Baechle if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
1161f95ec3c6SRalf Baechle /* Place color in the pseudopalette */
1162f95ec3c6SRalf Baechle if (regno > 16)
1163f95ec3c6SRalf Baechle return -EINVAL;
1164f95ec3c6SRalf Baechle
1165f95ec3c6SRalf Baechle palette = (u32*) fbi->pseudo_palette;
1166f95ec3c6SRalf Baechle
1167f95ec3c6SRalf Baechle red >>= (16 - fbi->var.red.length);
1168f95ec3c6SRalf Baechle green >>= (16 - fbi->var.green.length);
1169f95ec3c6SRalf Baechle blue >>= (16 - fbi->var.blue.length);
1170f95ec3c6SRalf Baechle
1171f95ec3c6SRalf Baechle value = (red << fbi->var.red.offset) |
1172f95ec3c6SRalf Baechle (green << fbi->var.green.offset)|
1173f95ec3c6SRalf Baechle (blue << fbi->var.blue.offset);
1174f95ec3c6SRalf Baechle value &= 0xFFFF;
1175f95ec3c6SRalf Baechle
1176f95ec3c6SRalf Baechle } else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
1177f95ec3c6SRalf Baechle /* COLOR TFT PALLETTIZED (use RGB 565) */
1178f95ec3c6SRalf Baechle value = (red & 0xF800)|((green >> 5) &
1179f95ec3c6SRalf Baechle 0x07E0)|((blue >> 11) & 0x001F);
1180f95ec3c6SRalf Baechle value &= 0xFFFF;
1181f95ec3c6SRalf Baechle
1182f95ec3c6SRalf Baechle } else if (0 /*panel_is_color(fbdev->panel)*/) {
1183f95ec3c6SRalf Baechle /* COLOR STN MODE */
1184f95ec3c6SRalf Baechle value = 0x1234;
1185f95ec3c6SRalf Baechle value &= 0xFFF;
1186f95ec3c6SRalf Baechle } else {
1187f95ec3c6SRalf Baechle /* MONOCHROME MODE */
1188f95ec3c6SRalf Baechle value = (green >> 12) & 0x000F;
1189f95ec3c6SRalf Baechle value &= 0xF;
1190f95ec3c6SRalf Baechle }
1191f95ec3c6SRalf Baechle
1192f95ec3c6SRalf Baechle palette[regno] = value;
1193f95ec3c6SRalf Baechle
1194f95ec3c6SRalf Baechle return 0;
1195f95ec3c6SRalf Baechle }
1196f95ec3c6SRalf Baechle
1197f95ec3c6SRalf Baechle /* fb_blank
1198f95ec3c6SRalf Baechle * Blank the screen. Depending on the mode, the screen will be
1199f95ec3c6SRalf Baechle * activated with the backlight color, or desactivated
1200f95ec3c6SRalf Baechle */
au1200fb_fb_blank(int blank_mode,struct fb_info * fbi)1201f95ec3c6SRalf Baechle static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
1202f95ec3c6SRalf Baechle {
1203a9b71a8fSManuel Lauss struct au1200fb_device *fbdev = fbi->par;
1204a9b71a8fSManuel Lauss
1205f95ec3c6SRalf Baechle /* Short-circuit screen blanking */
1206f95ec3c6SRalf Baechle if (noblanking)
1207f95ec3c6SRalf Baechle return 0;
1208f95ec3c6SRalf Baechle
1209f95ec3c6SRalf Baechle switch (blank_mode) {
1210f95ec3c6SRalf Baechle
1211f95ec3c6SRalf Baechle case FB_BLANK_UNBLANK:
1212f95ec3c6SRalf Baechle case FB_BLANK_NORMAL:
1213f95ec3c6SRalf Baechle /* printk("turn on panel\n"); */
1214a9b71a8fSManuel Lauss au1200_setpanel(panel, fbdev->pd);
1215f95ec3c6SRalf Baechle break;
1216f95ec3c6SRalf Baechle case FB_BLANK_VSYNC_SUSPEND:
1217f95ec3c6SRalf Baechle case FB_BLANK_HSYNC_SUSPEND:
1218f95ec3c6SRalf Baechle case FB_BLANK_POWERDOWN:
1219f95ec3c6SRalf Baechle /* printk("turn off panel\n"); */
1220a9b71a8fSManuel Lauss au1200_setpanel(NULL, fbdev->pd);
1221f95ec3c6SRalf Baechle break;
1222f95ec3c6SRalf Baechle default:
1223f95ec3c6SRalf Baechle break;
1224f95ec3c6SRalf Baechle
1225f95ec3c6SRalf Baechle }
1226f95ec3c6SRalf Baechle
1227f95ec3c6SRalf Baechle /* FB_BLANK_NORMAL is a soft blank */
1228f95ec3c6SRalf Baechle return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
1229f95ec3c6SRalf Baechle }
1230f95ec3c6SRalf Baechle
1231f95ec3c6SRalf Baechle /* fb_mmap
1232f95ec3c6SRalf Baechle * Map video memory in user space. We don't use the generic fb_mmap
1233f95ec3c6SRalf Baechle * method mainly to allow the use of the TLB streaming flag (CCA=6)
1234f95ec3c6SRalf Baechle */
au1200fb_fb_mmap(struct fb_info * info,struct vm_area_struct * vma)1235f95ec3c6SRalf Baechle static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1236f95ec3c6SRalf Baechle {
1237c329f606SManuel Lauss struct au1200fb_device *fbdev = info->par;
1238f95ec3c6SRalf Baechle
123976f92201SThomas Zimmermann vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
124076f92201SThomas Zimmermann
1241212efde8SCai Huoqing return dma_mmap_coherent(fbdev->dev, vma,
1242212efde8SCai Huoqing fbdev->fb_mem, fbdev->fb_phys, fbdev->fb_len);
1243f95ec3c6SRalf Baechle }
1244f95ec3c6SRalf Baechle
set_global(u_int cmd,struct au1200_lcd_global_regs_t * pdata)1245f95ec3c6SRalf Baechle static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
1246f95ec3c6SRalf Baechle {
1247f95ec3c6SRalf Baechle
1248f95ec3c6SRalf Baechle unsigned int hi1, divider;
1249f95ec3c6SRalf Baechle
1250f95ec3c6SRalf Baechle /* SCREEN_SIZE: user cannot reset size, must switch panel choice */
1251f95ec3c6SRalf Baechle
1252f95ec3c6SRalf Baechle if (pdata->flags & SCREEN_BACKCOLOR)
1253f95ec3c6SRalf Baechle lcd->backcolor = pdata->backcolor;
1254f95ec3c6SRalf Baechle
1255f95ec3c6SRalf Baechle if (pdata->flags & SCREEN_BRIGHTNESS) {
1256f95ec3c6SRalf Baechle
1257f95ec3c6SRalf Baechle // limit brightness pwm duty to >= 30/1600
1258f95ec3c6SRalf Baechle if (pdata->brightness < 30) {
1259f95ec3c6SRalf Baechle pdata->brightness = 30;
1260f95ec3c6SRalf Baechle }
1261f95ec3c6SRalf Baechle divider = (lcd->pwmdiv & 0x3FFFF) + 1;
1262f95ec3c6SRalf Baechle hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
1263f95ec3c6SRalf Baechle lcd->pwmhi &= 0xFFFF;
1264f95ec3c6SRalf Baechle lcd->pwmhi |= (hi1 << 16);
1265f95ec3c6SRalf Baechle }
1266f95ec3c6SRalf Baechle
1267f95ec3c6SRalf Baechle if (pdata->flags & SCREEN_COLORKEY)
1268f95ec3c6SRalf Baechle lcd->colorkey = pdata->colorkey;
1269f95ec3c6SRalf Baechle
1270f95ec3c6SRalf Baechle if (pdata->flags & SCREEN_MASK)
1271f95ec3c6SRalf Baechle lcd->colorkeymsk = pdata->mask;
12722f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
1273f95ec3c6SRalf Baechle }
1274f95ec3c6SRalf Baechle
get_global(u_int cmd,struct au1200_lcd_global_regs_t * pdata)1275f95ec3c6SRalf Baechle static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
1276f95ec3c6SRalf Baechle {
1277f95ec3c6SRalf Baechle unsigned int hi1, divider;
1278f95ec3c6SRalf Baechle
1279f95ec3c6SRalf Baechle pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
1280f95ec3c6SRalf Baechle pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
1281f95ec3c6SRalf Baechle
1282f95ec3c6SRalf Baechle pdata->backcolor = lcd->backcolor;
1283f95ec3c6SRalf Baechle pdata->colorkey = lcd->colorkey;
1284f95ec3c6SRalf Baechle pdata->mask = lcd->colorkeymsk;
1285f95ec3c6SRalf Baechle
1286f95ec3c6SRalf Baechle // brightness
1287f95ec3c6SRalf Baechle hi1 = (lcd->pwmhi >> 16) + 1;
1288f95ec3c6SRalf Baechle divider = (lcd->pwmdiv & 0x3FFFF) + 1;
1289f95ec3c6SRalf Baechle pdata->brightness = ((hi1 << 8) / divider) - 1;
12902f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
1291f95ec3c6SRalf Baechle }
1292f95ec3c6SRalf Baechle
set_window(unsigned int plane,struct au1200_lcd_window_regs_t * pdata)1293f95ec3c6SRalf Baechle static void set_window(unsigned int plane,
1294f95ec3c6SRalf Baechle struct au1200_lcd_window_regs_t *pdata)
1295f95ec3c6SRalf Baechle {
1296f95ec3c6SRalf Baechle unsigned int val, bpp;
1297f95ec3c6SRalf Baechle
1298f95ec3c6SRalf Baechle /* Window control register 0 */
1299f95ec3c6SRalf Baechle if (pdata->flags & WIN_POSITION) {
1300f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
1301f95ec3c6SRalf Baechle LCD_WINCTRL0_OY);
1302f95ec3c6SRalf Baechle val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
1303f95ec3c6SRalf Baechle val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
1304f95ec3c6SRalf Baechle lcd->window[plane].winctrl0 = val;
1305f95ec3c6SRalf Baechle }
1306f95ec3c6SRalf Baechle if (pdata->flags & WIN_ALPHA_COLOR) {
1307f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
1308f95ec3c6SRalf Baechle val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
1309f95ec3c6SRalf Baechle lcd->window[plane].winctrl0 = val;
1310f95ec3c6SRalf Baechle }
1311f95ec3c6SRalf Baechle if (pdata->flags & WIN_ALPHA_MODE) {
1312f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
1313f95ec3c6SRalf Baechle val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
1314f95ec3c6SRalf Baechle lcd->window[plane].winctrl0 = val;
1315f95ec3c6SRalf Baechle }
1316f95ec3c6SRalf Baechle
1317f95ec3c6SRalf Baechle /* Window control register 1 */
1318f95ec3c6SRalf Baechle if (pdata->flags & WIN_PRIORITY) {
1319f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
1320f95ec3c6SRalf Baechle val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
1321f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = val;
1322f95ec3c6SRalf Baechle }
1323f95ec3c6SRalf Baechle if (pdata->flags & WIN_CHANNEL) {
1324f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
1325f95ec3c6SRalf Baechle val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
1326f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = val;
1327f95ec3c6SRalf Baechle }
1328f95ec3c6SRalf Baechle if (pdata->flags & WIN_BUFFER_FORMAT) {
1329f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
1330f95ec3c6SRalf Baechle val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
1331f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = val;
1332f95ec3c6SRalf Baechle }
1333f95ec3c6SRalf Baechle if (pdata->flags & WIN_COLOR_ORDER) {
1334f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
1335f95ec3c6SRalf Baechle val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
1336f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = val;
1337f95ec3c6SRalf Baechle }
1338f95ec3c6SRalf Baechle if (pdata->flags & WIN_PIXEL_ORDER) {
1339f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
1340f95ec3c6SRalf Baechle val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
1341f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = val;
1342f95ec3c6SRalf Baechle }
1343f95ec3c6SRalf Baechle if (pdata->flags & WIN_SIZE) {
1344f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
1345f95ec3c6SRalf Baechle LCD_WINCTRL1_SZY);
1346f95ec3c6SRalf Baechle val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
1347f95ec3c6SRalf Baechle val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
1348f95ec3c6SRalf Baechle lcd->window[plane].winctrl1 = val;
1349f95ec3c6SRalf Baechle /* program buffer line width */
1350f95ec3c6SRalf Baechle bpp = winbpp(val) / 8;
1351f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
1352f95ec3c6SRalf Baechle val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
1353f95ec3c6SRalf Baechle lcd->window[plane].winctrl2 = val;
1354f95ec3c6SRalf Baechle }
1355f95ec3c6SRalf Baechle
1356f95ec3c6SRalf Baechle /* Window control register 2 */
1357f95ec3c6SRalf Baechle if (pdata->flags & WIN_COLORKEY_MODE) {
1358f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
1359f95ec3c6SRalf Baechle val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
1360f95ec3c6SRalf Baechle lcd->window[plane].winctrl2 = val;
1361f95ec3c6SRalf Baechle }
1362f95ec3c6SRalf Baechle if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
1363f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
1364f95ec3c6SRalf Baechle val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
1365f95ec3c6SRalf Baechle lcd->window[plane].winctrl2 = val;
1366f95ec3c6SRalf Baechle }
1367f95ec3c6SRalf Baechle if (pdata->flags & WIN_RAM_ARRAY_MODE) {
1368f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
1369f95ec3c6SRalf Baechle val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
1370f95ec3c6SRalf Baechle lcd->window[plane].winctrl2 = val;
1371f95ec3c6SRalf Baechle }
1372f95ec3c6SRalf Baechle
1373f95ec3c6SRalf Baechle /* Buffer line width programmed with WIN_SIZE */
1374f95ec3c6SRalf Baechle
1375f95ec3c6SRalf Baechle if (pdata->flags & WIN_BUFFER_SCALE) {
1376f95ec3c6SRalf Baechle val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
1377f95ec3c6SRalf Baechle LCD_WINCTRL2_SCY);
1378f95ec3c6SRalf Baechle val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
1379f95ec3c6SRalf Baechle val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
1380f95ec3c6SRalf Baechle lcd->window[plane].winctrl2 = val;
1381f95ec3c6SRalf Baechle }
1382f95ec3c6SRalf Baechle
1383f95ec3c6SRalf Baechle if (pdata->flags & WIN_ENABLE) {
1384f95ec3c6SRalf Baechle val = lcd->winenable;
1385f95ec3c6SRalf Baechle val &= ~(1<<plane);
1386f95ec3c6SRalf Baechle val |= (pdata->enable & 1) << plane;
1387f95ec3c6SRalf Baechle lcd->winenable = val;
1388f95ec3c6SRalf Baechle }
13892f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
1390f95ec3c6SRalf Baechle }
1391f95ec3c6SRalf Baechle
get_window(unsigned int plane,struct au1200_lcd_window_regs_t * pdata)1392f95ec3c6SRalf Baechle static void get_window(unsigned int plane,
1393f95ec3c6SRalf Baechle struct au1200_lcd_window_regs_t *pdata)
1394f95ec3c6SRalf Baechle {
1395f95ec3c6SRalf Baechle /* Window control register 0 */
1396f95ec3c6SRalf Baechle pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
1397f95ec3c6SRalf Baechle pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
1398f95ec3c6SRalf Baechle pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
1399f95ec3c6SRalf Baechle pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
1400f95ec3c6SRalf Baechle
1401f95ec3c6SRalf Baechle /* Window control register 1 */
1402f95ec3c6SRalf Baechle pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
1403f95ec3c6SRalf Baechle pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
1404f95ec3c6SRalf Baechle pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
1405f95ec3c6SRalf Baechle pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
1406f95ec3c6SRalf Baechle pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
1407f95ec3c6SRalf Baechle pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
1408f95ec3c6SRalf Baechle pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
1409f95ec3c6SRalf Baechle
1410f95ec3c6SRalf Baechle /* Window control register 2 */
1411f95ec3c6SRalf Baechle pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
1412f95ec3c6SRalf Baechle pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
1413f95ec3c6SRalf Baechle pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
1414f95ec3c6SRalf Baechle
1415f95ec3c6SRalf Baechle pdata->enable = (lcd->winenable >> plane) & 1;
14162f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
1417f95ec3c6SRalf Baechle }
1418f95ec3c6SRalf Baechle
au1200fb_ioctl(struct fb_info * info,unsigned int cmd,unsigned long arg)1419f95ec3c6SRalf Baechle static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
1420f95ec3c6SRalf Baechle unsigned long arg)
1421f95ec3c6SRalf Baechle {
1422a9b71a8fSManuel Lauss struct au1200fb_device *fbdev = info->par;
1423f95ec3c6SRalf Baechle int plane;
1424f95ec3c6SRalf Baechle int val;
1425f95ec3c6SRalf Baechle
1426f95ec3c6SRalf Baechle plane = fbinfo2index(info);
1427f95ec3c6SRalf Baechle print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
1428f95ec3c6SRalf Baechle
1429f95ec3c6SRalf Baechle if (cmd == AU1200_LCD_FB_IOCTL) {
1430f95ec3c6SRalf Baechle struct au1200_lcd_iodata_t iodata;
1431f95ec3c6SRalf Baechle
1432f95ec3c6SRalf Baechle if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
1433f95ec3c6SRalf Baechle return -EFAULT;
1434f95ec3c6SRalf Baechle
1435f95ec3c6SRalf Baechle print_dbg("FB IOCTL called\n");
1436f95ec3c6SRalf Baechle
1437f95ec3c6SRalf Baechle switch (iodata.subcmd) {
1438f95ec3c6SRalf Baechle case AU1200_LCD_SET_SCREEN:
1439f95ec3c6SRalf Baechle print_dbg("AU1200_LCD_SET_SCREEN\n");
1440f95ec3c6SRalf Baechle set_global(cmd, &iodata.global);
1441f95ec3c6SRalf Baechle break;
1442f95ec3c6SRalf Baechle
1443f95ec3c6SRalf Baechle case AU1200_LCD_GET_SCREEN:
1444f95ec3c6SRalf Baechle print_dbg("AU1200_LCD_GET_SCREEN\n");
1445f95ec3c6SRalf Baechle get_global(cmd, &iodata.global);
1446f95ec3c6SRalf Baechle break;
1447f95ec3c6SRalf Baechle
1448f95ec3c6SRalf Baechle case AU1200_LCD_SET_WINDOW:
1449f95ec3c6SRalf Baechle print_dbg("AU1200_LCD_SET_WINDOW\n");
1450f95ec3c6SRalf Baechle set_window(plane, &iodata.window);
1451f95ec3c6SRalf Baechle break;
1452f95ec3c6SRalf Baechle
1453f95ec3c6SRalf Baechle case AU1200_LCD_GET_WINDOW:
1454f95ec3c6SRalf Baechle print_dbg("AU1200_LCD_GET_WINDOW\n");
1455f95ec3c6SRalf Baechle get_window(plane, &iodata.window);
1456f95ec3c6SRalf Baechle break;
1457f95ec3c6SRalf Baechle
1458f95ec3c6SRalf Baechle case AU1200_LCD_SET_PANEL:
1459f95ec3c6SRalf Baechle print_dbg("AU1200_LCD_SET_PANEL\n");
1460f95ec3c6SRalf Baechle if ((iodata.global.panel_choice >= 0) &&
1461f95ec3c6SRalf Baechle (iodata.global.panel_choice <
1462f95ec3c6SRalf Baechle NUM_PANELS))
1463f95ec3c6SRalf Baechle {
1464f95ec3c6SRalf Baechle struct panel_settings *newpanel;
1465f95ec3c6SRalf Baechle panel_index = iodata.global.panel_choice;
1466f95ec3c6SRalf Baechle newpanel = &known_lcd_panels[panel_index];
1467a9b71a8fSManuel Lauss au1200_setpanel(newpanel, fbdev->pd);
1468f95ec3c6SRalf Baechle }
1469f95ec3c6SRalf Baechle break;
1470f95ec3c6SRalf Baechle
1471f95ec3c6SRalf Baechle case AU1200_LCD_GET_PANEL:
1472f95ec3c6SRalf Baechle print_dbg("AU1200_LCD_GET_PANEL\n");
1473f95ec3c6SRalf Baechle iodata.global.panel_choice = panel_index;
1474f95ec3c6SRalf Baechle break;
1475f95ec3c6SRalf Baechle
1476f95ec3c6SRalf Baechle default:
1477f95ec3c6SRalf Baechle return -EINVAL;
1478f95ec3c6SRalf Baechle }
1479f95ec3c6SRalf Baechle
1480f95ec3c6SRalf Baechle val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
1481f95ec3c6SRalf Baechle if (val) {
1482f95ec3c6SRalf Baechle print_dbg("error: could not copy %d bytes\n", val);
1483f95ec3c6SRalf Baechle return -EFAULT;
1484f95ec3c6SRalf Baechle }
1485f95ec3c6SRalf Baechle }
1486f95ec3c6SRalf Baechle
1487f95ec3c6SRalf Baechle return 0;
1488f95ec3c6SRalf Baechle }
1489f95ec3c6SRalf Baechle
1490f95ec3c6SRalf Baechle
14918a48ac33SJani Nikula static const struct fb_ops au1200fb_fb_ops = {
1492f95ec3c6SRalf Baechle .owner = THIS_MODULE,
1493dfc30522SThomas Zimmermann __FB_DEFAULT_DMAMEM_OPS_RDWR,
1494f95ec3c6SRalf Baechle .fb_check_var = au1200fb_fb_check_var,
1495f95ec3c6SRalf Baechle .fb_set_par = au1200fb_fb_set_par,
1496f95ec3c6SRalf Baechle .fb_setcolreg = au1200fb_fb_setcolreg,
1497f95ec3c6SRalf Baechle .fb_blank = au1200fb_fb_blank,
1498dfc30522SThomas Zimmermann __FB_DEFAULT_DMAMEM_OPS_DRAW,
1499f95ec3c6SRalf Baechle .fb_sync = NULL,
1500f95ec3c6SRalf Baechle .fb_ioctl = au1200fb_ioctl,
1501f95ec3c6SRalf Baechle .fb_mmap = au1200fb_fb_mmap,
1502f95ec3c6SRalf Baechle };
1503f95ec3c6SRalf Baechle
1504f95ec3c6SRalf Baechle /*-------------------------------------------------------------------------*/
1505f95ec3c6SRalf Baechle
au1200fb_handle_irq(int irq,void * dev_id)15067d12e780SDavid Howells static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
1507f95ec3c6SRalf Baechle {
1508f95ec3c6SRalf Baechle /* Nothing to do for now, just clear any pending interrupt */
1509f95ec3c6SRalf Baechle lcd->intstatus = lcd->intstatus;
15102f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
1511f95ec3c6SRalf Baechle
1512f95ec3c6SRalf Baechle return IRQ_HANDLED;
1513f95ec3c6SRalf Baechle }
1514f95ec3c6SRalf Baechle
1515f95ec3c6SRalf Baechle /*-------------------------------------------------------------------------*/
1516f95ec3c6SRalf Baechle
1517f95ec3c6SRalf Baechle /* AU1200 LCD device probe helpers */
1518f95ec3c6SRalf Baechle
au1200fb_init_fbinfo(struct au1200fb_device * fbdev)1519f95ec3c6SRalf Baechle static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
1520f95ec3c6SRalf Baechle {
1521c329f606SManuel Lauss struct fb_info *fbi = fbdev->fb_info;
152206208656SChristophe JAILLET int bpp, ret;
1523f95ec3c6SRalf Baechle
1524f95ec3c6SRalf Baechle fbi->fbops = &au1200fb_fb_ops;
1525f95ec3c6SRalf Baechle
1526f95ec3c6SRalf Baechle bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
1527f95ec3c6SRalf Baechle
1528f95ec3c6SRalf Baechle /* Copy monitor specs from panel data */
1529f95ec3c6SRalf Baechle /* fixme: we're setting up LCD controller windows, so these dont give a
1530f95ec3c6SRalf Baechle damn as to what the monitor specs are (the panel itself does, but that
153125985edcSLucas De Marchi isn't done here...so maybe need a generic catchall monitor setting??? */
1532f95ec3c6SRalf Baechle memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
1533f95ec3c6SRalf Baechle
1534f95ec3c6SRalf Baechle /* We first try the user mode passed in argument. If that failed,
1535f95ec3c6SRalf Baechle * or if no one has been specified, we default to the first mode of the
1536f95ec3c6SRalf Baechle * panel list. Note that after this call, var data will be set */
1537f95ec3c6SRalf Baechle if (!fb_find_mode(&fbi->var,
1538f95ec3c6SRalf Baechle fbi,
1539f95ec3c6SRalf Baechle NULL, /* drv_info.opt_mode, */
1540f95ec3c6SRalf Baechle fbi->monspecs.modedb,
1541f95ec3c6SRalf Baechle fbi->monspecs.modedb_len,
1542f95ec3c6SRalf Baechle fbi->monspecs.modedb,
1543f95ec3c6SRalf Baechle bpp)) {
1544f95ec3c6SRalf Baechle
1545f95ec3c6SRalf Baechle print_err("Cannot find valid mode for panel %s", panel->name);
1546f95ec3c6SRalf Baechle return -EFAULT;
1547f95ec3c6SRalf Baechle }
1548f95ec3c6SRalf Baechle
1549dd00cc48SYoann Padioleau fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
1550ab798b90SChristophe JAILLET if (!fbi->pseudo_palette)
1551f95ec3c6SRalf Baechle return -ENOMEM;
1552f95ec3c6SRalf Baechle
155306208656SChristophe JAILLET ret = fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0);
155406208656SChristophe JAILLET if (ret < 0) {
1555f95ec3c6SRalf Baechle print_err("Fail to allocate colormap (%d entries)",
1556f95ec3c6SRalf Baechle AU1200_LCD_NBR_PALETTE_ENTRIES);
155706208656SChristophe JAILLET return ret;
1558f95ec3c6SRalf Baechle }
1559f95ec3c6SRalf Baechle
156027d50646SJustin Stitt strscpy(fbi->fix.id, "AU1200");
1561f95ec3c6SRalf Baechle fbi->fix.smem_start = fbdev->fb_phys;
1562f95ec3c6SRalf Baechle fbi->fix.smem_len = fbdev->fb_len;
1563f95ec3c6SRalf Baechle fbi->fix.type = FB_TYPE_PACKED_PIXELS;
1564f95ec3c6SRalf Baechle fbi->fix.xpanstep = 0;
1565f95ec3c6SRalf Baechle fbi->fix.ypanstep = 0;
1566f95ec3c6SRalf Baechle fbi->fix.mmio_start = 0;
1567f95ec3c6SRalf Baechle fbi->fix.mmio_len = 0;
1568f95ec3c6SRalf Baechle fbi->fix.accel = FB_ACCEL_NONE;
1569f95ec3c6SRalf Baechle
1570cb99b486SThomas Zimmermann fbi->flags |= FBINFO_VIRTFB;
1571cb99b486SThomas Zimmermann
1572f5eccc49SThomas Zimmermann fbi->screen_buffer = fbdev->fb_mem;
1573f95ec3c6SRalf Baechle
1574f95ec3c6SRalf Baechle au1200fb_update_fbinfo(fbi);
1575f95ec3c6SRalf Baechle
1576f95ec3c6SRalf Baechle return 0;
1577f95ec3c6SRalf Baechle }
1578f95ec3c6SRalf Baechle
1579f95ec3c6SRalf Baechle /*-------------------------------------------------------------------------*/
1580f95ec3c6SRalf Baechle
1581f95ec3c6SRalf Baechle
au1200fb_setup(struct au1200fb_platdata * pd)1582a9b71a8fSManuel Lauss static int au1200fb_setup(struct au1200fb_platdata *pd)
1583a9b71a8fSManuel Lauss {
1584a9b71a8fSManuel Lauss char *options = NULL;
1585a9b71a8fSManuel Lauss char *this_opt, *endptr;
1586a9b71a8fSManuel Lauss int num_panels = ARRAY_SIZE(known_lcd_panels);
1587a9b71a8fSManuel Lauss int panel_idx = -1;
1588a9b71a8fSManuel Lauss
1589a9b71a8fSManuel Lauss fb_get_options(DRIVER_NAME, &options);
1590a9b71a8fSManuel Lauss
1591a9b71a8fSManuel Lauss if (!options)
1592a9b71a8fSManuel Lauss goto out;
1593a9b71a8fSManuel Lauss
1594a9b71a8fSManuel Lauss while ((this_opt = strsep(&options, ",")) != NULL) {
1595a9b71a8fSManuel Lauss /* Panel option - can be panel name,
1596a9b71a8fSManuel Lauss * "bs" for board-switch, or number/index */
1597a9b71a8fSManuel Lauss if (!strncmp(this_opt, "panel:", 6)) {
1598a9b71a8fSManuel Lauss int i;
1599a9b71a8fSManuel Lauss long int li;
1600a9b71a8fSManuel Lauss char *endptr;
1601a9b71a8fSManuel Lauss this_opt += 6;
1602a9b71a8fSManuel Lauss /* First check for index, which allows
1603a9b71a8fSManuel Lauss * to short circuit this mess */
1604a9b71a8fSManuel Lauss li = simple_strtol(this_opt, &endptr, 0);
1605a9b71a8fSManuel Lauss if (*endptr == '\0')
1606a9b71a8fSManuel Lauss panel_idx = (int)li;
1607a9b71a8fSManuel Lauss else if (strcmp(this_opt, "bs") == 0)
1608a9b71a8fSManuel Lauss panel_idx = pd->panel_index();
1609a9b71a8fSManuel Lauss else {
1610a9b71a8fSManuel Lauss for (i = 0; i < num_panels; i++) {
1611a9b71a8fSManuel Lauss if (!strcmp(this_opt,
1612a9b71a8fSManuel Lauss known_lcd_panels[i].name)) {
1613a9b71a8fSManuel Lauss panel_idx = i;
1614a9b71a8fSManuel Lauss break;
1615a9b71a8fSManuel Lauss }
1616a9b71a8fSManuel Lauss }
1617a9b71a8fSManuel Lauss }
1618a9b71a8fSManuel Lauss if ((panel_idx < 0) || (panel_idx >= num_panels))
1619a9b71a8fSManuel Lauss print_warn("Panel %s not supported!", this_opt);
1620a9b71a8fSManuel Lauss else
1621a9b71a8fSManuel Lauss panel_index = panel_idx;
1622a9b71a8fSManuel Lauss
1623a9b71a8fSManuel Lauss } else if (strncmp(this_opt, "nohwcursor", 10) == 0)
1624a9b71a8fSManuel Lauss nohwcursor = 1;
1625a9b71a8fSManuel Lauss else if (strncmp(this_opt, "devices:", 8) == 0) {
1626a9b71a8fSManuel Lauss this_opt += 8;
1627a9b71a8fSManuel Lauss device_count = simple_strtol(this_opt, &endptr, 0);
1628a9b71a8fSManuel Lauss if ((device_count < 0) ||
1629a9b71a8fSManuel Lauss (device_count > MAX_DEVICE_COUNT))
1630a9b71a8fSManuel Lauss device_count = MAX_DEVICE_COUNT;
1631a9b71a8fSManuel Lauss } else if (strncmp(this_opt, "wincfg:", 7) == 0) {
1632a9b71a8fSManuel Lauss this_opt += 7;
1633a9b71a8fSManuel Lauss window_index = simple_strtol(this_opt, &endptr, 0);
1634a9b71a8fSManuel Lauss if ((window_index < 0) ||
1635a9b71a8fSManuel Lauss (window_index >= ARRAY_SIZE(windows)))
1636a9b71a8fSManuel Lauss window_index = DEFAULT_WINDOW_INDEX;
1637a9b71a8fSManuel Lauss } else if (strncmp(this_opt, "off", 3) == 0)
1638a9b71a8fSManuel Lauss return 1;
1639a9b71a8fSManuel Lauss else
1640a9b71a8fSManuel Lauss print_warn("Unsupported option \"%s\"", this_opt);
1641a9b71a8fSManuel Lauss }
1642a9b71a8fSManuel Lauss
1643a9b71a8fSManuel Lauss out:
1644a9b71a8fSManuel Lauss return 0;
1645a9b71a8fSManuel Lauss }
1646a9b71a8fSManuel Lauss
1647a9b71a8fSManuel Lauss /* AU1200 LCD controller device driver */
au1200fb_drv_probe(struct platform_device * dev)164848c68c4fSGreg Kroah-Hartman static int au1200fb_drv_probe(struct platform_device *dev)
1649f95ec3c6SRalf Baechle {
1650f95ec3c6SRalf Baechle struct au1200fb_device *fbdev;
1651a9b71a8fSManuel Lauss struct au1200fb_platdata *pd;
1652c329f606SManuel Lauss struct fb_info *fbi = NULL;
16531630d85aSManuel Lauss int bpp, plane, ret, irq;
1654f95ec3c6SRalf Baechle
1655a9b71a8fSManuel Lauss print_info("" DRIVER_DESC "");
1656a9b71a8fSManuel Lauss
1657a9b71a8fSManuel Lauss pd = dev->dev.platform_data;
1658a9b71a8fSManuel Lauss if (!pd)
1659a9b71a8fSManuel Lauss return -ENODEV;
1660a9b71a8fSManuel Lauss
1661a9b71a8fSManuel Lauss /* Setup driver with options */
1662a9b71a8fSManuel Lauss if (au1200fb_setup(pd))
1663a9b71a8fSManuel Lauss return -ENODEV;
1664a9b71a8fSManuel Lauss
1665a9b71a8fSManuel Lauss /* Point to the panel selected */
1666a9b71a8fSManuel Lauss panel = &known_lcd_panels[panel_index];
1667a9b71a8fSManuel Lauss win = &windows[window_index];
1668a9b71a8fSManuel Lauss
1669a9b71a8fSManuel Lauss printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
1670a9b71a8fSManuel Lauss printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
1671a9b71a8fSManuel Lauss
16728be90b07SManuel Lauss for (plane = 0; plane < device_count; ++plane) {
1673f95ec3c6SRalf Baechle bpp = winbpp(win->w[plane].mode_winctrl1);
1674f95ec3c6SRalf Baechle if (win->w[plane].xres == 0)
1675f95ec3c6SRalf Baechle win->w[plane].xres = panel->Xres;
1676f95ec3c6SRalf Baechle if (win->w[plane].yres == 0)
1677f95ec3c6SRalf Baechle win->w[plane].yres = panel->Yres;
1678f95ec3c6SRalf Baechle
1679c329f606SManuel Lauss fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
1680c329f606SManuel Lauss &dev->dev);
16818cae353eSChristophe JAILLET if (!fbi) {
16828cae353eSChristophe JAILLET ret = -ENOMEM;
1683c329f606SManuel Lauss goto failed;
16848cae353eSChristophe JAILLET }
1685c329f606SManuel Lauss
1686c329f606SManuel Lauss _au1200fb_infos[plane] = fbi;
1687c329f606SManuel Lauss fbdev = fbi->par;
1688c329f606SManuel Lauss fbdev->fb_info = fbi;
1689a9b71a8fSManuel Lauss fbdev->pd = pd;
1690e0b29902SChristoph Hellwig fbdev->dev = &dev->dev;
1691c329f606SManuel Lauss
1692f95ec3c6SRalf Baechle fbdev->plane = plane;
1693f95ec3c6SRalf Baechle
1694f95ec3c6SRalf Baechle /* Allocate the framebuffer to the maximum screen size */
1695f95ec3c6SRalf Baechle fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
1696f95ec3c6SRalf Baechle
169763d36c95SChristoph Hellwig fbdev->fb_mem = dmam_alloc_attrs(&dev->dev,
1698f95ec3c6SRalf Baechle PAGE_ALIGN(fbdev->fb_len),
16995ae01cbaSChristoph Hellwig &fbdev->fb_phys, GFP_KERNEL, 0);
1700f95ec3c6SRalf Baechle if (!fbdev->fb_mem) {
17013879490fSColin Ian King print_err("fail to allocate framebuffer (size: %dK))",
1702f95ec3c6SRalf Baechle fbdev->fb_len / 1024);
1703451f1306SChristophe JAILLET ret = -ENOMEM;
1704451f1306SChristophe JAILLET goto failed;
1705f95ec3c6SRalf Baechle }
1706f95ec3c6SRalf Baechle
1707f95ec3c6SRalf Baechle print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
1708f95ec3c6SRalf Baechle print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
1709f95ec3c6SRalf Baechle
1710f95ec3c6SRalf Baechle /* Init FB data */
1711ab798b90SChristophe JAILLET ret = au1200fb_init_fbinfo(fbdev);
1712ab798b90SChristophe JAILLET if (ret < 0)
1713f95ec3c6SRalf Baechle goto failed;
1714f95ec3c6SRalf Baechle
1715f95ec3c6SRalf Baechle /* Register new framebuffer */
1716c329f606SManuel Lauss ret = register_framebuffer(fbi);
1717c329f606SManuel Lauss if (ret < 0) {
1718f95ec3c6SRalf Baechle print_err("cannot register new framebuffer");
1719f95ec3c6SRalf Baechle goto failed;
1720f95ec3c6SRalf Baechle }
1721f95ec3c6SRalf Baechle
1722c329f606SManuel Lauss au1200fb_fb_set_par(fbi);
1723f95ec3c6SRalf Baechle }
1724f95ec3c6SRalf Baechle
1725f95ec3c6SRalf Baechle /* Now hook interrupt too */
17261630d85aSManuel Lauss irq = platform_get_irq(dev, 0);
17274e88761fSZhang Shurong if (irq < 0)
17284e88761fSZhang Shurong return irq;
17294e88761fSZhang Shurong
17301630d85aSManuel Lauss ret = request_irq(irq, au1200fb_handle_irq,
1731f8798ccbSYong Zhang IRQF_SHARED, "lcd", (void *)dev);
17321630d85aSManuel Lauss if (ret) {
1733f95ec3c6SRalf Baechle print_err("fail to request interrupt line %d (err: %d)",
17341630d85aSManuel Lauss irq, ret);
1735f95ec3c6SRalf Baechle goto failed;
1736f95ec3c6SRalf Baechle }
1737f95ec3c6SRalf Baechle
1738a9b71a8fSManuel Lauss platform_set_drvdata(dev, pd);
1739a9b71a8fSManuel Lauss
1740a9b71a8fSManuel Lauss /* Kickstart the panel */
1741a9b71a8fSManuel Lauss au1200_setpanel(panel, pd);
1742a9b71a8fSManuel Lauss
1743f95ec3c6SRalf Baechle return 0;
1744f95ec3c6SRalf Baechle
1745f95ec3c6SRalf Baechle failed:
17466bbbb680SChristophe JAILLET for (plane = 0; plane < device_count; ++plane) {
17476bbbb680SChristophe JAILLET fbi = _au1200fb_infos[plane];
17486bbbb680SChristophe JAILLET if (!fbi)
17496bbbb680SChristophe JAILLET break;
17506bbbb680SChristophe JAILLET
17516bbbb680SChristophe JAILLET /* Clean up all probe data */
17526bbbb680SChristophe JAILLET unregister_framebuffer(fbi);
1753c329f606SManuel Lauss if (fbi->cmap.len != 0)
1754c329f606SManuel Lauss fb_dealloc_cmap(&fbi->cmap);
1755c329f606SManuel Lauss kfree(fbi->pseudo_palette);
17566bbbb680SChristophe JAILLET
17576bbbb680SChristophe JAILLET framebuffer_release(fbi);
17586bbbb680SChristophe JAILLET _au1200fb_infos[plane] = NULL;
1759c329f606SManuel Lauss }
1760f95ec3c6SRalf Baechle return ret;
1761f95ec3c6SRalf Baechle }
1762f95ec3c6SRalf Baechle
au1200fb_drv_remove(struct platform_device * dev)17634b88b6e1SUwe Kleine-König static void au1200fb_drv_remove(struct platform_device *dev)
1764f95ec3c6SRalf Baechle {
1765a9b71a8fSManuel Lauss struct au1200fb_platdata *pd = platform_get_drvdata(dev);
1766c329f606SManuel Lauss struct fb_info *fbi;
1767f95ec3c6SRalf Baechle int plane;
1768f95ec3c6SRalf Baechle
1769f95ec3c6SRalf Baechle /* Turn off the panel */
1770a9b71a8fSManuel Lauss au1200_setpanel(NULL, pd);
1771f95ec3c6SRalf Baechle
17728be90b07SManuel Lauss for (plane = 0; plane < device_count; ++plane) {
1773c329f606SManuel Lauss fbi = _au1200fb_infos[plane];
1774f95ec3c6SRalf Baechle
1775f95ec3c6SRalf Baechle /* Clean up all probe data */
1776c329f606SManuel Lauss unregister_framebuffer(fbi);
1777c329f606SManuel Lauss if (fbi->cmap.len != 0)
1778c329f606SManuel Lauss fb_dealloc_cmap(&fbi->cmap);
1779c329f606SManuel Lauss kfree(fbi->pseudo_palette);
1780c329f606SManuel Lauss
1781c329f606SManuel Lauss framebuffer_release(fbi);
1782c329f606SManuel Lauss _au1200fb_infos[plane] = NULL;
1783f95ec3c6SRalf Baechle }
1784f95ec3c6SRalf Baechle
17851630d85aSManuel Lauss free_irq(platform_get_irq(dev, 0), (void *)dev);
1786f95ec3c6SRalf Baechle }
1787f95ec3c6SRalf Baechle
1788f95ec3c6SRalf Baechle #ifdef CONFIG_PM
au1200fb_drv_suspend(struct device * dev)178998707fccSManuel Lauss static int au1200fb_drv_suspend(struct device *dev)
1790f95ec3c6SRalf Baechle {
1791a9b71a8fSManuel Lauss struct au1200fb_platdata *pd = dev_get_drvdata(dev);
1792a9b71a8fSManuel Lauss au1200_setpanel(NULL, pd);
179398707fccSManuel Lauss
179498707fccSManuel Lauss lcd->outmask = 0;
17952f73bfbeSManuel Lauss wmb(); /* drain writebuffer */
179698707fccSManuel Lauss
1797f95ec3c6SRalf Baechle return 0;
1798f95ec3c6SRalf Baechle }
1799f95ec3c6SRalf Baechle
au1200fb_drv_resume(struct device * dev)180098707fccSManuel Lauss static int au1200fb_drv_resume(struct device *dev)
1801f95ec3c6SRalf Baechle {
1802a9b71a8fSManuel Lauss struct au1200fb_platdata *pd = dev_get_drvdata(dev);
180398707fccSManuel Lauss struct fb_info *fbi;
180498707fccSManuel Lauss int i;
180598707fccSManuel Lauss
180698707fccSManuel Lauss /* Kickstart the panel */
1807a9b71a8fSManuel Lauss au1200_setpanel(panel, pd);
180898707fccSManuel Lauss
18098be90b07SManuel Lauss for (i = 0; i < device_count; i++) {
181098707fccSManuel Lauss fbi = _au1200fb_infos[i];
181198707fccSManuel Lauss au1200fb_fb_set_par(fbi);
181298707fccSManuel Lauss }
181398707fccSManuel Lauss
1814f95ec3c6SRalf Baechle return 0;
1815f95ec3c6SRalf Baechle }
181698707fccSManuel Lauss
181798707fccSManuel Lauss static const struct dev_pm_ops au1200fb_pmops = {
181898707fccSManuel Lauss .suspend = au1200fb_drv_suspend,
181998707fccSManuel Lauss .resume = au1200fb_drv_resume,
182098707fccSManuel Lauss .freeze = au1200fb_drv_suspend,
182198707fccSManuel Lauss .thaw = au1200fb_drv_resume,
182298707fccSManuel Lauss };
182398707fccSManuel Lauss
182498707fccSManuel Lauss #define AU1200FB_PMOPS (&au1200fb_pmops)
182598707fccSManuel Lauss
182698707fccSManuel Lauss #else
182798707fccSManuel Lauss #define AU1200FB_PMOPS NULL
1828f95ec3c6SRalf Baechle #endif /* CONFIG_PM */
1829f95ec3c6SRalf Baechle
18307a192ec3SMing Lei static struct platform_driver au1200fb_driver = {
18317a192ec3SMing Lei .driver = {
1832f95ec3c6SRalf Baechle .name = "au1200-lcd",
183398707fccSManuel Lauss .pm = AU1200FB_PMOPS,
18347a192ec3SMing Lei },
1835f95ec3c6SRalf Baechle .probe = au1200fb_drv_probe,
183601ecc142SUwe Kleine-König .remove = au1200fb_drv_remove,
1837f95ec3c6SRalf Baechle };
1838d07b3191SHanjun Guo module_platform_driver(au1200fb_driver);
1839f95ec3c6SRalf Baechle
1840f95ec3c6SRalf Baechle MODULE_DESCRIPTION(DRIVER_DESC);
1841f95ec3c6SRalf Baechle MODULE_LICENSE("GPL");
1842