cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

au1200fb.c (49791B)


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