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