162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * BRIEF MODULE DESCRIPTION
362306a36Sopenharmony_ci *	Au1200 LCD Driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2004-2005 AMD
662306a36Sopenharmony_ci * Author: AMD
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on:
962306a36Sopenharmony_ci * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
1062306a36Sopenharmony_ci *  Created 28 Dec 1997 by Geert Uytterhoeven
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  This program is free software; you can redistribute	 it and/or modify it
1362306a36Sopenharmony_ci *  under  the terms of	 the GNU General  Public License as published by the
1462306a36Sopenharmony_ci *  Free Software Foundation;  either version 2 of the	License, or (at your
1562306a36Sopenharmony_ci *  option) any later version.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
1862306a36Sopenharmony_ci *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
1962306a36Sopenharmony_ci *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
2062306a36Sopenharmony_ci *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
2162306a36Sopenharmony_ci *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2262306a36Sopenharmony_ci *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
2362306a36Sopenharmony_ci *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2462306a36Sopenharmony_ci *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
2562306a36Sopenharmony_ci *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2662306a36Sopenharmony_ci *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci *  You should have received a copy of the  GNU General Public License along
2962306a36Sopenharmony_ci *  with this program; if not, write  to the Free Software Foundation, Inc.,
3062306a36Sopenharmony_ci *  675 Mass Ave, Cambridge, MA 02139, USA.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/clk.h>
3462306a36Sopenharmony_ci#include <linux/module.h>
3562306a36Sopenharmony_ci#include <linux/platform_device.h>
3662306a36Sopenharmony_ci#include <linux/kernel.h>
3762306a36Sopenharmony_ci#include <linux/errno.h>
3862306a36Sopenharmony_ci#include <linux/string.h>
3962306a36Sopenharmony_ci#include <linux/mm.h>
4062306a36Sopenharmony_ci#include <linux/fb.h>
4162306a36Sopenharmony_ci#include <linux/init.h>
4262306a36Sopenharmony_ci#include <linux/interrupt.h>
4362306a36Sopenharmony_ci#include <linux/ctype.h>
4462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
4562306a36Sopenharmony_ci#include <linux/slab.h>
4662306a36Sopenharmony_ci#include <linux/uaccess.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#include <asm/mach-au1x00/au1000.h>
4962306a36Sopenharmony_ci#include <asm/mach-au1x00/au1200fb.h>	/* platform_data */
5062306a36Sopenharmony_ci#include "au1200fb.h"
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define DRIVER_NAME "au1200fb"
5362306a36Sopenharmony_ci#define DRIVER_DESC "LCD controller driver for AU1200 processors"
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define DEBUG 0
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
5862306a36Sopenharmony_ci#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
5962306a36Sopenharmony_ci#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#if DEBUG
6262306a36Sopenharmony_ci#define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg)
6362306a36Sopenharmony_ci#else
6462306a36Sopenharmony_ci#define print_dbg(f, arg...) do {} while (0)
6562306a36Sopenharmony_ci#endif
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define AU1200_LCD_FB_IOCTL 0x46FF
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define AU1200_LCD_SET_SCREEN 1
7162306a36Sopenharmony_ci#define AU1200_LCD_GET_SCREEN 2
7262306a36Sopenharmony_ci#define AU1200_LCD_SET_WINDOW 3
7362306a36Sopenharmony_ci#define AU1200_LCD_GET_WINDOW 4
7462306a36Sopenharmony_ci#define AU1200_LCD_SET_PANEL  5
7562306a36Sopenharmony_ci#define AU1200_LCD_GET_PANEL  6
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define SCREEN_SIZE		    (1<< 1)
7862306a36Sopenharmony_ci#define SCREEN_BACKCOLOR    (1<< 2)
7962306a36Sopenharmony_ci#define SCREEN_BRIGHTNESS   (1<< 3)
8062306a36Sopenharmony_ci#define SCREEN_COLORKEY     (1<< 4)
8162306a36Sopenharmony_ci#define SCREEN_MASK         (1<< 5)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct au1200_lcd_global_regs_t {
8462306a36Sopenharmony_ci	unsigned int flags;
8562306a36Sopenharmony_ci	unsigned int xsize;
8662306a36Sopenharmony_ci	unsigned int ysize;
8762306a36Sopenharmony_ci	unsigned int backcolor;
8862306a36Sopenharmony_ci	unsigned int brightness;
8962306a36Sopenharmony_ci	unsigned int colorkey;
9062306a36Sopenharmony_ci	unsigned int mask;
9162306a36Sopenharmony_ci	unsigned int panel_choice;
9262306a36Sopenharmony_ci	char panel_desc[80];
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define WIN_POSITION            (1<< 0)
9762306a36Sopenharmony_ci#define WIN_ALPHA_COLOR         (1<< 1)
9862306a36Sopenharmony_ci#define WIN_ALPHA_MODE          (1<< 2)
9962306a36Sopenharmony_ci#define WIN_PRIORITY            (1<< 3)
10062306a36Sopenharmony_ci#define WIN_CHANNEL             (1<< 4)
10162306a36Sopenharmony_ci#define WIN_BUFFER_FORMAT       (1<< 5)
10262306a36Sopenharmony_ci#define WIN_COLOR_ORDER         (1<< 6)
10362306a36Sopenharmony_ci#define WIN_PIXEL_ORDER         (1<< 7)
10462306a36Sopenharmony_ci#define WIN_SIZE                (1<< 8)
10562306a36Sopenharmony_ci#define WIN_COLORKEY_MODE       (1<< 9)
10662306a36Sopenharmony_ci#define WIN_DOUBLE_BUFFER_MODE  (1<< 10)
10762306a36Sopenharmony_ci#define WIN_RAM_ARRAY_MODE      (1<< 11)
10862306a36Sopenharmony_ci#define WIN_BUFFER_SCALE        (1<< 12)
10962306a36Sopenharmony_ci#define WIN_ENABLE	            (1<< 13)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct au1200_lcd_window_regs_t {
11262306a36Sopenharmony_ci	unsigned int flags;
11362306a36Sopenharmony_ci	unsigned int xpos;
11462306a36Sopenharmony_ci	unsigned int ypos;
11562306a36Sopenharmony_ci	unsigned int alpha_color;
11662306a36Sopenharmony_ci	unsigned int alpha_mode;
11762306a36Sopenharmony_ci	unsigned int priority;
11862306a36Sopenharmony_ci	unsigned int channel;
11962306a36Sopenharmony_ci	unsigned int buffer_format;
12062306a36Sopenharmony_ci	unsigned int color_order;
12162306a36Sopenharmony_ci	unsigned int pixel_order;
12262306a36Sopenharmony_ci	unsigned int xsize;
12362306a36Sopenharmony_ci	unsigned int ysize;
12462306a36Sopenharmony_ci	unsigned int colorkey_mode;
12562306a36Sopenharmony_ci	unsigned int double_buffer_mode;
12662306a36Sopenharmony_ci	unsigned int ram_array_mode;
12762306a36Sopenharmony_ci	unsigned int xscale;
12862306a36Sopenharmony_ci	unsigned int yscale;
12962306a36Sopenharmony_ci	unsigned int enable;
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistruct au1200_lcd_iodata_t {
13462306a36Sopenharmony_ci	unsigned int subcmd;
13562306a36Sopenharmony_ci	struct au1200_lcd_global_regs_t global;
13662306a36Sopenharmony_ci	struct au1200_lcd_window_regs_t window;
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#if defined(__BIG_ENDIAN)
14062306a36Sopenharmony_ci#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11
14162306a36Sopenharmony_ci#else
14262306a36Sopenharmony_ci#define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00
14362306a36Sopenharmony_ci#endif
14462306a36Sopenharmony_ci#define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* Private, per-framebuffer management information (independent of the panel itself) */
14762306a36Sopenharmony_cistruct au1200fb_device {
14862306a36Sopenharmony_ci	struct fb_info *fb_info;		/* FB driver info record */
14962306a36Sopenharmony_ci	struct au1200fb_platdata *pd;
15062306a36Sopenharmony_ci	struct device *dev;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	int					plane;
15362306a36Sopenharmony_ci	unsigned char* 		fb_mem;		/* FrameBuffer memory map */
15462306a36Sopenharmony_ci	unsigned int		fb_len;
15562306a36Sopenharmony_ci	dma_addr_t    		fb_phys;
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/********************************************************************/
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* LCD controller restrictions */
16162306a36Sopenharmony_ci#define AU1200_LCD_MAX_XRES	1280
16262306a36Sopenharmony_ci#define AU1200_LCD_MAX_YRES	1024
16362306a36Sopenharmony_ci#define AU1200_LCD_MAX_BPP	32
16462306a36Sopenharmony_ci#define AU1200_LCD_MAX_CLK	96000000 /* fixme: this needs to go away ? */
16562306a36Sopenharmony_ci#define AU1200_LCD_NBR_PALETTE_ENTRIES 256
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* Default number of visible screen buffer to allocate */
16862306a36Sopenharmony_ci#define AU1200FB_NBR_VIDEO_BUFFERS 1
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* Default maximum number of fb devices to create */
17162306a36Sopenharmony_ci#define MAX_DEVICE_COUNT	4
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Default window configuration entry to use (see windows[]) */
17462306a36Sopenharmony_ci#define DEFAULT_WINDOW_INDEX	2
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/********************************************************************/
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT];
17962306a36Sopenharmony_cistatic struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
18062306a36Sopenharmony_cistatic int device_count = MAX_DEVICE_COUNT;
18162306a36Sopenharmony_cistatic int window_index = DEFAULT_WINDOW_INDEX;	/* default is zero */
18262306a36Sopenharmony_cistatic int panel_index = 2; /* default is zero */
18362306a36Sopenharmony_cistatic struct window_settings *win;
18462306a36Sopenharmony_cistatic struct panel_settings *panel;
18562306a36Sopenharmony_cistatic int noblanking = 1;
18662306a36Sopenharmony_cistatic int nohwcursor = 0;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistruct window_settings {
18962306a36Sopenharmony_ci	unsigned char name[64];
19062306a36Sopenharmony_ci	uint32 mode_backcolor;
19162306a36Sopenharmony_ci	uint32 mode_colorkey;
19262306a36Sopenharmony_ci	uint32 mode_colorkeymsk;
19362306a36Sopenharmony_ci	struct {
19462306a36Sopenharmony_ci		int xres;
19562306a36Sopenharmony_ci		int yres;
19662306a36Sopenharmony_ci		int xpos;
19762306a36Sopenharmony_ci		int ypos;
19862306a36Sopenharmony_ci		uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
19962306a36Sopenharmony_ci		uint32 mode_winenable;
20062306a36Sopenharmony_ci	} w[4];
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#if defined(__BIG_ENDIAN)
20462306a36Sopenharmony_ci#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
20562306a36Sopenharmony_ci#else
20662306a36Sopenharmony_ci#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
20762306a36Sopenharmony_ci#endif
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/*
21062306a36Sopenharmony_ci * Default window configurations
21162306a36Sopenharmony_ci */
21262306a36Sopenharmony_cistatic struct window_settings windows[] = {
21362306a36Sopenharmony_ci	{ /* Index 0 */
21462306a36Sopenharmony_ci		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
21562306a36Sopenharmony_ci		/* mode_backcolor	*/ 0x006600ff,
21662306a36Sopenharmony_ci		/* mode_colorkey,msk*/ 0, 0,
21762306a36Sopenharmony_ci		{
21862306a36Sopenharmony_ci			{
21962306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
22062306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
22162306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP,
22262306a36Sopenharmony_ci			/* mode_winenable*/ LCD_WINENABLE_WEN0,
22362306a36Sopenharmony_ci			},
22462306a36Sopenharmony_ci			{
22562306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 100, 100, 100, 100,
22662306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
22762306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP |
22862306a36Sopenharmony_ci				LCD_WINCTRL1_PIPE,
22962306a36Sopenharmony_ci			/* mode_winenable*/ LCD_WINENABLE_WEN1,
23062306a36Sopenharmony_ci			},
23162306a36Sopenharmony_ci			{
23262306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
23362306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
23462306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP,
23562306a36Sopenharmony_ci			/* mode_winenable*/ 0,
23662306a36Sopenharmony_ci			},
23762306a36Sopenharmony_ci			{
23862306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
23962306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
24062306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP |
24162306a36Sopenharmony_ci				LCD_WINCTRL1_PIPE,
24262306a36Sopenharmony_ci			/* mode_winenable*/ 0,
24362306a36Sopenharmony_ci			},
24462306a36Sopenharmony_ci		},
24562306a36Sopenharmony_ci	},
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	{ /* Index 1 */
24862306a36Sopenharmony_ci		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
24962306a36Sopenharmony_ci		/* mode_backcolor	*/ 0x006600ff,
25062306a36Sopenharmony_ci		/* mode_colorkey,msk*/ 0, 0,
25162306a36Sopenharmony_ci		{
25262306a36Sopenharmony_ci			{
25362306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 320, 240, 5, 5,
25462306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP |
25562306a36Sopenharmony_ci				LCD_WINCTRL1_PO_00,
25662306a36Sopenharmony_ci			/* mode_winenable*/ LCD_WINENABLE_WEN0,
25762306a36Sopenharmony_ci			},
25862306a36Sopenharmony_ci			{
25962306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
26062306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565
26162306a36Sopenharmony_ci				| LCD_WINCTRL1_PO_16BPP,
26262306a36Sopenharmony_ci			/* mode_winenable*/ 0,
26362306a36Sopenharmony_ci			},
26462306a36Sopenharmony_ci			{
26562306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 100, 100, 0, 0,
26662306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
26762306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP |
26862306a36Sopenharmony_ci				LCD_WINCTRL1_PIPE,
26962306a36Sopenharmony_ci			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
27062306a36Sopenharmony_ci			},
27162306a36Sopenharmony_ci			{
27262306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 200, 25, 0, 0,
27362306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
27462306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP |
27562306a36Sopenharmony_ci				LCD_WINCTRL1_PIPE,
27662306a36Sopenharmony_ci			/* mode_winenable*/ 0,
27762306a36Sopenharmony_ci			},
27862306a36Sopenharmony_ci		},
27962306a36Sopenharmony_ci	},
28062306a36Sopenharmony_ci	{ /* Index 2 */
28162306a36Sopenharmony_ci		"0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
28262306a36Sopenharmony_ci		/* mode_backcolor	*/ 0x006600ff,
28362306a36Sopenharmony_ci		/* mode_colorkey,msk*/ 0, 0,
28462306a36Sopenharmony_ci		{
28562306a36Sopenharmony_ci			{
28662306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
28762306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
28862306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP,
28962306a36Sopenharmony_ci			/* mode_winenable*/ LCD_WINENABLE_WEN0,
29062306a36Sopenharmony_ci			},
29162306a36Sopenharmony_ci			{
29262306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
29362306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
29462306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP,
29562306a36Sopenharmony_ci			/* mode_winenable*/ 0,
29662306a36Sopenharmony_ci			},
29762306a36Sopenharmony_ci			{
29862306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
29962306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP |
30062306a36Sopenharmony_ci				LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE,
30162306a36Sopenharmony_ci			/* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
30262306a36Sopenharmony_ci			},
30362306a36Sopenharmony_ci			{
30462306a36Sopenharmony_ci			/* xres, yres, xpos, ypos */ 0, 0, 0, 0,
30562306a36Sopenharmony_ci			/* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 |
30662306a36Sopenharmony_ci				LCD_WINCTRL1_PO_16BPP |
30762306a36Sopenharmony_ci				LCD_WINCTRL1_PIPE,
30862306a36Sopenharmony_ci			/* mode_winenable*/ 0,
30962306a36Sopenharmony_ci			},
31062306a36Sopenharmony_ci		},
31162306a36Sopenharmony_ci	},
31262306a36Sopenharmony_ci	/* Need VGA 640 @ 24bpp, @ 32bpp */
31362306a36Sopenharmony_ci	/* Need VGA 800 @ 24bpp, @ 32bpp */
31462306a36Sopenharmony_ci	/* Need VGA 1024 @ 24bpp, @ 32bpp */
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/*
31862306a36Sopenharmony_ci * Controller configurations for various panels.
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistruct panel_settings
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	const char name[25];		/* Full name <vendor>_<model> */
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	struct 	fb_monspecs monspecs; 	/* FB monitor specs */
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* panel timings */
32862306a36Sopenharmony_ci	uint32 mode_screen;
32962306a36Sopenharmony_ci	uint32 mode_horztiming;
33062306a36Sopenharmony_ci	uint32 mode_verttiming;
33162306a36Sopenharmony_ci	uint32 mode_clkcontrol;
33262306a36Sopenharmony_ci	uint32 mode_pwmdiv;
33362306a36Sopenharmony_ci	uint32 mode_pwmhi;
33462306a36Sopenharmony_ci	uint32 mode_outmask;
33562306a36Sopenharmony_ci	uint32 mode_fifoctrl;
33662306a36Sopenharmony_ci	uint32 mode_backlight;
33762306a36Sopenharmony_ci	uint32 lcdclk;
33862306a36Sopenharmony_ci#define Xres min_xres
33962306a36Sopenharmony_ci#define Yres min_yres
34062306a36Sopenharmony_ci	u32	min_xres;		/* Minimum horizontal resolution */
34162306a36Sopenharmony_ci	u32	max_xres;		/* Maximum horizontal resolution */
34262306a36Sopenharmony_ci	u32 	min_yres;		/* Minimum vertical resolution */
34362306a36Sopenharmony_ci	u32 	max_yres;		/* Maximum vertical resolution */
34462306a36Sopenharmony_ci};
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/********************************************************************/
34762306a36Sopenharmony_ci/* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/* List of panels known to work with the AU1200 LCD controller.
35062306a36Sopenharmony_ci * To add a new panel, enter the same specifications as the
35162306a36Sopenharmony_ci * Generic_TFT one, and MAKE SURE that it doesn't conflicts
35262306a36Sopenharmony_ci * with the controller restrictions. Restrictions are:
35362306a36Sopenharmony_ci *
35462306a36Sopenharmony_ci * STN color panels: max_bpp <= 12
35562306a36Sopenharmony_ci * STN mono panels: max_bpp <= 4
35662306a36Sopenharmony_ci * TFT panels: max_bpp <= 16
35762306a36Sopenharmony_ci * max_xres <= 800
35862306a36Sopenharmony_ci * max_yres <= 600
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_cistatic struct panel_settings known_lcd_panels[] =
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	[0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */
36362306a36Sopenharmony_ci		.name = "QVGA_320x240",
36462306a36Sopenharmony_ci		.monspecs = {
36562306a36Sopenharmony_ci			.modedb = NULL,
36662306a36Sopenharmony_ci			.modedb_len = 0,
36762306a36Sopenharmony_ci			.hfmin = 30000,
36862306a36Sopenharmony_ci			.hfmax = 70000,
36962306a36Sopenharmony_ci			.vfmin = 60,
37062306a36Sopenharmony_ci			.vfmax = 60,
37162306a36Sopenharmony_ci			.dclkmin = 6000000,
37262306a36Sopenharmony_ci			.dclkmax = 28000000,
37362306a36Sopenharmony_ci			.input = FB_DISP_RGB,
37462306a36Sopenharmony_ci		},
37562306a36Sopenharmony_ci		.mode_screen		= LCD_SCREEN_SX_N(320) |
37662306a36Sopenharmony_ci			LCD_SCREEN_SY_N(240),
37762306a36Sopenharmony_ci		.mode_horztiming	= 0x00c4623b,
37862306a36Sopenharmony_ci		.mode_verttiming	= 0x00502814,
37962306a36Sopenharmony_ci		.mode_clkcontrol	= 0x00020002, /* /4=24Mhz */
38062306a36Sopenharmony_ci		.mode_pwmdiv		= 0x00000000,
38162306a36Sopenharmony_ci		.mode_pwmhi		= 0x00000000,
38262306a36Sopenharmony_ci		.mode_outmask	= 0x00FFFFFF,
38362306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
38462306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
38562306a36Sopenharmony_ci		.lcdclk		= 96,
38662306a36Sopenharmony_ci		320, 320,
38762306a36Sopenharmony_ci		240, 240,
38862306a36Sopenharmony_ci	},
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	[1] = { /* VGA 640x480 H:30.3kHz V:58Hz */
39162306a36Sopenharmony_ci		.name = "VGA_640x480",
39262306a36Sopenharmony_ci		.monspecs = {
39362306a36Sopenharmony_ci			.modedb = NULL,
39462306a36Sopenharmony_ci			.modedb_len = 0,
39562306a36Sopenharmony_ci			.hfmin = 30000,
39662306a36Sopenharmony_ci			.hfmax = 70000,
39762306a36Sopenharmony_ci			.vfmin = 60,
39862306a36Sopenharmony_ci			.vfmax = 60,
39962306a36Sopenharmony_ci			.dclkmin = 6000000,
40062306a36Sopenharmony_ci			.dclkmax = 28000000,
40162306a36Sopenharmony_ci			.input = FB_DISP_RGB,
40262306a36Sopenharmony_ci		},
40362306a36Sopenharmony_ci		.mode_screen		= 0x13f9df80,
40462306a36Sopenharmony_ci		.mode_horztiming	= 0x003c5859,
40562306a36Sopenharmony_ci		.mode_verttiming	= 0x00741201,
40662306a36Sopenharmony_ci		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
40762306a36Sopenharmony_ci		.mode_pwmdiv		= 0x00000000,
40862306a36Sopenharmony_ci		.mode_pwmhi		= 0x00000000,
40962306a36Sopenharmony_ci		.mode_outmask	= 0x00FFFFFF,
41062306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
41162306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
41262306a36Sopenharmony_ci		.lcdclk		= 96,
41362306a36Sopenharmony_ci		640, 480,
41462306a36Sopenharmony_ci		640, 480,
41562306a36Sopenharmony_ci	},
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	[2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */
41862306a36Sopenharmony_ci		.name = "SVGA_800x600",
41962306a36Sopenharmony_ci		.monspecs = {
42062306a36Sopenharmony_ci			.modedb = NULL,
42162306a36Sopenharmony_ci			.modedb_len = 0,
42262306a36Sopenharmony_ci			.hfmin = 30000,
42362306a36Sopenharmony_ci			.hfmax = 70000,
42462306a36Sopenharmony_ci			.vfmin = 60,
42562306a36Sopenharmony_ci			.vfmax = 60,
42662306a36Sopenharmony_ci			.dclkmin = 6000000,
42762306a36Sopenharmony_ci			.dclkmax = 28000000,
42862306a36Sopenharmony_ci			.input = FB_DISP_RGB,
42962306a36Sopenharmony_ci		},
43062306a36Sopenharmony_ci		.mode_screen		= 0x18fa5780,
43162306a36Sopenharmony_ci		.mode_horztiming	= 0x00dc7e77,
43262306a36Sopenharmony_ci		.mode_verttiming	= 0x00584805,
43362306a36Sopenharmony_ci		.mode_clkcontrol	= 0x00020000, /* /2=48Mhz */
43462306a36Sopenharmony_ci		.mode_pwmdiv		= 0x00000000,
43562306a36Sopenharmony_ci		.mode_pwmhi		= 0x00000000,
43662306a36Sopenharmony_ci		.mode_outmask	= 0x00FFFFFF,
43762306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
43862306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
43962306a36Sopenharmony_ci		.lcdclk		= 96,
44062306a36Sopenharmony_ci		800, 800,
44162306a36Sopenharmony_ci		600, 600,
44262306a36Sopenharmony_ci	},
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	[3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */
44562306a36Sopenharmony_ci		.name = "XVGA_1024x768",
44662306a36Sopenharmony_ci		.monspecs = {
44762306a36Sopenharmony_ci			.modedb = NULL,
44862306a36Sopenharmony_ci			.modedb_len = 0,
44962306a36Sopenharmony_ci			.hfmin = 30000,
45062306a36Sopenharmony_ci			.hfmax = 70000,
45162306a36Sopenharmony_ci			.vfmin = 60,
45262306a36Sopenharmony_ci			.vfmax = 60,
45362306a36Sopenharmony_ci			.dclkmin = 6000000,
45462306a36Sopenharmony_ci			.dclkmax = 28000000,
45562306a36Sopenharmony_ci			.input = FB_DISP_RGB,
45662306a36Sopenharmony_ci		},
45762306a36Sopenharmony_ci		.mode_screen		= 0x1ffaff80,
45862306a36Sopenharmony_ci		.mode_horztiming	= 0x007d0e57,
45962306a36Sopenharmony_ci		.mode_verttiming	= 0x00740a01,
46062306a36Sopenharmony_ci		.mode_clkcontrol	= 0x000A0000, /* /1 */
46162306a36Sopenharmony_ci		.mode_pwmdiv		= 0x00000000,
46262306a36Sopenharmony_ci		.mode_pwmhi		= 0x00000000,
46362306a36Sopenharmony_ci		.mode_outmask	= 0x00FFFFFF,
46462306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
46562306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
46662306a36Sopenharmony_ci		.lcdclk		= 72,
46762306a36Sopenharmony_ci		1024, 1024,
46862306a36Sopenharmony_ci		768, 768,
46962306a36Sopenharmony_ci	},
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	[4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */
47262306a36Sopenharmony_ci		.name = "XVGA_1280x1024",
47362306a36Sopenharmony_ci		.monspecs = {
47462306a36Sopenharmony_ci			.modedb = NULL,
47562306a36Sopenharmony_ci			.modedb_len = 0,
47662306a36Sopenharmony_ci			.hfmin = 30000,
47762306a36Sopenharmony_ci			.hfmax = 70000,
47862306a36Sopenharmony_ci			.vfmin = 60,
47962306a36Sopenharmony_ci			.vfmax = 60,
48062306a36Sopenharmony_ci			.dclkmin = 6000000,
48162306a36Sopenharmony_ci			.dclkmax = 28000000,
48262306a36Sopenharmony_ci			.input = FB_DISP_RGB,
48362306a36Sopenharmony_ci		},
48462306a36Sopenharmony_ci		.mode_screen		= 0x27fbff80,
48562306a36Sopenharmony_ci		.mode_horztiming	= 0x00cdb2c7,
48662306a36Sopenharmony_ci		.mode_verttiming	= 0x00600002,
48762306a36Sopenharmony_ci		.mode_clkcontrol	= 0x000A0000, /* /1 */
48862306a36Sopenharmony_ci		.mode_pwmdiv		= 0x00000000,
48962306a36Sopenharmony_ci		.mode_pwmhi		= 0x00000000,
49062306a36Sopenharmony_ci		.mode_outmask	= 0x00FFFFFF,
49162306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
49262306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
49362306a36Sopenharmony_ci		.lcdclk		= 120,
49462306a36Sopenharmony_ci		1280, 1280,
49562306a36Sopenharmony_ci		1024, 1024,
49662306a36Sopenharmony_ci	},
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	[5] = { /* Samsung 1024x768 TFT */
49962306a36Sopenharmony_ci		.name = "Samsung_1024x768_TFT",
50062306a36Sopenharmony_ci		.monspecs = {
50162306a36Sopenharmony_ci			.modedb = NULL,
50262306a36Sopenharmony_ci			.modedb_len = 0,
50362306a36Sopenharmony_ci			.hfmin = 30000,
50462306a36Sopenharmony_ci			.hfmax = 70000,
50562306a36Sopenharmony_ci			.vfmin = 60,
50662306a36Sopenharmony_ci			.vfmax = 60,
50762306a36Sopenharmony_ci			.dclkmin = 6000000,
50862306a36Sopenharmony_ci			.dclkmax = 28000000,
50962306a36Sopenharmony_ci			.input = FB_DISP_RGB,
51062306a36Sopenharmony_ci		},
51162306a36Sopenharmony_ci		.mode_screen		= 0x1ffaff80,
51262306a36Sopenharmony_ci		.mode_horztiming	= 0x018cc677,
51362306a36Sopenharmony_ci		.mode_verttiming	= 0x00241217,
51462306a36Sopenharmony_ci		.mode_clkcontrol	= 0x00000000, /* SCB 0x1 /4=24Mhz */
51562306a36Sopenharmony_ci		.mode_pwmdiv		= 0x8000063f, /* SCB 0x0 */
51662306a36Sopenharmony_ci		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
51762306a36Sopenharmony_ci		.mode_outmask	= 0x00FFFFFF,
51862306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
51962306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
52062306a36Sopenharmony_ci		.lcdclk		= 96,
52162306a36Sopenharmony_ci		1024, 1024,
52262306a36Sopenharmony_ci		768, 768,
52362306a36Sopenharmony_ci	},
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	[6] = { /* Toshiba 640x480 TFT */
52662306a36Sopenharmony_ci		.name = "Toshiba_640x480_TFT",
52762306a36Sopenharmony_ci		.monspecs = {
52862306a36Sopenharmony_ci			.modedb = NULL,
52962306a36Sopenharmony_ci			.modedb_len = 0,
53062306a36Sopenharmony_ci			.hfmin = 30000,
53162306a36Sopenharmony_ci			.hfmax = 70000,
53262306a36Sopenharmony_ci			.vfmin = 60,
53362306a36Sopenharmony_ci			.vfmax = 60,
53462306a36Sopenharmony_ci			.dclkmin = 6000000,
53562306a36Sopenharmony_ci			.dclkmax = 28000000,
53662306a36Sopenharmony_ci			.input = FB_DISP_RGB,
53762306a36Sopenharmony_ci		},
53862306a36Sopenharmony_ci		.mode_screen		= LCD_SCREEN_SX_N(640) |
53962306a36Sopenharmony_ci			LCD_SCREEN_SY_N(480),
54062306a36Sopenharmony_ci		.mode_horztiming	= LCD_HORZTIMING_HPW_N(96) |
54162306a36Sopenharmony_ci			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
54262306a36Sopenharmony_ci		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
54362306a36Sopenharmony_ci			LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32),
54462306a36Sopenharmony_ci		.mode_clkcontrol	= 0x00000000, /* /4=24Mhz */
54562306a36Sopenharmony_ci		.mode_pwmdiv		= 0x8000063f,
54662306a36Sopenharmony_ci		.mode_pwmhi		= 0x03400000,
54762306a36Sopenharmony_ci		.mode_outmask	= 0x00fcfcfc,
54862306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
54962306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
55062306a36Sopenharmony_ci		.lcdclk		= 96,
55162306a36Sopenharmony_ci		640, 480,
55262306a36Sopenharmony_ci		640, 480,
55362306a36Sopenharmony_ci	},
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	[7] = { /* Sharp 320x240 TFT */
55662306a36Sopenharmony_ci		.name = "Sharp_320x240_TFT",
55762306a36Sopenharmony_ci		.monspecs = {
55862306a36Sopenharmony_ci			.modedb = NULL,
55962306a36Sopenharmony_ci			.modedb_len = 0,
56062306a36Sopenharmony_ci			.hfmin = 12500,
56162306a36Sopenharmony_ci			.hfmax = 20000,
56262306a36Sopenharmony_ci			.vfmin = 38,
56362306a36Sopenharmony_ci			.vfmax = 81,
56462306a36Sopenharmony_ci			.dclkmin = 4500000,
56562306a36Sopenharmony_ci			.dclkmax = 6800000,
56662306a36Sopenharmony_ci			.input = FB_DISP_RGB,
56762306a36Sopenharmony_ci		},
56862306a36Sopenharmony_ci		.mode_screen		= LCD_SCREEN_SX_N(320) |
56962306a36Sopenharmony_ci			LCD_SCREEN_SY_N(240),
57062306a36Sopenharmony_ci		.mode_horztiming	= LCD_HORZTIMING_HPW_N(60) |
57162306a36Sopenharmony_ci			LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
57262306a36Sopenharmony_ci		.mode_verttiming	= LCD_VERTTIMING_VPW_N(2) |
57362306a36Sopenharmony_ci			LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5),
57462306a36Sopenharmony_ci		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/
57562306a36Sopenharmony_ci		.mode_pwmdiv		= 0x8000063f,
57662306a36Sopenharmony_ci		.mode_pwmhi		= 0x03400000,
57762306a36Sopenharmony_ci		.mode_outmask	= 0x00fcfcfc,
57862306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
57962306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
58062306a36Sopenharmony_ci		.lcdclk		= 96, /* 96MHz AUXPLL */
58162306a36Sopenharmony_ci		320, 320,
58262306a36Sopenharmony_ci		240, 240,
58362306a36Sopenharmony_ci	},
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	[8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */
58662306a36Sopenharmony_ci		.name = "Toppoly_TD070WGCB2",
58762306a36Sopenharmony_ci		.monspecs = {
58862306a36Sopenharmony_ci			.modedb = NULL,
58962306a36Sopenharmony_ci			.modedb_len = 0,
59062306a36Sopenharmony_ci			.hfmin = 30000,
59162306a36Sopenharmony_ci			.hfmax = 70000,
59262306a36Sopenharmony_ci			.vfmin = 60,
59362306a36Sopenharmony_ci			.vfmax = 60,
59462306a36Sopenharmony_ci			.dclkmin = 6000000,
59562306a36Sopenharmony_ci			.dclkmax = 28000000,
59662306a36Sopenharmony_ci			.input = FB_DISP_RGB,
59762306a36Sopenharmony_ci		},
59862306a36Sopenharmony_ci		.mode_screen		= LCD_SCREEN_SX_N(856) |
59962306a36Sopenharmony_ci			LCD_SCREEN_SY_N(480),
60062306a36Sopenharmony_ci		.mode_horztiming	= LCD_HORZTIMING_HND2_N(43) |
60162306a36Sopenharmony_ci			LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114),
60262306a36Sopenharmony_ci		.mode_verttiming	= LCD_VERTTIMING_VND2_N(20) |
60362306a36Sopenharmony_ci			LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
60462306a36Sopenharmony_ci		.mode_clkcontrol	= 0x00020001, /* /4=24Mhz */
60562306a36Sopenharmony_ci		.mode_pwmdiv		= 0x8000063f,
60662306a36Sopenharmony_ci		.mode_pwmhi		= 0x03400000,
60762306a36Sopenharmony_ci		.mode_outmask	= 0x00fcfcfc,
60862306a36Sopenharmony_ci		.mode_fifoctrl	= 0x2f2f2f2f,
60962306a36Sopenharmony_ci		.mode_backlight	= 0x00000000,
61062306a36Sopenharmony_ci		.lcdclk		= 96,
61162306a36Sopenharmony_ci		856, 856,
61262306a36Sopenharmony_ci		480, 480,
61362306a36Sopenharmony_ci	},
61462306a36Sopenharmony_ci	[9] = {
61562306a36Sopenharmony_ci		.name = "DB1300_800x480",
61662306a36Sopenharmony_ci		.monspecs = {
61762306a36Sopenharmony_ci			.modedb = NULL,
61862306a36Sopenharmony_ci			.modedb_len = 0,
61962306a36Sopenharmony_ci			.hfmin = 30000,
62062306a36Sopenharmony_ci			.hfmax = 70000,
62162306a36Sopenharmony_ci			.vfmin = 60,
62262306a36Sopenharmony_ci			.vfmax = 60,
62362306a36Sopenharmony_ci			.dclkmin = 6000000,
62462306a36Sopenharmony_ci			.dclkmax = 28000000,
62562306a36Sopenharmony_ci			.input = FB_DISP_RGB,
62662306a36Sopenharmony_ci		},
62762306a36Sopenharmony_ci		.mode_screen		= LCD_SCREEN_SX_N(800) |
62862306a36Sopenharmony_ci					  LCD_SCREEN_SY_N(480),
62962306a36Sopenharmony_ci		.mode_horztiming	= LCD_HORZTIMING_HPW_N(5) |
63062306a36Sopenharmony_ci					  LCD_HORZTIMING_HND1_N(16) |
63162306a36Sopenharmony_ci					  LCD_HORZTIMING_HND2_N(8),
63262306a36Sopenharmony_ci		.mode_verttiming	= LCD_VERTTIMING_VPW_N(4) |
63362306a36Sopenharmony_ci					  LCD_VERTTIMING_VND1_N(8) |
63462306a36Sopenharmony_ci					  LCD_VERTTIMING_VND2_N(5),
63562306a36Sopenharmony_ci		.mode_clkcontrol	= LCD_CLKCONTROL_PCD_N(1) |
63662306a36Sopenharmony_ci					  LCD_CLKCONTROL_IV |
63762306a36Sopenharmony_ci					  LCD_CLKCONTROL_IH,
63862306a36Sopenharmony_ci		.mode_pwmdiv		= 0x00000000,
63962306a36Sopenharmony_ci		.mode_pwmhi		= 0x00000000,
64062306a36Sopenharmony_ci		.mode_outmask		= 0x00FFFFFF,
64162306a36Sopenharmony_ci		.mode_fifoctrl		= 0x2f2f2f2f,
64262306a36Sopenharmony_ci		.mode_backlight		= 0x00000000,
64362306a36Sopenharmony_ci		.lcdclk			= 96,
64462306a36Sopenharmony_ci		800, 800,
64562306a36Sopenharmony_ci		480, 480,
64662306a36Sopenharmony_ci	},
64762306a36Sopenharmony_ci};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci#define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci/********************************************************************/
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic int winbpp (unsigned int winctrl1)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	int bits = 0;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* how many bits are needed for each pixel format */
65862306a36Sopenharmony_ci	switch (winctrl1 & LCD_WINCTRL1_FRM) {
65962306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_1BPP:
66062306a36Sopenharmony_ci		bits = 1;
66162306a36Sopenharmony_ci		break;
66262306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_2BPP:
66362306a36Sopenharmony_ci		bits = 2;
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_4BPP:
66662306a36Sopenharmony_ci		bits = 4;
66762306a36Sopenharmony_ci		break;
66862306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_8BPP:
66962306a36Sopenharmony_ci		bits = 8;
67062306a36Sopenharmony_ci		break;
67162306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_12BPP:
67262306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPP655:
67362306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPP565:
67462306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPP556:
67562306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPPI1555:
67662306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPPI5551:
67762306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPPA1555:
67862306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_16BPPA5551:
67962306a36Sopenharmony_ci		bits = 16;
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_24BPP:
68262306a36Sopenharmony_ci	case LCD_WINCTRL1_FRM_32BPP:
68362306a36Sopenharmony_ci		bits = 32;
68462306a36Sopenharmony_ci		break;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	return bits;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic int fbinfo2index (struct fb_info *fb_info)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	int i;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	for (i = 0; i < device_count; ++i) {
69562306a36Sopenharmony_ci		if (fb_info == _au1200fb_infos[i])
69662306a36Sopenharmony_ci			return i;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci	printk("au1200fb: ERROR: fbinfo2index failed!\n");
69962306a36Sopenharmony_ci	return -1;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
70362306a36Sopenharmony_ci	int xpos, int ypos)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
70662306a36Sopenharmony_ci	int xsz, ysz;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	winctrl0 = lcd->window[plane].winctrl0;
71162306a36Sopenharmony_ci	winctrl1 = lcd->window[plane].winctrl1;
71262306a36Sopenharmony_ci	winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
71362306a36Sopenharmony_ci	winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* Check for off-screen adjustments */
71662306a36Sopenharmony_ci	xsz = win->w[plane].xres;
71762306a36Sopenharmony_ci	ysz = win->w[plane].yres;
71862306a36Sopenharmony_ci	if ((xpos + win->w[plane].xres) > panel->Xres) {
71962306a36Sopenharmony_ci		/* Off-screen to the right */
72062306a36Sopenharmony_ci		xsz = panel->Xres - xpos; /* off by 1 ??? */
72162306a36Sopenharmony_ci		/*printk("off screen right\n");*/
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if ((ypos + win->w[plane].yres) > panel->Yres) {
72562306a36Sopenharmony_ci		/* Off-screen to the bottom */
72662306a36Sopenharmony_ci		ysz = panel->Yres - ypos; /* off by 1 ??? */
72762306a36Sopenharmony_ci		/*printk("off screen bottom\n");*/
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (xpos < 0) {
73162306a36Sopenharmony_ci		/* Off-screen to the left */
73262306a36Sopenharmony_ci		xsz = win->w[plane].xres + xpos;
73362306a36Sopenharmony_ci		fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
73462306a36Sopenharmony_ci		xpos = 0;
73562306a36Sopenharmony_ci		/*printk("off screen left\n");*/
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (ypos < 0) {
73962306a36Sopenharmony_ci		/* Off-screen to the top */
74062306a36Sopenharmony_ci		ysz = win->w[plane].yres + ypos;
74162306a36Sopenharmony_ci		/* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */
74262306a36Sopenharmony_ci		ypos = 0;
74362306a36Sopenharmony_ci		/*printk("off screen top\n");*/
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* record settings */
74762306a36Sopenharmony_ci	win->w[plane].xpos = xpos;
74862306a36Sopenharmony_ci	win->w[plane].ypos = ypos;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	xsz -= 1;
75162306a36Sopenharmony_ci	ysz -= 1;
75262306a36Sopenharmony_ci	winctrl0 |= (xpos << 21);
75362306a36Sopenharmony_ci	winctrl0 |= (ypos << 10);
75462306a36Sopenharmony_ci	winctrl1 |= (xsz << 11);
75562306a36Sopenharmony_ci	winctrl1 |= (ysz << 0);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* Disable the window while making changes, then restore WINEN */
75862306a36Sopenharmony_ci	winenable = lcd->winenable & (1 << plane);
75962306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
76062306a36Sopenharmony_ci	lcd->winenable &= ~(1 << plane);
76162306a36Sopenharmony_ci	lcd->window[plane].winctrl0 = winctrl0;
76262306a36Sopenharmony_ci	lcd->window[plane].winctrl1 = winctrl1;
76362306a36Sopenharmony_ci	lcd->window[plane].winbuf0 =
76462306a36Sopenharmony_ci	lcd->window[plane].winbuf1 = fbdev->fb_phys;
76562306a36Sopenharmony_ci	lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
76662306a36Sopenharmony_ci	lcd->winenable |= winenable;
76762306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	return 0;
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic void au1200_setpanel(struct panel_settings *newpanel,
77362306a36Sopenharmony_ci			    struct au1200fb_platdata *pd)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	/*
77662306a36Sopenharmony_ci	 * Perform global setup/init of LCD controller
77762306a36Sopenharmony_ci	 */
77862306a36Sopenharmony_ci	uint32 winenable;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* Make sure all windows disabled */
78162306a36Sopenharmony_ci	winenable = lcd->winenable;
78262306a36Sopenharmony_ci	lcd->winenable = 0;
78362306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
78462306a36Sopenharmony_ci	/*
78562306a36Sopenharmony_ci	 * Ensure everything is disabled before reconfiguring
78662306a36Sopenharmony_ci	 */
78762306a36Sopenharmony_ci	if (lcd->screen & LCD_SCREEN_SEN) {
78862306a36Sopenharmony_ci		/* Wait for vertical sync period */
78962306a36Sopenharmony_ci		lcd->intstatus = LCD_INT_SS;
79062306a36Sopenharmony_ci		while ((lcd->intstatus & LCD_INT_SS) == 0)
79162306a36Sopenharmony_ci			;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		lcd->screen &= ~LCD_SCREEN_SEN;	/*disable the controller*/
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		do {
79662306a36Sopenharmony_ci			lcd->intstatus = lcd->intstatus; /*clear interrupts*/
79762306a36Sopenharmony_ci			wmb(); /* drain writebuffer */
79862306a36Sopenharmony_ci		/*wait for controller to shut down*/
79962306a36Sopenharmony_ci		} while ((lcd->intstatus & LCD_INT_SD) == 0);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		/* Call shutdown of current panel (if up) */
80262306a36Sopenharmony_ci		/* this must occur last, because if an external clock is driving
80362306a36Sopenharmony_ci		    the controller, the clock cannot be turned off before first
80462306a36Sopenharmony_ci			shutting down the controller.
80562306a36Sopenharmony_ci		 */
80662306a36Sopenharmony_ci		if (pd->panel_shutdown)
80762306a36Sopenharmony_ci			pd->panel_shutdown();
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* Newpanel == NULL indicates a shutdown operation only */
81162306a36Sopenharmony_ci	if (newpanel == NULL)
81262306a36Sopenharmony_ci		return;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	panel = newpanel;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	/*
81962306a36Sopenharmony_ci	 * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
82262306a36Sopenharmony_ci	{
82362306a36Sopenharmony_ci		struct clk *c = clk_get(NULL, "lcd_intclk");
82462306a36Sopenharmony_ci		long r, pc = panel->lcdclk * 1000000;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		if (!IS_ERR(c)) {
82762306a36Sopenharmony_ci			r = clk_round_rate(c, pc);
82862306a36Sopenharmony_ci			if ((pc - r) < (pc / 10)) {	/* 10% slack */
82962306a36Sopenharmony_ci				clk_set_rate(c, r);
83062306a36Sopenharmony_ci				clk_prepare_enable(c);
83162306a36Sopenharmony_ci			}
83262306a36Sopenharmony_ci			clk_put(c);
83362306a36Sopenharmony_ci		}
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/*
83762306a36Sopenharmony_ci	 * Configure panel timings
83862306a36Sopenharmony_ci	 */
83962306a36Sopenharmony_ci	lcd->screen = panel->mode_screen;
84062306a36Sopenharmony_ci	lcd->horztiming = panel->mode_horztiming;
84162306a36Sopenharmony_ci	lcd->verttiming = panel->mode_verttiming;
84262306a36Sopenharmony_ci	lcd->clkcontrol = panel->mode_clkcontrol;
84362306a36Sopenharmony_ci	lcd->pwmdiv = panel->mode_pwmdiv;
84462306a36Sopenharmony_ci	lcd->pwmhi = panel->mode_pwmhi;
84562306a36Sopenharmony_ci	lcd->outmask = panel->mode_outmask;
84662306a36Sopenharmony_ci	lcd->fifoctrl = panel->mode_fifoctrl;
84762306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* fixme: Check window settings to make sure still valid
85062306a36Sopenharmony_ci	 * for new geometry */
85162306a36Sopenharmony_ci#if 0
85262306a36Sopenharmony_ci	au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos);
85362306a36Sopenharmony_ci	au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos);
85462306a36Sopenharmony_ci	au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos);
85562306a36Sopenharmony_ci	au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos);
85662306a36Sopenharmony_ci#endif
85762306a36Sopenharmony_ci	lcd->winenable = winenable;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/*
86062306a36Sopenharmony_ci	 * Re-enable screen now that it is configured
86162306a36Sopenharmony_ci	 */
86262306a36Sopenharmony_ci	lcd->screen |= LCD_SCREEN_SEN;
86362306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* Call init of panel */
86662306a36Sopenharmony_ci	if (pd->panel_init)
86762306a36Sopenharmony_ci		pd->panel_init();
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	/* FIX!!!! not appropriate on panel change!!! Global setup/init */
87062306a36Sopenharmony_ci	lcd->intenable = 0;
87162306a36Sopenharmony_ci	lcd->intstatus = ~0;
87262306a36Sopenharmony_ci	lcd->backcolor = win->mode_backcolor;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* Setup Color Key - FIX!!! */
87562306a36Sopenharmony_ci	lcd->colorkey = win->mode_colorkey;
87662306a36Sopenharmony_ci	lcd->colorkeymsk = win->mode_colorkeymsk;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* Setup HWCursor - FIX!!! Need to support this eventually */
87962306a36Sopenharmony_ci	lcd->hwc.cursorctrl = 0;
88062306a36Sopenharmony_ci	lcd->hwc.cursorpos = 0;
88162306a36Sopenharmony_ci	lcd->hwc.cursorcolor0 = 0;
88262306a36Sopenharmony_ci	lcd->hwc.cursorcolor1 = 0;
88362306a36Sopenharmony_ci	lcd->hwc.cursorcolor2 = 0;
88462306a36Sopenharmony_ci	lcd->hwc.cursorcolor3 = 0;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci#if 0
88862306a36Sopenharmony_ci#define D(X) printk("%25s: %08X\n", #X, X)
88962306a36Sopenharmony_ci	D(lcd->screen);
89062306a36Sopenharmony_ci	D(lcd->horztiming);
89162306a36Sopenharmony_ci	D(lcd->verttiming);
89262306a36Sopenharmony_ci	D(lcd->clkcontrol);
89362306a36Sopenharmony_ci	D(lcd->pwmdiv);
89462306a36Sopenharmony_ci	D(lcd->pwmhi);
89562306a36Sopenharmony_ci	D(lcd->outmask);
89662306a36Sopenharmony_ci	D(lcd->fifoctrl);
89762306a36Sopenharmony_ci	D(lcd->window[0].winctrl0);
89862306a36Sopenharmony_ci	D(lcd->window[0].winctrl1);
89962306a36Sopenharmony_ci	D(lcd->window[0].winctrl2);
90062306a36Sopenharmony_ci	D(lcd->window[0].winbuf0);
90162306a36Sopenharmony_ci	D(lcd->window[0].winbuf1);
90262306a36Sopenharmony_ci	D(lcd->window[0].winbufctrl);
90362306a36Sopenharmony_ci	D(lcd->window[1].winctrl0);
90462306a36Sopenharmony_ci	D(lcd->window[1].winctrl1);
90562306a36Sopenharmony_ci	D(lcd->window[1].winctrl2);
90662306a36Sopenharmony_ci	D(lcd->window[1].winbuf0);
90762306a36Sopenharmony_ci	D(lcd->window[1].winbuf1);
90862306a36Sopenharmony_ci	D(lcd->window[1].winbufctrl);
90962306a36Sopenharmony_ci	D(lcd->window[2].winctrl0);
91062306a36Sopenharmony_ci	D(lcd->window[2].winctrl1);
91162306a36Sopenharmony_ci	D(lcd->window[2].winctrl2);
91262306a36Sopenharmony_ci	D(lcd->window[2].winbuf0);
91362306a36Sopenharmony_ci	D(lcd->window[2].winbuf1);
91462306a36Sopenharmony_ci	D(lcd->window[2].winbufctrl);
91562306a36Sopenharmony_ci	D(lcd->window[3].winctrl0);
91662306a36Sopenharmony_ci	D(lcd->window[3].winctrl1);
91762306a36Sopenharmony_ci	D(lcd->window[3].winctrl2);
91862306a36Sopenharmony_ci	D(lcd->window[3].winbuf0);
91962306a36Sopenharmony_ci	D(lcd->window[3].winbuf1);
92062306a36Sopenharmony_ci	D(lcd->window[3].winbufctrl);
92162306a36Sopenharmony_ci	D(lcd->winenable);
92262306a36Sopenharmony_ci	D(lcd->intenable);
92362306a36Sopenharmony_ci	D(lcd->intstatus);
92462306a36Sopenharmony_ci	D(lcd->backcolor);
92562306a36Sopenharmony_ci	D(lcd->winenable);
92662306a36Sopenharmony_ci	D(lcd->colorkey);
92762306a36Sopenharmony_ci    D(lcd->colorkeymsk);
92862306a36Sopenharmony_ci	D(lcd->hwc.cursorctrl);
92962306a36Sopenharmony_ci	D(lcd->hwc.cursorpos);
93062306a36Sopenharmony_ci	D(lcd->hwc.cursorcolor0);
93162306a36Sopenharmony_ci	D(lcd->hwc.cursorcolor1);
93262306a36Sopenharmony_ci	D(lcd->hwc.cursorcolor2);
93362306a36Sopenharmony_ci	D(lcd->hwc.cursorcolor3);
93462306a36Sopenharmony_ci#endif
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_cistatic void au1200_setmode(struct au1200fb_device *fbdev)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	int plane = fbdev->plane;
94062306a36Sopenharmony_ci	/* Window/plane setup */
94162306a36Sopenharmony_ci	lcd->window[plane].winctrl1 = ( 0
94262306a36Sopenharmony_ci		| LCD_WINCTRL1_PRI_N(plane)
94362306a36Sopenharmony_ci		| win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
94462306a36Sopenharmony_ci		) ;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	lcd->window[plane].winctrl2 = ( 0
94962306a36Sopenharmony_ci		| LCD_WINCTRL2_CKMODE_00
95062306a36Sopenharmony_ci		| LCD_WINCTRL2_DBM
95162306a36Sopenharmony_ci		| LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length)
95262306a36Sopenharmony_ci		| LCD_WINCTRL2_SCX_1
95362306a36Sopenharmony_ci		| LCD_WINCTRL2_SCY_1
95462306a36Sopenharmony_ci		) ;
95562306a36Sopenharmony_ci	lcd->winenable |= win->w[plane].mode_winenable;
95662306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci/* Inline helpers */
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci/*#define panel_is_dual(panel)  ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
96362306a36Sopenharmony_ci/*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci#define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN)
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci/* Bitfields format supported by the controller. */
96862306a36Sopenharmony_cistatic struct fb_bitfield rgb_bitfields[][4] = {
96962306a36Sopenharmony_ci  	/*     Red, 	   Green, 	 Blue, 	     Transp   */
97062306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPP655 >> 25] =
97162306a36Sopenharmony_ci		{ { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPP565 >> 25] =
97462306a36Sopenharmony_ci		{ { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPP556 >> 25] =
97762306a36Sopenharmony_ci		{ { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPPI1555 >> 25] =
98062306a36Sopenharmony_ci		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPPI5551 >> 25] =
98362306a36Sopenharmony_ci		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } },
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPPA1555 >> 25] =
98662306a36Sopenharmony_ci		{ { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_16BPPA5551 >> 25] =
98962306a36Sopenharmony_ci		{ { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_24BPP >> 25] =
99262306a36Sopenharmony_ci		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } },
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	[LCD_WINCTRL1_FRM_32BPP >> 25] =
99562306a36Sopenharmony_ci		{ { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } },
99662306a36Sopenharmony_ci};
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci/* Helpers */
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic void au1200fb_update_fbinfo(struct fb_info *fbi)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	/* FIX!!!! This also needs to take the window pixel format into account!!! */
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	/* Update var-dependent FB info */
100762306a36Sopenharmony_ci	if (panel_is_color(panel)) {
100862306a36Sopenharmony_ci		if (fbi->var.bits_per_pixel <= 8) {
100962306a36Sopenharmony_ci			/* palettized */
101062306a36Sopenharmony_ci			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
101162306a36Sopenharmony_ci			fbi->fix.line_length = fbi->var.xres_virtual /
101262306a36Sopenharmony_ci				(8/fbi->var.bits_per_pixel);
101362306a36Sopenharmony_ci		} else {
101462306a36Sopenharmony_ci			/* non-palettized */
101562306a36Sopenharmony_ci			fbi->fix.visual = FB_VISUAL_TRUECOLOR;
101662306a36Sopenharmony_ci			fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8);
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci	} else {
101962306a36Sopenharmony_ci		/* mono FIX!!! mono 8 and 4 bits */
102062306a36Sopenharmony_ci		fbi->fix.visual = FB_VISUAL_MONO10;
102162306a36Sopenharmony_ci		fbi->fix.line_length = fbi->var.xres_virtual / 8;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual;
102562306a36Sopenharmony_ci	print_dbg("line length: %d\n", fbi->fix.line_length);
102662306a36Sopenharmony_ci	print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel);
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/* AU1200 framebuffer driver */
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci/* fb_check_var
103462306a36Sopenharmony_ci * Validate var settings with hardware restrictions and modify it if necessary
103562306a36Sopenharmony_ci */
103662306a36Sopenharmony_cistatic int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
103762306a36Sopenharmony_ci	struct fb_info *fbi)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	struct au1200fb_device *fbdev = fbi->par;
104062306a36Sopenharmony_ci	u32 pixclock;
104162306a36Sopenharmony_ci	int screen_size, plane;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (!var->pixclock)
104462306a36Sopenharmony_ci		return -EINVAL;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	plane = fbdev->plane;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* Make sure that the mode respect all LCD controller and
104962306a36Sopenharmony_ci	 * panel restrictions. */
105062306a36Sopenharmony_ci	var->xres = win->w[plane].xres;
105162306a36Sopenharmony_ci	var->yres = win->w[plane].yres;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* No need for virtual resolution support */
105462306a36Sopenharmony_ci	var->xres_virtual = var->xres;
105562306a36Sopenharmony_ci	var->yres_virtual = var->yres;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	screen_size = var->xres_virtual * var->yres_virtual;
106062306a36Sopenharmony_ci	if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8);
106162306a36Sopenharmony_ci	else screen_size /= (8/var->bits_per_pixel);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (fbdev->fb_len < screen_size)
106462306a36Sopenharmony_ci		return -EINVAL; /* Virtual screen is to big, abort */
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/* FIX!!!! what are the implicaitons of ignoring this for windows ??? */
106762306a36Sopenharmony_ci	/* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel
106862306a36Sopenharmony_ci	 * clock can only be obtain by dividing this value by an even integer.
106962306a36Sopenharmony_ci	 * Fallback to a slower pixel clock if necessary. */
107062306a36Sopenharmony_ci	pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin);
107162306a36Sopenharmony_ci	pixclock = min3(pixclock, fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (AU1200_LCD_MAX_CLK % pixclock) {
107462306a36Sopenharmony_ci		int diff = AU1200_LCD_MAX_CLK % pixclock;
107562306a36Sopenharmony_ci		pixclock -= diff;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	var->pixclock = KHZ2PICOS(pixclock/1000);
107962306a36Sopenharmony_ci#if 0
108062306a36Sopenharmony_ci	if (!panel_is_active(panel)) {
108162306a36Sopenharmony_ci		int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci		if (!panel_is_color(panel)
108462306a36Sopenharmony_ci			&& (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) {
108562306a36Sopenharmony_ci			/* STN 8bit mono panel support is up to 6MHz pixclock */
108662306a36Sopenharmony_ci			var->pixclock = KHZ2PICOS(6000);
108762306a36Sopenharmony_ci		} else if (!pcd) {
108862306a36Sopenharmony_ci			/* Other STN panel support is up to 12MHz  */
108962306a36Sopenharmony_ci			var->pixclock = KHZ2PICOS(12000);
109062306a36Sopenharmony_ci		}
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci#endif
109362306a36Sopenharmony_ci	/* Set bitfield accordingly */
109462306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
109562306a36Sopenharmony_ci		case 16:
109662306a36Sopenharmony_ci		{
109762306a36Sopenharmony_ci			/* 16bpp True color.
109862306a36Sopenharmony_ci			 * These must be set to MATCH WINCTRL[FORM] */
109962306a36Sopenharmony_ci			int idx;
110062306a36Sopenharmony_ci			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
110162306a36Sopenharmony_ci			var->red    = rgb_bitfields[idx][0];
110262306a36Sopenharmony_ci			var->green  = rgb_bitfields[idx][1];
110362306a36Sopenharmony_ci			var->blue   = rgb_bitfields[idx][2];
110462306a36Sopenharmony_ci			var->transp = rgb_bitfields[idx][3];
110562306a36Sopenharmony_ci			break;
110662306a36Sopenharmony_ci		}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci		case 32:
110962306a36Sopenharmony_ci		{
111062306a36Sopenharmony_ci			/* 32bpp True color.
111162306a36Sopenharmony_ci			 * These must be set to MATCH WINCTRL[FORM] */
111262306a36Sopenharmony_ci			int idx;
111362306a36Sopenharmony_ci			idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25;
111462306a36Sopenharmony_ci			var->red    = rgb_bitfields[idx][0];
111562306a36Sopenharmony_ci			var->green  = rgb_bitfields[idx][1];
111662306a36Sopenharmony_ci			var->blue   = rgb_bitfields[idx][2];
111762306a36Sopenharmony_ci			var->transp = rgb_bitfields[idx][3];
111862306a36Sopenharmony_ci			break;
111962306a36Sopenharmony_ci		}
112062306a36Sopenharmony_ci		default:
112162306a36Sopenharmony_ci			print_dbg("Unsupported depth %dbpp", var->bits_per_pixel);
112262306a36Sopenharmony_ci			return -EINVAL;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	return 0;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci/* fb_set_par
112962306a36Sopenharmony_ci * Set hardware with var settings. This will enable the controller with a
113062306a36Sopenharmony_ci * specific mode, normally validated with the fb_check_var method
113162306a36Sopenharmony_ci */
113262306a36Sopenharmony_cistatic int au1200fb_fb_set_par(struct fb_info *fbi)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	struct au1200fb_device *fbdev = fbi->par;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	au1200fb_update_fbinfo(fbi);
113762306a36Sopenharmony_ci	au1200_setmode(fbdev);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	return 0;
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci/* fb_setcolreg
114362306a36Sopenharmony_ci * Set color in LCD palette.
114462306a36Sopenharmony_ci */
114562306a36Sopenharmony_cistatic int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
114662306a36Sopenharmony_ci	unsigned blue, unsigned transp, struct fb_info *fbi)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	volatile u32 *palette = lcd->palette;
114962306a36Sopenharmony_ci	u32 value;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1))
115262306a36Sopenharmony_ci		return -EINVAL;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (fbi->var.grayscale) {
115562306a36Sopenharmony_ci		/* Convert color to grayscale */
115662306a36Sopenharmony_ci		red = green = blue =
115762306a36Sopenharmony_ci			(19595 * red + 38470 * green + 7471 * blue) >> 16;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
116162306a36Sopenharmony_ci		/* Place color in the pseudopalette */
116262306a36Sopenharmony_ci		if (regno > 16)
116362306a36Sopenharmony_ci			return -EINVAL;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		palette = (u32*) fbi->pseudo_palette;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci		red   >>= (16 - fbi->var.red.length);
116862306a36Sopenharmony_ci		green >>= (16 - fbi->var.green.length);
116962306a36Sopenharmony_ci		blue  >>= (16 - fbi->var.blue.length);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		value = (red   << fbi->var.red.offset) 	|
117262306a36Sopenharmony_ci			(green << fbi->var.green.offset)|
117362306a36Sopenharmony_ci			(blue  << fbi->var.blue.offset);
117462306a36Sopenharmony_ci		value &= 0xFFFF;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	} else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) {
117762306a36Sopenharmony_ci		/* COLOR TFT PALLETTIZED (use RGB 565) */
117862306a36Sopenharmony_ci		value = (red & 0xF800)|((green >> 5) &
117962306a36Sopenharmony_ci				0x07E0)|((blue >> 11) & 0x001F);
118062306a36Sopenharmony_ci		value &= 0xFFFF;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	} else if (0 /*panel_is_color(fbdev->panel)*/) {
118362306a36Sopenharmony_ci		/* COLOR STN MODE */
118462306a36Sopenharmony_ci		value = 0x1234;
118562306a36Sopenharmony_ci		value &= 0xFFF;
118662306a36Sopenharmony_ci	} else {
118762306a36Sopenharmony_ci		/* MONOCHROME MODE */
118862306a36Sopenharmony_ci		value = (green >> 12) & 0x000F;
118962306a36Sopenharmony_ci		value &= 0xF;
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	palette[regno] = value;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	return 0;
119562306a36Sopenharmony_ci}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci/* fb_blank
119862306a36Sopenharmony_ci * Blank the screen. Depending on the mode, the screen will be
119962306a36Sopenharmony_ci * activated with the backlight color, or desactivated
120062306a36Sopenharmony_ci */
120162306a36Sopenharmony_cistatic int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	struct au1200fb_device *fbdev = fbi->par;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/* Short-circuit screen blanking */
120662306a36Sopenharmony_ci	if (noblanking)
120762306a36Sopenharmony_ci		return 0;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	switch (blank_mode) {
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	case FB_BLANK_UNBLANK:
121262306a36Sopenharmony_ci	case FB_BLANK_NORMAL:
121362306a36Sopenharmony_ci		/* printk("turn on panel\n"); */
121462306a36Sopenharmony_ci		au1200_setpanel(panel, fbdev->pd);
121562306a36Sopenharmony_ci		break;
121662306a36Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
121762306a36Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
121862306a36Sopenharmony_ci	case FB_BLANK_POWERDOWN:
121962306a36Sopenharmony_ci		/* printk("turn off panel\n"); */
122062306a36Sopenharmony_ci		au1200_setpanel(NULL, fbdev->pd);
122162306a36Sopenharmony_ci		break;
122262306a36Sopenharmony_ci	default:
122362306a36Sopenharmony_ci		break;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/* FB_BLANK_NORMAL is a soft blank */
122862306a36Sopenharmony_ci	return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci/* fb_mmap
123262306a36Sopenharmony_ci * Map video memory in user space. We don't use the generic fb_mmap
123362306a36Sopenharmony_ci * method mainly to allow the use of the TLB streaming flag (CCA=6)
123462306a36Sopenharmony_ci */
123562306a36Sopenharmony_cistatic int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct au1200fb_device *fbdev = info->par;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	return dma_mmap_coherent(fbdev->dev, vma,
124062306a36Sopenharmony_ci				 fbdev->fb_mem, fbdev->fb_phys, fbdev->fb_len);
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	unsigned int hi1, divider;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/* SCREEN_SIZE: user cannot reset size, must switch panel choice */
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	if (pdata->flags & SCREEN_BACKCOLOR)
125162306a36Sopenharmony_ci		lcd->backcolor = pdata->backcolor;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (pdata->flags & SCREEN_BRIGHTNESS) {
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci		// limit brightness pwm duty to >= 30/1600
125662306a36Sopenharmony_ci		if (pdata->brightness < 30) {
125762306a36Sopenharmony_ci			pdata->brightness = 30;
125862306a36Sopenharmony_ci		}
125962306a36Sopenharmony_ci		divider = (lcd->pwmdiv & 0x3FFFF) + 1;
126062306a36Sopenharmony_ci		hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8);
126162306a36Sopenharmony_ci		lcd->pwmhi &= 0xFFFF;
126262306a36Sopenharmony_ci		lcd->pwmhi |= (hi1 << 16);
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (pdata->flags & SCREEN_COLORKEY)
126662306a36Sopenharmony_ci		lcd->colorkey = pdata->colorkey;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	if (pdata->flags & SCREEN_MASK)
126962306a36Sopenharmony_ci		lcd->colorkeymsk = pdata->mask;
127062306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_cistatic void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	unsigned int hi1, divider;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1;
127862306a36Sopenharmony_ci	pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	pdata->backcolor = lcd->backcolor;
128162306a36Sopenharmony_ci	pdata->colorkey = lcd->colorkey;
128262306a36Sopenharmony_ci	pdata->mask = lcd->colorkeymsk;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	// brightness
128562306a36Sopenharmony_ci	hi1 = (lcd->pwmhi >> 16) + 1;
128662306a36Sopenharmony_ci	divider = (lcd->pwmdiv & 0x3FFFF) + 1;
128762306a36Sopenharmony_ci	pdata->brightness = ((hi1 << 8) / divider) - 1;
128862306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic void set_window(unsigned int plane,
129262306a36Sopenharmony_ci	struct au1200_lcd_window_regs_t *pdata)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	unsigned int val, bpp;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	/* Window control register 0 */
129762306a36Sopenharmony_ci	if (pdata->flags & WIN_POSITION) {
129862306a36Sopenharmony_ci		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX |
129962306a36Sopenharmony_ci				LCD_WINCTRL0_OY);
130062306a36Sopenharmony_ci		val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX);
130162306a36Sopenharmony_ci		val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY);
130262306a36Sopenharmony_ci		lcd->window[plane].winctrl0 = val;
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci	if (pdata->flags & WIN_ALPHA_COLOR) {
130562306a36Sopenharmony_ci		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A);
130662306a36Sopenharmony_ci		val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A);
130762306a36Sopenharmony_ci		lcd->window[plane].winctrl0 = val;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci	if (pdata->flags & WIN_ALPHA_MODE) {
131062306a36Sopenharmony_ci		val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN);
131162306a36Sopenharmony_ci		val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN);
131262306a36Sopenharmony_ci		lcd->window[plane].winctrl0 = val;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	/* Window control register 1 */
131662306a36Sopenharmony_ci	if (pdata->flags & WIN_PRIORITY) {
131762306a36Sopenharmony_ci		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI);
131862306a36Sopenharmony_ci		val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI);
131962306a36Sopenharmony_ci		lcd->window[plane].winctrl1 = val;
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci	if (pdata->flags & WIN_CHANNEL) {
132262306a36Sopenharmony_ci		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE);
132362306a36Sopenharmony_ci		val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE);
132462306a36Sopenharmony_ci		lcd->window[plane].winctrl1 = val;
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci	if (pdata->flags & WIN_BUFFER_FORMAT) {
132762306a36Sopenharmony_ci		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM);
132862306a36Sopenharmony_ci		val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM);
132962306a36Sopenharmony_ci		lcd->window[plane].winctrl1 = val;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci	if (pdata->flags & WIN_COLOR_ORDER) {
133262306a36Sopenharmony_ci		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO);
133362306a36Sopenharmony_ci		val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO);
133462306a36Sopenharmony_ci		lcd->window[plane].winctrl1 = val;
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci	if (pdata->flags & WIN_PIXEL_ORDER) {
133762306a36Sopenharmony_ci		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO);
133862306a36Sopenharmony_ci		val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO);
133962306a36Sopenharmony_ci		lcd->window[plane].winctrl1 = val;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci	if (pdata->flags & WIN_SIZE) {
134262306a36Sopenharmony_ci		val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX |
134362306a36Sopenharmony_ci				LCD_WINCTRL1_SZY);
134462306a36Sopenharmony_ci		val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX);
134562306a36Sopenharmony_ci		val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY);
134662306a36Sopenharmony_ci		lcd->window[plane].winctrl1 = val;
134762306a36Sopenharmony_ci		/* program buffer line width */
134862306a36Sopenharmony_ci		bpp = winbpp(val) / 8;
134962306a36Sopenharmony_ci		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX);
135062306a36Sopenharmony_ci		val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX);
135162306a36Sopenharmony_ci		lcd->window[plane].winctrl2 = val;
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	/* Window control register 2 */
135562306a36Sopenharmony_ci	if (pdata->flags & WIN_COLORKEY_MODE) {
135662306a36Sopenharmony_ci		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE);
135762306a36Sopenharmony_ci		val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE);
135862306a36Sopenharmony_ci		lcd->window[plane].winctrl2 = val;
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci	if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) {
136162306a36Sopenharmony_ci		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM);
136262306a36Sopenharmony_ci		val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM);
136362306a36Sopenharmony_ci		lcd->window[plane].winctrl2 = val;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci	if (pdata->flags & WIN_RAM_ARRAY_MODE) {
136662306a36Sopenharmony_ci		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM);
136762306a36Sopenharmony_ci		val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM);
136862306a36Sopenharmony_ci		lcd->window[plane].winctrl2 = val;
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	/* Buffer line width programmed with WIN_SIZE */
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	if (pdata->flags & WIN_BUFFER_SCALE) {
137462306a36Sopenharmony_ci		val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX |
137562306a36Sopenharmony_ci				LCD_WINCTRL2_SCY);
137662306a36Sopenharmony_ci		val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX);
137762306a36Sopenharmony_ci		val |= ((pdata->ysize) & LCD_WINCTRL2_SCY);
137862306a36Sopenharmony_ci		lcd->window[plane].winctrl2 = val;
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	if (pdata->flags & WIN_ENABLE) {
138262306a36Sopenharmony_ci		val = lcd->winenable;
138362306a36Sopenharmony_ci		val &= ~(1<<plane);
138462306a36Sopenharmony_ci		val |= (pdata->enable & 1) << plane;
138562306a36Sopenharmony_ci		lcd->winenable = val;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void get_window(unsigned int plane,
139162306a36Sopenharmony_ci	struct au1200_lcd_window_regs_t *pdata)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	/* Window control register 0 */
139462306a36Sopenharmony_ci	pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
139562306a36Sopenharmony_ci	pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
139662306a36Sopenharmony_ci	pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2;
139762306a36Sopenharmony_ci	pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	/* Window control register 1 */
140062306a36Sopenharmony_ci	pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30;
140162306a36Sopenharmony_ci	pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29;
140262306a36Sopenharmony_ci	pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25;
140362306a36Sopenharmony_ci	pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24;
140462306a36Sopenharmony_ci	pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22;
140562306a36Sopenharmony_ci	pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1;
140662306a36Sopenharmony_ci	pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/* Window control register 2 */
140962306a36Sopenharmony_ci	pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24;
141062306a36Sopenharmony_ci	pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23;
141162306a36Sopenharmony_ci	pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	pdata->enable = (lcd->winenable >> plane) & 1;
141462306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
141862306a36Sopenharmony_ci                          unsigned long arg)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	struct au1200fb_device *fbdev = info->par;
142162306a36Sopenharmony_ci	int plane;
142262306a36Sopenharmony_ci	int val;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	plane = fbinfo2index(info);
142562306a36Sopenharmony_ci	print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (cmd == AU1200_LCD_FB_IOCTL) {
142862306a36Sopenharmony_ci		struct au1200_lcd_iodata_t iodata;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata)))
143162306a36Sopenharmony_ci			return -EFAULT;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		print_dbg("FB IOCTL called\n");
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		switch (iodata.subcmd) {
143662306a36Sopenharmony_ci		case AU1200_LCD_SET_SCREEN:
143762306a36Sopenharmony_ci			print_dbg("AU1200_LCD_SET_SCREEN\n");
143862306a36Sopenharmony_ci			set_global(cmd, &iodata.global);
143962306a36Sopenharmony_ci			break;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		case AU1200_LCD_GET_SCREEN:
144262306a36Sopenharmony_ci			print_dbg("AU1200_LCD_GET_SCREEN\n");
144362306a36Sopenharmony_ci			get_global(cmd, &iodata.global);
144462306a36Sopenharmony_ci			break;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		case AU1200_LCD_SET_WINDOW:
144762306a36Sopenharmony_ci			print_dbg("AU1200_LCD_SET_WINDOW\n");
144862306a36Sopenharmony_ci			set_window(plane, &iodata.window);
144962306a36Sopenharmony_ci			break;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci		case AU1200_LCD_GET_WINDOW:
145262306a36Sopenharmony_ci			print_dbg("AU1200_LCD_GET_WINDOW\n");
145362306a36Sopenharmony_ci			get_window(plane, &iodata.window);
145462306a36Sopenharmony_ci			break;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci		case AU1200_LCD_SET_PANEL:
145762306a36Sopenharmony_ci			print_dbg("AU1200_LCD_SET_PANEL\n");
145862306a36Sopenharmony_ci			if ((iodata.global.panel_choice >= 0) &&
145962306a36Sopenharmony_ci					(iodata.global.panel_choice <
146062306a36Sopenharmony_ci					 NUM_PANELS))
146162306a36Sopenharmony_ci			{
146262306a36Sopenharmony_ci				struct panel_settings *newpanel;
146362306a36Sopenharmony_ci				panel_index = iodata.global.panel_choice;
146462306a36Sopenharmony_ci				newpanel = &known_lcd_panels[panel_index];
146562306a36Sopenharmony_ci				au1200_setpanel(newpanel, fbdev->pd);
146662306a36Sopenharmony_ci			}
146762306a36Sopenharmony_ci			break;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci		case AU1200_LCD_GET_PANEL:
147062306a36Sopenharmony_ci			print_dbg("AU1200_LCD_GET_PANEL\n");
147162306a36Sopenharmony_ci			iodata.global.panel_choice = panel_index;
147262306a36Sopenharmony_ci			break;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		default:
147562306a36Sopenharmony_ci			return -EINVAL;
147662306a36Sopenharmony_ci		}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci		val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata));
147962306a36Sopenharmony_ci		if (val) {
148062306a36Sopenharmony_ci			print_dbg("error: could not copy %d bytes\n", val);
148162306a36Sopenharmony_ci			return -EFAULT;
148262306a36Sopenharmony_ci		}
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return 0;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic const struct fb_ops au1200fb_fb_ops = {
149062306a36Sopenharmony_ci	.owner		= THIS_MODULE,
149162306a36Sopenharmony_ci	.fb_check_var	= au1200fb_fb_check_var,
149262306a36Sopenharmony_ci	.fb_set_par	= au1200fb_fb_set_par,
149362306a36Sopenharmony_ci	.fb_setcolreg	= au1200fb_fb_setcolreg,
149462306a36Sopenharmony_ci	.fb_blank	= au1200fb_fb_blank,
149562306a36Sopenharmony_ci	.fb_fillrect	= sys_fillrect,
149662306a36Sopenharmony_ci	.fb_copyarea	= sys_copyarea,
149762306a36Sopenharmony_ci	.fb_imageblit	= sys_imageblit,
149862306a36Sopenharmony_ci	.fb_read	= fb_sys_read,
149962306a36Sopenharmony_ci	.fb_write	= fb_sys_write,
150062306a36Sopenharmony_ci	.fb_sync	= NULL,
150162306a36Sopenharmony_ci	.fb_ioctl	= au1200fb_ioctl,
150262306a36Sopenharmony_ci	.fb_mmap	= au1200fb_fb_mmap,
150362306a36Sopenharmony_ci};
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_cistatic irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	/* Nothing to do for now, just clear any pending interrupt */
151062306a36Sopenharmony_ci	lcd->intstatus = lcd->intstatus;
151162306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	return IRQ_HANDLED;
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci/* AU1200 LCD device probe helpers */
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cistatic int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	struct fb_info *fbi = fbdev->fb_info;
152362306a36Sopenharmony_ci	int bpp, ret;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	fbi->fbops = &au1200fb_fb_ops;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	/* Copy monitor specs from panel data */
153062306a36Sopenharmony_ci	/* fixme: we're setting up LCD controller windows, so these dont give a
153162306a36Sopenharmony_ci	damn as to what the monitor specs are (the panel itself does, but that
153262306a36Sopenharmony_ci	isn't done here...so maybe need a generic catchall monitor setting??? */
153362306a36Sopenharmony_ci	memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs));
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	/* We first try the user mode passed in argument. If that failed,
153662306a36Sopenharmony_ci	 * or if no one has been specified, we default to the first mode of the
153762306a36Sopenharmony_ci	 * panel list. Note that after this call, var data will be set */
153862306a36Sopenharmony_ci	if (!fb_find_mode(&fbi->var,
153962306a36Sopenharmony_ci			  fbi,
154062306a36Sopenharmony_ci			  NULL, /* drv_info.opt_mode, */
154162306a36Sopenharmony_ci			  fbi->monspecs.modedb,
154262306a36Sopenharmony_ci			  fbi->monspecs.modedb_len,
154362306a36Sopenharmony_ci			  fbi->monspecs.modedb,
154462306a36Sopenharmony_ci			  bpp)) {
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci		print_err("Cannot find valid mode for panel %s", panel->name);
154762306a36Sopenharmony_ci		return -EFAULT;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
155162306a36Sopenharmony_ci	if (!fbi->pseudo_palette)
155262306a36Sopenharmony_ci		return -ENOMEM;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	ret = fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0);
155562306a36Sopenharmony_ci	if (ret < 0) {
155662306a36Sopenharmony_ci		print_err("Fail to allocate colormap (%d entries)",
155762306a36Sopenharmony_ci			  AU1200_LCD_NBR_PALETTE_ENTRIES);
155862306a36Sopenharmony_ci		return ret;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id));
156262306a36Sopenharmony_ci	fbi->fix.smem_start = fbdev->fb_phys;
156362306a36Sopenharmony_ci	fbi->fix.smem_len = fbdev->fb_len;
156462306a36Sopenharmony_ci	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
156562306a36Sopenharmony_ci	fbi->fix.xpanstep = 0;
156662306a36Sopenharmony_ci	fbi->fix.ypanstep = 0;
156762306a36Sopenharmony_ci	fbi->fix.mmio_start = 0;
156862306a36Sopenharmony_ci	fbi->fix.mmio_len = 0;
156962306a36Sopenharmony_ci	fbi->fix.accel = FB_ACCEL_NONE;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	fbi->screen_buffer = fbdev->fb_mem;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	au1200fb_update_fbinfo(fbi);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	return 0;
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistatic int au1200fb_setup(struct au1200fb_platdata *pd)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	char *options = NULL;
158462306a36Sopenharmony_ci	char *this_opt, *endptr;
158562306a36Sopenharmony_ci	int num_panels = ARRAY_SIZE(known_lcd_panels);
158662306a36Sopenharmony_ci	int panel_idx = -1;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	fb_get_options(DRIVER_NAME, &options);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	if (!options)
159162306a36Sopenharmony_ci		goto out;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
159462306a36Sopenharmony_ci		/* Panel option - can be panel name,
159562306a36Sopenharmony_ci		 * "bs" for board-switch, or number/index */
159662306a36Sopenharmony_ci		if (!strncmp(this_opt, "panel:", 6)) {
159762306a36Sopenharmony_ci			int i;
159862306a36Sopenharmony_ci			long int li;
159962306a36Sopenharmony_ci			char *endptr;
160062306a36Sopenharmony_ci			this_opt += 6;
160162306a36Sopenharmony_ci			/* First check for index, which allows
160262306a36Sopenharmony_ci			 * to short circuit this mess */
160362306a36Sopenharmony_ci			li = simple_strtol(this_opt, &endptr, 0);
160462306a36Sopenharmony_ci			if (*endptr == '\0')
160562306a36Sopenharmony_ci				panel_idx = (int)li;
160662306a36Sopenharmony_ci			else if (strcmp(this_opt, "bs") == 0)
160762306a36Sopenharmony_ci				panel_idx = pd->panel_index();
160862306a36Sopenharmony_ci			else {
160962306a36Sopenharmony_ci				for (i = 0; i < num_panels; i++) {
161062306a36Sopenharmony_ci					if (!strcmp(this_opt,
161162306a36Sopenharmony_ci						    known_lcd_panels[i].name)) {
161262306a36Sopenharmony_ci						panel_idx = i;
161362306a36Sopenharmony_ci						break;
161462306a36Sopenharmony_ci					}
161562306a36Sopenharmony_ci				}
161662306a36Sopenharmony_ci			}
161762306a36Sopenharmony_ci			if ((panel_idx < 0) || (panel_idx >= num_panels))
161862306a36Sopenharmony_ci				print_warn("Panel %s not supported!", this_opt);
161962306a36Sopenharmony_ci			else
162062306a36Sopenharmony_ci				panel_index = panel_idx;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci		} else if (strncmp(this_opt, "nohwcursor", 10) == 0)
162362306a36Sopenharmony_ci			nohwcursor = 1;
162462306a36Sopenharmony_ci		else if (strncmp(this_opt, "devices:", 8) == 0) {
162562306a36Sopenharmony_ci			this_opt += 8;
162662306a36Sopenharmony_ci			device_count = simple_strtol(this_opt, &endptr, 0);
162762306a36Sopenharmony_ci			if ((device_count < 0) ||
162862306a36Sopenharmony_ci			    (device_count > MAX_DEVICE_COUNT))
162962306a36Sopenharmony_ci				device_count = MAX_DEVICE_COUNT;
163062306a36Sopenharmony_ci		} else if (strncmp(this_opt, "wincfg:", 7) == 0) {
163162306a36Sopenharmony_ci			this_opt += 7;
163262306a36Sopenharmony_ci			window_index = simple_strtol(this_opt, &endptr, 0);
163362306a36Sopenharmony_ci			if ((window_index < 0) ||
163462306a36Sopenharmony_ci			    (window_index >= ARRAY_SIZE(windows)))
163562306a36Sopenharmony_ci				window_index = DEFAULT_WINDOW_INDEX;
163662306a36Sopenharmony_ci		} else if (strncmp(this_opt, "off", 3) == 0)
163762306a36Sopenharmony_ci			return 1;
163862306a36Sopenharmony_ci		else
163962306a36Sopenharmony_ci			print_warn("Unsupported option \"%s\"", this_opt);
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ciout:
164362306a36Sopenharmony_ci	return 0;
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci/* AU1200 LCD controller device driver */
164762306a36Sopenharmony_cistatic int au1200fb_drv_probe(struct platform_device *dev)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	struct au1200fb_device *fbdev;
165062306a36Sopenharmony_ci	struct au1200fb_platdata *pd;
165162306a36Sopenharmony_ci	struct fb_info *fbi = NULL;
165262306a36Sopenharmony_ci	int bpp, plane, ret, irq;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	print_info("" DRIVER_DESC "");
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	pd = dev->dev.platform_data;
165762306a36Sopenharmony_ci	if (!pd)
165862306a36Sopenharmony_ci		return -ENODEV;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	/* Setup driver with options */
166162306a36Sopenharmony_ci	if (au1200fb_setup(pd))
166262306a36Sopenharmony_ci		return -ENODEV;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	/* Point to the panel selected */
166562306a36Sopenharmony_ci	panel = &known_lcd_panels[panel_index];
166662306a36Sopenharmony_ci	win = &windows[window_index];
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
166962306a36Sopenharmony_ci	printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	for (plane = 0; plane < device_count; ++plane) {
167262306a36Sopenharmony_ci		bpp = winbpp(win->w[plane].mode_winctrl1);
167362306a36Sopenharmony_ci		if (win->w[plane].xres == 0)
167462306a36Sopenharmony_ci			win->w[plane].xres = panel->Xres;
167562306a36Sopenharmony_ci		if (win->w[plane].yres == 0)
167662306a36Sopenharmony_ci			win->w[plane].yres = panel->Yres;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci		fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
167962306a36Sopenharmony_ci					&dev->dev);
168062306a36Sopenharmony_ci		if (!fbi) {
168162306a36Sopenharmony_ci			ret = -ENOMEM;
168262306a36Sopenharmony_ci			goto failed;
168362306a36Sopenharmony_ci		}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci		_au1200fb_infos[plane] = fbi;
168662306a36Sopenharmony_ci		fbdev = fbi->par;
168762306a36Sopenharmony_ci		fbdev->fb_info = fbi;
168862306a36Sopenharmony_ci		fbdev->pd = pd;
168962306a36Sopenharmony_ci		fbdev->dev = &dev->dev;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci		fbdev->plane = plane;
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci		/* Allocate the framebuffer to the maximum screen size */
169462306a36Sopenharmony_ci		fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci		fbdev->fb_mem = dmam_alloc_attrs(&dev->dev,
169762306a36Sopenharmony_ci				PAGE_ALIGN(fbdev->fb_len),
169862306a36Sopenharmony_ci				&fbdev->fb_phys, GFP_KERNEL, 0);
169962306a36Sopenharmony_ci		if (!fbdev->fb_mem) {
170062306a36Sopenharmony_ci			print_err("fail to allocate framebuffer (size: %dK))",
170162306a36Sopenharmony_ci				  fbdev->fb_len / 1024);
170262306a36Sopenharmony_ci			ret = -ENOMEM;
170362306a36Sopenharmony_ci			goto failed;
170462306a36Sopenharmony_ci		}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci		print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
170762306a36Sopenharmony_ci		print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci		/* Init FB data */
171062306a36Sopenharmony_ci		ret = au1200fb_init_fbinfo(fbdev);
171162306a36Sopenharmony_ci		if (ret < 0)
171262306a36Sopenharmony_ci			goto failed;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci		/* Register new framebuffer */
171562306a36Sopenharmony_ci		ret = register_framebuffer(fbi);
171662306a36Sopenharmony_ci		if (ret < 0) {
171762306a36Sopenharmony_ci			print_err("cannot register new framebuffer");
171862306a36Sopenharmony_ci			goto failed;
171962306a36Sopenharmony_ci		}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci		au1200fb_fb_set_par(fbi);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
172462306a36Sopenharmony_ci		if (plane == 0)
172562306a36Sopenharmony_ci			if (fb_prepare_logo(fbi, FB_ROTATE_UR)) {
172662306a36Sopenharmony_ci				/* Start display and show logo on boot */
172762306a36Sopenharmony_ci				fb_set_cmap(&fbi->cmap, fbi);
172862306a36Sopenharmony_ci				fb_show_logo(fbi, FB_ROTATE_UR);
172962306a36Sopenharmony_ci			}
173062306a36Sopenharmony_ci#endif
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	/* Now hook interrupt too */
173462306a36Sopenharmony_ci	irq = platform_get_irq(dev, 0);
173562306a36Sopenharmony_ci	if (irq < 0)
173662306a36Sopenharmony_ci		return irq;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	ret = request_irq(irq, au1200fb_handle_irq,
173962306a36Sopenharmony_ci			  IRQF_SHARED, "lcd", (void *)dev);
174062306a36Sopenharmony_ci	if (ret) {
174162306a36Sopenharmony_ci		print_err("fail to request interrupt line %d (err: %d)",
174262306a36Sopenharmony_ci			  irq, ret);
174362306a36Sopenharmony_ci		goto failed;
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	platform_set_drvdata(dev, pd);
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	/* Kickstart the panel */
174962306a36Sopenharmony_ci	au1200_setpanel(panel, pd);
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	return 0;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cifailed:
175462306a36Sopenharmony_ci	for (plane = 0; plane < device_count; ++plane) {
175562306a36Sopenharmony_ci		fbi = _au1200fb_infos[plane];
175662306a36Sopenharmony_ci		if (!fbi)
175762306a36Sopenharmony_ci			break;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci		/* Clean up all probe data */
176062306a36Sopenharmony_ci		unregister_framebuffer(fbi);
176162306a36Sopenharmony_ci		if (fbi->cmap.len != 0)
176262306a36Sopenharmony_ci			fb_dealloc_cmap(&fbi->cmap);
176362306a36Sopenharmony_ci		kfree(fbi->pseudo_palette);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci		framebuffer_release(fbi);
176662306a36Sopenharmony_ci		_au1200fb_infos[plane] = NULL;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci	return ret;
176962306a36Sopenharmony_ci}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cistatic void au1200fb_drv_remove(struct platform_device *dev)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct au1200fb_platdata *pd = platform_get_drvdata(dev);
177462306a36Sopenharmony_ci	struct fb_info *fbi;
177562306a36Sopenharmony_ci	int plane;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	/* Turn off the panel */
177862306a36Sopenharmony_ci	au1200_setpanel(NULL, pd);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	for (plane = 0; plane < device_count; ++plane)	{
178162306a36Sopenharmony_ci		fbi = _au1200fb_infos[plane];
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci		/* Clean up all probe data */
178462306a36Sopenharmony_ci		unregister_framebuffer(fbi);
178562306a36Sopenharmony_ci		if (fbi->cmap.len != 0)
178662306a36Sopenharmony_ci			fb_dealloc_cmap(&fbi->cmap);
178762306a36Sopenharmony_ci		kfree(fbi->pseudo_palette);
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci		framebuffer_release(fbi);
179062306a36Sopenharmony_ci		_au1200fb_infos[plane] = NULL;
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	free_irq(platform_get_irq(dev, 0), (void *)dev);
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci#ifdef CONFIG_PM
179762306a36Sopenharmony_cistatic int au1200fb_drv_suspend(struct device *dev)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	struct au1200fb_platdata *pd = dev_get_drvdata(dev);
180062306a36Sopenharmony_ci	au1200_setpanel(NULL, pd);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	lcd->outmask = 0;
180362306a36Sopenharmony_ci	wmb(); /* drain writebuffer */
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	return 0;
180662306a36Sopenharmony_ci}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_cistatic int au1200fb_drv_resume(struct device *dev)
180962306a36Sopenharmony_ci{
181062306a36Sopenharmony_ci	struct au1200fb_platdata *pd = dev_get_drvdata(dev);
181162306a36Sopenharmony_ci	struct fb_info *fbi;
181262306a36Sopenharmony_ci	int i;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	/* Kickstart the panel */
181562306a36Sopenharmony_ci	au1200_setpanel(panel, pd);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	for (i = 0; i < device_count; i++) {
181862306a36Sopenharmony_ci		fbi = _au1200fb_infos[i];
181962306a36Sopenharmony_ci		au1200fb_fb_set_par(fbi);
182062306a36Sopenharmony_ci	}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	return 0;
182362306a36Sopenharmony_ci}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_cistatic const struct dev_pm_ops au1200fb_pmops = {
182662306a36Sopenharmony_ci	.suspend	= au1200fb_drv_suspend,
182762306a36Sopenharmony_ci	.resume		= au1200fb_drv_resume,
182862306a36Sopenharmony_ci	.freeze		= au1200fb_drv_suspend,
182962306a36Sopenharmony_ci	.thaw		= au1200fb_drv_resume,
183062306a36Sopenharmony_ci};
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci#define AU1200FB_PMOPS	(&au1200fb_pmops)
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci#else
183562306a36Sopenharmony_ci#define AU1200FB_PMOPS	NULL
183662306a36Sopenharmony_ci#endif /* CONFIG_PM */
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_cistatic struct platform_driver au1200fb_driver = {
183962306a36Sopenharmony_ci	.driver = {
184062306a36Sopenharmony_ci		.name	= "au1200-lcd",
184162306a36Sopenharmony_ci		.pm	= AU1200FB_PMOPS,
184262306a36Sopenharmony_ci	},
184362306a36Sopenharmony_ci	.probe		= au1200fb_drv_probe,
184462306a36Sopenharmony_ci	.remove_new	= au1200fb_drv_remove,
184562306a36Sopenharmony_ci};
184662306a36Sopenharmony_cimodule_platform_driver(au1200fb_driver);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
184962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1850