11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/drivers/video/sa1100fb.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1999 Eric A. Thomas
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Based on acornfb.c Copyright (C) Russell King.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License.  See the file COPYING in the main directory of this archive for
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more details.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	        StrongARM 1100 LCD Controller Frame Buffer Driver
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Please direct your questions and comments on this driver to the following
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * email address:
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	linux-arm-kernel@lists.arm.linux.org.uk
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean patches should be sent to the ARM Linux Patch System.  Please see the
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * following web page for more information:
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	http://www.arm.linux.org.uk/developer/patches/info.shtml
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thank you.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Known problems:
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- With the Neponset plugged into an Assabet, LCD powerdown
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  doesn't work (LCD stays powered up).  Therefore we shouldn't
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  blank the screen.
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- We don't limit the CPU clock rate nor the mode selection
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  according to the available SDRAM bandwidth.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Other notes:
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Linear grayscale palettes and the kernel.
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  Such code does not belong in the kernel.  The kernel frame buffer
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  drivers do not expect a linear colourmap, but a colourmap based on
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  the VT100 standard mapping.
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  If your _userspace_ requires a linear colourmap, then the setup of
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  such a colourmap belongs _in userspace_, not in the kernel.  Code
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  to set the colourmap correctly from user space has been sent to
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  David Neuer.  It's around 8 lines of C code, plus another 4 to
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  detect if we are using grayscale.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- The following must never be specified in a panel definition:
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- The following should be specified:
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     either LCCR0_Color or LCCR0_Mono
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     either LCCR0_Sngl or LCCR0_Dual
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     either LCCR0_Act or LCCR0_Pas
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     either LCCR3_OutEnH or LCCD3_OutEnL
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     either LCCR3_PixRsEdg or LCCR3_PixFlEdg
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	     either LCCR3_ACBsDiv or LCCR3_ACBsCntOff
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Code Status:
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1999/04/01:
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Driver appears to be working for Brutus 320x200x8bpp mode.  Other
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  resolutions are working, but only the 8bpp mode is supported.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  Changes need to be made to the palette encode and decode routines
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  to support 4 and 16 bpp modes.
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  Driver is not designed to be a module.  The FrameBuffer is statically
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  allocated since dynamic allocation of a 300k buffer cannot be
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  guaranteed.
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1999/06/17:
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- FrameBuffer memory is now allocated at run-time when the
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  driver is initialized.
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
692f82af08fcc7dc01a7e98a49a5995a77e32a2925Nicolas Pitre * 2000/04/10: Nicolas Pitre <nico@fluxnic.net>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Big cleanup for dynamic selection of machine type at run time.
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/07/19: Jamey Hicks <jamey@crl.dec.com>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Support for Bitsy aka Compaq iPAQ H3600 added.
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com>
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	       Jeff Sutherland <jsutherland@accelent.com>
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Resolved an issue caused by a change made to the Assabet's PLD
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  earlier this year which broke the framebuffer driver for newer
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  Phase 4 Assabets.  Some other parameters were changed to optimize
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  for the Sharp display.
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp>
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- XP860 support added
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/08/19: Mark Huang <mhuang@livetoy.com>
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Allows standard options to be passed on the kernel command line
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  for most common passive displays.
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/08/29:
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- s/save_flags_cli/local_irq_save/
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Updated LART stuff. Fixed some minor bugs.
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw>
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Pangolin support added
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de>
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Huw Webpanel support added
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2000/11/23: Eric Peng <ericpeng@coventive.com>
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Freebird add
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com>
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	       Cliff Brake <cbrake@accelent.com>
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Added PM callback
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/05/26: <rmk@arm.linux.org.uk>
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Fix 16bpp so that (a) we use the right colours rather than some
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  totally random colour depending on what was in page 0, and (b)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  we don't de-reference a NULL pointer.
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- remove duplicated implementation of consistent_alloc()
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- convert dma address types to dma_addr_t
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- remove unused 'montype' stuff
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- remove redundant zero inits of init_var after the initial
11759f0cb0fddc14ffc6676ae62e911f8115ebc8ccfRussell King *	  memset.
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- remove allow_modeset (acornfb idea does not belong here)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/05/28: <rmk@arm.linux.org.uk>
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- massive cleanup - move machine dependent data into structures
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- I've left various #warnings in - if you see one, and know
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  the hardware concerned, please get in contact with me.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/05/31: <rmk@arm.linux.org.uk>
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Fix LCCR1 HSW value, fix all machine type specifications to
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  keep values in line.  (Please check your machine type specs)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/06/10: <rmk@arm.linux.org.uk>
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Fiddle with the LCD controller from task context only; mainly
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  so that we can run with interrupts on, and sleep.
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Convert #warnings into #errors.  No pain, no gain. ;)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/06/14: <rmk@arm.linux.org.uk>
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Make the palette BPS value for 12bpp come out correctly.
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Take notice of "greyscale" on any colour depth.
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Make truecolor visuals use the RGB channel encoding information.
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/07/02: <rmk@arm.linux.org.uk>
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Fix colourmap problems.
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/07/13: <abraham@2d3d.co.za>
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Added support for the ICP LCD-Kit01 on LART. This LCD is
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  manufactured by Prime View, model no V16C6448AB
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/07/23: <rmk@arm.linux.org.uk>
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Hand merge version from handhelds.org CVS tree.  See patch
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  notes for 595/1 for more information.
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Drop 12bpp (it's 16bpp with different colour register mappings).
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- This hardware can not do direct colour.  Therefore we don't
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  support it.
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/07/27: <rmk@arm.linux.org.uk>
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Halve YRES on dual scan LCDs.
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/08/22: <rmk@arm.linux.org.uk>
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Add b/w iPAQ pixclock value.
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001/10/12: <rmk@arm.linux.org.uk>
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- Add patch 681/1 and clean up stork definitions.
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
17027ac792ca0b0a1e7e65f20342260650516c95864Andrea Righi#include <linux/mm.h>
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fb.h>
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cpufreq.h>
176d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h>
1787951ac91c7d45b61f54f1cdabc24b52b40785de6Matthias Kaehlcke#include <linux/mutex.h>
179997302259f386bca8fe1db67c50296ca426c438fRussell King#include <linux/io.h>
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h>
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mach-types.h>
183a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/assabet.h>
184a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/shannon.h>
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * debugging?
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG 0
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complain if VAR is out of range.
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_VAR 1
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef ASSABET_PAL_VIDEO
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sa1100fb.h"
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern void (*sa1100fb_backlight_power)(int on);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern void (*sa1100fb_lcd_power)(int on);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2020a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewskistatic struct sa1100fb_rgb rgb_4 = {
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.red	= { .offset = 0,  .length = 4, },
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green	= { .offset = 0,  .length = 4, },
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue	= { .offset = 0,  .length = 4, },
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.transp	= { .offset = 0,  .length = 0, },
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2090a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewskistatic struct sa1100fb_rgb rgb_8 = {
2100a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski	.red	= { .offset = 0,  .length = 8, },
2110a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski	.green	= { .offset = 0,  .length = 8, },
2120a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski	.blue	= { .offset = 0,  .length = 8, },
2130a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski	.transp	= { .offset = 0,  .length = 0, },
2140a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski};
2150a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_rgb def_rgb_16 = {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.red	= { .offset = 11, .length = 5, },
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green	= { .offset = 5,  .length = 6, },
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue	= { .offset = 0,  .length = 5, },
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.transp	= { .offset = 0,  .length = 0, },
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_ASSABET
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef ASSABET_PAL_VIDEO
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * takes an RGB666 signal, but we provide it with an RGB565 signal
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead (def_rgb_16).
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 171521,	.bpp		= 16,
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 320,		.yres		= 240,
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 5,		.vsync_len	= 1,
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 61,		.upper_margin	= 3,
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 9,		.lower_margin	= 0,
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info pal_info __initdata = {
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 67797,	.bpp		= 16,
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,		.yres		= 512,
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 64,		.vsync_len	= 6,
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 125,		.upper_margin	= 70,
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 115,		.lower_margin	= 36,
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_H3600
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info h3600_info __initdata = {
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 174757, 	.bpp		= 16,
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 320,		.yres		= 240,
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 3,		.vsync_len	= 3,
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 12,		.upper_margin	= 10,
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 17,		.lower_margin	= 1,
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmap_static	= 1,
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_rgb h3600_rgb_16 = {
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.red	= { .offset = 12, .length = 4, },
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.green	= { .offset = 7,  .length = 4, },
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.blue	= { .offset = 1,  .length = 4, },
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.transp	= { .offset = 0,  .length = 0, },
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_H3100
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info h3100_info __initdata = {
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 406977, 	.bpp		= 4,
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 320,		.yres		= 240,
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 26,		.vsync_len	= 41,
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 4,		.upper_margin	= 0,
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 4,		.lower_margin	= 0,
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmap_greyscale	= 1,
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmap_inverse	= 1,
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_COLLIE
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info collie_info __initdata = {
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 171521,	.bpp		= 16,
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 320,		.yres		= 240,
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 5,		.vsync_len	= 1,
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 11,		.upper_margin	= 2,
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 30,		.lower_margin	= 0,
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_GREY_LCD
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info lart_grey_info __initdata = {
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 150000,	.bpp		= 4,
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 320,		.yres		= 240,
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 1,		.vsync_len	= 1,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 4,		.upper_margin	= 0,
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 2,		.lower_margin	= 0,
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cmap_greyscale	= 1,
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_COLOR_LCD
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info lart_color_info __initdata = {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 150000,	.bpp		= 16,
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 320,		.yres		= 240,
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 2,		.vsync_len	= 3,
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 69,		.upper_margin	= 14,
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 8,		.lower_margin	= 4,
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_VIDEO_OUT
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info lart_video_info __initdata = {
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 39721,	.bpp		= 16,
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,		.yres		= 480,
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 95,		.vsync_len	= 2,
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 40,		.upper_margin	= 32,
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 24,		.lower_margin	= 11,
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_KIT01_LCD
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info lart_kit01_info __initdata = {
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 63291,	.bpp		= 16,
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,		.yres		= 480,
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 64,		.vsync_len	= 3,
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 122,		.upper_margin	= 45,
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 10,		.lower_margin	= 10,
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_SHANNON
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info shannon_info __initdata = {
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pixclock	= 152500,	.bpp		= 8,
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xres		= 640,		.yres		= 480,
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hsync_len	= 4,		.vsync_len	= 3,
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.left_margin	= 2,		.upper_margin	= 0,
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.right_margin	= 1,		.lower_margin	= 0,
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lccr3		= LCCR3_ACBsDiv(512),
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_mach_info * __init
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_get_machine_info(struct sa1100fb_info *fbi)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_mach_info *inf = NULL;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *            R        G       B       T
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * h3600    {12,4}, { 7,4}, { 1,4}, { 0,0}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_ASSABET
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_assabet()) {
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef ASSABET_PAL_VIDEO
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &lq039q2ds54_info;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &pal_info;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_H3100
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_h3100()) {
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &h3100_info;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_H3600
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_h3600()) {
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &h3600_info;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->rgb[RGB_16] = &h3600_rgb_16;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_COLLIE
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_collie()) {
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &collie_info;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_LART
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_lart()) {
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_GREY_LCD
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &lart_grey_info;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_COLOR_LCD
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &lart_color_info;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_VIDEO_OUT
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &lart_video_info;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LART_KIT01_LCD
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &lart_kit01_info;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SA1100_SHANNON
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_shannon()) {
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inf = &shannon_info;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return inf;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state)
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We need to handle two requests being made at the same time.
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * There are two important cases:
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *     We must perform the unblanking, which will do our REENABLE for us.
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  2. When we are blanking, but immediately unblank before we have
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fbi->task_state == C_ENABLE && state == C_REENABLE)
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = (u_int) -1;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fbi->task_state == C_DISABLE && state == C_ENABLE)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = C_REENABLE;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state != (u_int)-1) {
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->task_state = state;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule_work(&fbi->task);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chan &= 0xffff;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chan >>= 16 - bf->length;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return chan << bf->offset;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Convert bits-per-pixel to a hardware palette PBS value.
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u_int palette_pbs(struct fb_var_screeninfo *var)
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (var->bits_per_pixel) {
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:  ret = 0 << 12;	break;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:  ret = 1 << 12; break;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 16: ret = 2 << 12; break;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       u_int trans, struct fb_info *info)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int val, ret = 1;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (regno < fbi->palette_size) {
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = ((red >> 4) & 0xf00);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= ((green >> 8) & 0x0f0);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val |= ((blue >> 12) & 0x00f);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regno == 0)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val |= palette_pbs(&fbi->fb.var);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->palette_cpu[regno] = val;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   u_int trans, struct fb_info *info)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 1;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If inverse mode was selected, invert all the colours
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * rather than the register number.  The register number
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * is what you poke into the framebuffer to produce the
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * colour you requested.
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fbi->cmap_inverse) {
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		red   = 0xffff - red;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		green = 0xffff - green;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		blue  = 0xffff - blue;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If greyscale is true, then we convert the RGB value
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to greyscale no mater what visual we are using.
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fbi->fb.var.grayscale)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		red = green = blue = (19595 * red + 38470 * green +
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					7471 * blue) >> 16;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (fbi->fb.fix.visual) {
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_VISUAL_TRUECOLOR:
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * 12 or 16-bit True Colour.  We encode the RGB value
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * according to the RGB bitfield information.
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regno < 16) {
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u32 *pal = fbi->fb.pseudo_palette;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val  = chan_to_field(red, &fbi->fb.var.red);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val |= chan_to_field(green, &fbi->fb.var.green);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val |= chan_to_field(blue, &fbi->fb.var.blue);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pal[regno] = val;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = 0;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_VISUAL_STATIC_PSEUDOCOLOR:
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_VISUAL_PSEUDOCOLOR:
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5776edb7467be2195e7eeb6844e37668253af216100Pavel Machek#ifdef CONFIG_CPU_FREQ
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  sa1100fb_display_dma_period()
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Calculate the minimum period (in picoseconds) between two DMA
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    requests for the LCD controller.  If we hit this, it means we're
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    doing nothing but LCD DMA.
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
584fc1df37e3b195cb73ecb14c30d41b7aace3f844aRussell Kingstatic inline unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Period = pixclock * bits_per_byte * bytes_per_transfer
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *		/ memory_bits_per_pixel;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return var->pixclock * 8 * 16 / var->bits_per_pixel;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5926edb7467be2195e7eeb6844e37668253af216100Pavel Machek#endif
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  sa1100fb_check_var():
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Round up in the following order: bits_per_pixel, xres,
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    bitfields, horizontal timing, vertical timing.
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rgbidx;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres < MIN_XRES)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xres = MIN_XRES;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres < MIN_YRES)
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres = MIN_YRES;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres > fbi->max_xres)
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xres = fbi->max_xres;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres > fbi->max_yres)
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres = fbi->max_yres;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->xres_virtual = max(var->xres_virtual, var->xres);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->yres_virtual = max(var->yres_virtual, var->yres);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (var->bits_per_pixel) {
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 4:
6200a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski		rgbidx = RGB_4;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 8:
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rgbidx = RGB_8;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 16:
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rgbidx = RGB_16;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Copy the RGB parameters for this display
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * from the machine specific parameters.
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->red    = fbi->rgb[rgbidx]->red;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->green  = fbi->rgb[rgbidx]->green;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->blue   = fbi->rgb[rgbidx]->blue;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	var->transp = fbi->rgb[rgbidx]->transp;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("RGBT length = %d:%d:%d:%d\n",
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.length, var->green.length, var->blue.length,
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.length);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->red.offset, var->green.offset, var->blue.offset,
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->transp.offset);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_FREQ
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100fb_display_dma_period(var),
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cpufreq_get(smp_processor_id()));
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void sa1100fb_set_truecolor(u_int is_true_color)
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_assabet()) {
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1		// phase 4 or newer Assabet's
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_true_color)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// older Assabet's
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_true_color)
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sa1100fb_set_par():
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Set the user defined part of the display for the specified console
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sa1100fb_set_par(struct fb_info *info)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fb_var_screeninfo *var = &info->var;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long palette_mem_size;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("set_par\n");
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->bits_per_pixel == 16)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (!fbi->cmap_static)
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Some people have weird ideas about wanting static
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * pseudocolor maps.  I suspect their user space
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * applications are broken.
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.line_length = var->xres_virtual *
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  var->bits_per_pixel / 8;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	palette_mem_size = fbi->palette_size * sizeof(u16);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Set (any) board control register to handle new color depth
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sa1100fb_activate_var(var, fbi);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  struct fb_info *info)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Make sure the user isn't doing something stupid.
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return gen_set_cmap(cmap, kspc, con, info);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Formal definition of the VESA spec:
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  On
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	This refers to the state of the display when it is in full operation
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Stand-By
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	This defines an optional operating state of minimal power reduction with
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	the shortest recovery time
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Suspend
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	This refers to a level of power management in which substantial power
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	reduction is achieved by the display.  The display can have a longer
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	recovery time from this state than from the Stand-by state
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Off
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	This indicates that the display is consuming the lowest level of power
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	and is non-operational. Recovery from this state may optionally require
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	the user to manually power on the monitor
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Now, the fbdev driver adds an additional state, (blank), where they
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  turn off the video (maybe by colormap tricks), but don't mess with the
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  video itself: think of it semantically between on and Stand-By.
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  So here's what we should do in our fbdev blank routine:
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This will match the matrox implementation.
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sa1100fb_blank():
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Blank the display by setting all palette values to zero.  Note, the
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	12 and 16 bpp modes don't really use the palette, so this will not
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      blank the display in all modes.
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sa1100fb_blank(int blank, struct fb_info *info)
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("sa1100fb_blank: blank=%d\n", blank);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (blank) {
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_POWERDOWN:
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_VSYNC_SUSPEND:
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_HSYNC_SUSPEND:
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_NORMAL:
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < fbi->palette_size; i++)
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100fb_schedule_work(fbi, C_DISABLE);
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case FB_BLANK_UNBLANK:
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fb_set_cmap(&fbi->fb.cmap, info);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100fb_schedule_work(fbi, C_ENABLE);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801216d526c89d144928f095f2800bc6c67e968d628Christoph Hellwigstatic int sa1100fb_mmap(struct fb_info *info,
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct vm_area_struct *vma)
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (off < info->fix.smem_len) {
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vma->vm_pgoff += 1; /* skip over the palette */
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     fbi->map_dma, fbi->map_size);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = info->fix.mmio_start;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((vma->vm_end - vma->vm_start + off) > len)
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	off += start & PAGE_MASK;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vma->vm_pgoff = off >> PAGE_SHIFT;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vma->vm_flags |= VM_IO;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   vma->vm_end - vma->vm_start,
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   vma->vm_page_prot);
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_ops sa1100fb_ops = {
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_check_var	= sa1100fb_check_var,
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_set_par	= sa1100fb_set_par,
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	.fb_set_cmap	= sa1100fb_set_cmap,
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_setcolreg	= sa1100fb_setcolreg,
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_fillrect	= cfb_fillrect,
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_copyarea	= cfb_copyarea,
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_imageblit	= cfb_imageblit,
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_blank	= sa1100fb_blank,
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fb_mmap	= sa1100fb_mmap,
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the PCD value from the clock rate (in picoseconds).
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We take account of the PPCR clock setting.
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int pcd = cpuclock / 100;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pcd *= pixclock;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pcd /= 10000000;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pcd + 1;	/* make up for integer math truncations */
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sa1100fb_activate_var():
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Configures LCD Controller based on entries in var parameter.  Settings are
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	only written to the controller if changes were made.
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_lcd_reg new_regs;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int half_screen_size, yres, pcd;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_long flags;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("Configuring SA1100 LCD\n");
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->xres, var->hsync_len,
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->left_margin, var->right_margin);
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->yres, var->vsync_len,
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		var->upper_margin, var->lower_margin);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if DEBUG_VAR
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->xres < 16        || var->xres > 1024)
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid xres %d\n",
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->xres);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->hsync_len < 1    || var->hsync_len > 64)
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid hsync_len %d\n",
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->hsync_len);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->left_margin < 1  || var->left_margin > 255)
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid left_margin %d\n",
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->left_margin);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->right_margin < 1 || var->right_margin > 255)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid right_margin %d\n",
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->right_margin);
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->yres < 1         || var->yres > 1024)
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid yres %d\n",
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->yres);
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->vsync_len < 1    || var->vsync_len > 64)
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid vsync_len %d\n",
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->vsync_len);
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->upper_margin < 0 || var->upper_margin > 255)
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid upper_margin %d\n",
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->upper_margin);
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (var->lower_margin < 0 || var->lower_margin > 255)
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: invalid lower_margin %d\n",
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->fb.fix.id, var->lower_margin);
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_regs.lccr0 = fbi->lccr0 |
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_regs.lccr1 =
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR1_DisWdth(var->xres) +
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR1_HorSnchWdth(var->hsync_len) +
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR1_BegLnDel(var->left_margin) +
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR1_EndLnDel(var->right_margin);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we have a dual scan LCD, then we need to halve
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the YRES parameter.
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	yres = var->yres;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fbi->lccr0 & LCCR0_Dual)
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		yres /= 2;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_regs.lccr2 =
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR2_DisHght(yres) +
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR2_VrtSnchWdth(var->vsync_len) +
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR2_BegFrmDel(var->upper_margin) +
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR2_EndFrmDel(var->lower_margin);
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pcd = get_pcd(var->pixclock, cpufreq_get(0));
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	half_screen_size = var->bits_per_pixel;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	half_screen_size = half_screen_size * var->xres * var->yres / 16;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Update shadow copy atomically */
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->dbar1 = fbi->palette_dma;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->dbar2 = fbi->screen_dma + half_screen_size;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->reg_lccr0 = new_regs.lccr0;
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->reg_lccr1 = new_regs.lccr1;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->reg_lccr2 = new_regs.lccr2;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->reg_lccr3 = new_regs.lccr3;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Only update the registers if the controller is enabled
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and something has changed.
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100fb_schedule_work(fbi, C_REENABLE);
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE!  The following functions are purely helpers for set_ctrlr_state.
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Do not call them directly; set_ctrlr_state does the correct serialisation
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to ensure that things happen in the right way 100% of time time.
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	-- rmk
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("backlight o%s\n", on ? "n" : "ff");
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sa1100fb_backlight_power)
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100fb_backlight_power(on);
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("LCD power o%s\n", on ? "n" : "ff");
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sa1100fb_lcd_power)
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100fb_lcd_power(on);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int mask = 0;
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Enable GPIO<9:2> for LCD use if:
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  1. Active display, or
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *  2. Color Dual Passive display
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * see table 11.8 on page 11-27 in the SA1100 manual
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *   -- Erik.
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SA1110 spec update nr. 25 says we can and should
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * clear LDD15 to 12 for 4 or 8bpp modes with active
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * panels.
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (fbi->fb.var.bits_per_pixel > 8 ||
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mask) {
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		GPDR |= mask;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		GAFR |= mask;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("Enabling LCD controller\n");
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Make sure the mode bits are present in the first palette entry
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->palette_cpu[0] &= 0xcfff;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Sequence from 11.7.10 */
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR3 = fbi->reg_lccr3;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR2 = fbi->reg_lccr2;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR1 = fbi->reg_lccr1;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBAR1 = fbi->dbar1;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBAR2 = fbi->dbar2;
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR0 |= LCCR0_LEN;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_shannon()) {
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		GPDR |= SHANNON_GPIO_DISP_EN;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		GPSR |= SHANNON_GPIO_DISP_EN;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DECLARE_WAITQUEUE(wait, current);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK("Disabling LCD controller\n");
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_shannon()) {
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		GPCR |= SHANNON_GPIO_DISP_EN;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_current_state(TASK_UNINTERRUPTIBLE);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_wait_queue(&fbi->ctrlr_wait, &wait);
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCSR = 0xffffffff;	/* Clear LCD Status Register */
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCCR0 &= ~LCCR0_LEN;	/* Disable LCD Controller */
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	schedule_timeout(20 * HZ / 1000);
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_wait_queue(&fbi->ctrlr_wait, &wait);
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10727d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = dev_id;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int lcsr = LCSR;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lcsr & LCSR_LDD) {
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LCCR0 |= LCCR0_LDM;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wake_up(&fbi->ctrlr_wait);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LCSR = lcsr;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function must be called from task context only, since it will
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sleep when disabling the LCD controller, or if we get two contending
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * processes trying to alter state.
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int old_state;
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10957951ac91c7d45b61f54f1cdabc24b52b40785de6Matthias Kaehlcke	mutex_lock(&fbi->ctrlr_lock);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_state = fbi->state;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Hack around fbcon initialisation.
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_state == C_STARTUP && state == C_REENABLE)
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		state = C_ENABLE;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (state) {
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_DISABLE_CLKCHANGE:
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Disable controller for clock change.  If the
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * controller is already disabled, then do nothing.
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->state = state;
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_disable_controller(fbi);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_DISABLE_PM:
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_DISABLE:
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Disable controller
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_state != C_DISABLE) {
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->state = state;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__sa1100fb_backlight_power(fbi, 0);
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (old_state != C_DISABLE_CLKCHANGE)
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sa1100fb_disable_controller(fbi);
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__sa1100fb_lcd_power(fbi, 0);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_ENABLE_CLKCHANGE:
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Enable the controller after clock change.  Only
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * do this if we were disabled for the clock change.
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_state == C_DISABLE_CLKCHANGE) {
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->state = C_ENABLE;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_enable_controller(fbi);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_REENABLE:
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Re-enable the controller only if it was already
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * enabled.  This is so we reprogram the control
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * registers.
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_state == C_ENABLE) {
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_disable_controller(fbi);
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_setup_gpio(fbi);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_enable_controller(fbi);
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_ENABLE_PM:
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Re-enable the controller after PM.  This is not
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * perfect - think about the case where we were doing
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * a clock change, and we suspended half-way through.
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_state != C_DISABLE_PM)
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* fall through */
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case C_ENABLE:
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Power up the LCD screen, enable controller, and
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * turn on the backlight.
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (old_state != C_ENABLE) {
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fbi->state = C_ENABLE;
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_setup_gpio(fbi);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__sa1100fb_lcd_power(fbi, 1);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100fb_enable_controller(fbi);
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			__sa1100fb_backlight_power(fbi, 1);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11807951ac91c7d45b61f54f1cdabc24b52b40785de6Matthias Kaehlcke	mutex_unlock(&fbi->ctrlr_lock);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Our LCD controller task (which is called when we blank or unblank)
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * via keventd.
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11872343217fb770ef2b172a12186c0cd0526bfb7d0cPavel Machekstatic void sa1100fb_task(struct work_struct *w)
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11892343217fb770ef2b172a12186c0cd0526bfb7d0cPavel Machek	struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int state = xchg(&fbi->task_state, -1);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_ctrlr_state(fbi, state);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_FREQ
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the minimum DMA period over all displays that we own.
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This, together with the SDRAM bandwidth defines the slowest CPU
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * frequency that can be selected.
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int min_period = (unsigned int)-1;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_NR_CONSOLES; i++) {
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct display *disp = &fb_display[i];
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int period;
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Do we own this display?
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (disp->fb_info != &fbi->fb)
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Ok, calculate its DMA period
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		period = sa1100fb_display_dma_period(&disp->var);
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (period < min_period)
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			min_period = period;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return min_period;
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * FIXME: we need to verify _all_ consoles.
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sa1100fb_display_dma_period(&fbi->fb.var);
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CPU clock speed change handler.  We need to adjust the LCD timing
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parameters when the CPU clock is adjusted by the power management
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * subsystem.
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 void *data)
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpufreq_freqs *f = data;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int pcd;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_PRECHANGE:
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_POSTCHANGE:
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pcd = get_pcd(fbi->fb.var.pixclock, f->new);
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     void *data)
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct cpufreq_policy *policy = data;
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_ADJUST:
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_INCOMPATIBLE:
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_DEBUG "min dma period: %d ps, "
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			policy->max);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* todo: fill in min/max values */
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_NOTIFY:
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {} while(0);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* todo: panic if min/max values aren't fulfilled
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * [can't really happen unless there's a bug in the
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * CPU policy verififcation process *
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Power management hooks.  Note that we won't be called from IRQ context,
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unlike the blank functions above, so we may sleep.
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12933ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12953ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct sa1100fb_info *fbi = platform_get_drvdata(dev);
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12979480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King	set_ctrlr_state(fbi, C_DISABLE_PM);
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13013ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int sa1100fb_resume(struct platform_device *dev)
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13033ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct sa1100fb_info *fbi = platform_get_drvdata(dev);
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13059480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King	set_ctrlr_state(fbi, C_ENABLE_PM);
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sa1100fb_suspend	NULL
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sa1100fb_resume		NULL
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sa1100fb_map_video_memory():
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Allocates the DRAM memory for the frame buffer.  This buffer is
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	remapped into a non-cached, non-buffered, memory region to
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      allow palette and pixel writes to occur without flushing the
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      cache.  Once this area is remapped, all virtual memory
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      access to the video memory should occur at the new region.
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We reserve one page for the palette, plus the size
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * of the framebuffer.
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					      &fbi->map_dma, GFP_KERNEL);
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fbi->map_cpu) {
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME: this is actually the wrong thing to place in
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * smem_start.  But fbdev suffers from the problem that
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it needs an API which doesn't exist (in this case,
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * dma_writecombine_mmap)
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fbi->fb.fix.smem_start = fbi->screen_dma;
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fbi->map_cpu ? 0 : -ENOMEM;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Fake monspecs to fill in fbinfo structure */
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fb_monspecs monspecs __initdata = {
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hfmin	= 30000,
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hfmax	= 70000,
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vfmin	= 50,
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.vfmax	= 65,
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_mach_info *inf;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      GFP_KERNEL);
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!fbi)
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(fbi, 0, sizeof(struct sa1100fb_info));
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->dev = dev;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(fbi->fb.fix.id, SA1100_NAME);
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.type_aux	= 0;
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.xpanstep	= 0;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.ypanstep	= 0;
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.ywrapstep	= 0;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.accel	= FB_ACCEL_NONE;
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.nonstd	= 0;
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.activate	= FB_ACTIVATE_NOW;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.height	= -1;
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.width	= -1;
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.accel_flags	= 0;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fbops		= &sa1100fb_ops;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.flags		= FBINFO_DEFAULT;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.monspecs	= monspecs;
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.pseudo_palette	= (fbi + 1);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13890a4534801468325fdb6a7b7bf73ad2a958a1e379Michal Januszewski	fbi->rgb[RGB_4]		= &rgb_4;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->rgb[RGB_8]		= &rgb_8;
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->rgb[RGB_16]	= &def_rgb_16;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inf = sa1100fb_get_machine_info(fbi);
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * People just don't seem to get this.  We don't support
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * anything but correct entries now, so panic if someone
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * does something stupid.
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    inf->pixclock == 0)
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		panic("sa1100fb error: invalid LCCR3 fields set or zero "
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"pixclock.");
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->max_xres			= inf->xres;
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.xres		= inf->xres;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.xres_virtual	= inf->xres;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->max_yres			= inf->yres;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.yres		= inf->yres;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.yres_virtual	= inf->yres;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->max_bpp			= inf->bpp;
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.bits_per_pixel	= inf->bpp;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.pixclock		= inf->pixclock;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.hsync_len		= inf->hsync_len;
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.left_margin		= inf->left_margin;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.right_margin	= inf->right_margin;
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.vsync_len		= inf->vsync_len;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.upper_margin	= inf->upper_margin;
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.lower_margin	= inf->lower_margin;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.sync		= inf->sync;
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.var.grayscale		= inf->cmap_greyscale;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->cmap_inverse		= inf->cmap_inverse;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->cmap_static		= inf->cmap_static;
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->lccr0			= inf->lccr0;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->lccr3			= inf->lccr3;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->state			= C_STARTUP;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->task_state			= (u_char)-1;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  fbi->max_bpp / 8;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_waitqueue_head(&fbi->ctrlr_wait);
14322343217fb770ef2b172a12186c0cd0526bfb7d0cPavel Machek	INIT_WORK(&fbi->task, sa1100fb_task);
14337951ac91c7d45b61f54f1cdabc24b52b40785de6Matthias Kaehlcke	mutex_init(&fbi->ctrlr_lock);
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return fbi;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1438c2e13037e6794bd0d9de3f9ecabf5615f15c160bUwe Kleine-Königstatic int __devinit sa1100fb_probe(struct platform_device *pdev)
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sa1100fb_info *fbi;
1441e9368f8288338c25d8a339c91b15e17ebf33752dRussell King	int ret, irq;
1442e9368f8288338c25d8a339c91b15e17ebf33752dRussell King
1443e9368f8288338c25d8a339c91b15e17ebf33752dRussell King	irq = platform_get_irq(pdev, 0);
1444489447380a2921ec0e9154f773c44ab3167ede4bDavid Vrabel	if (irq < 0)
1445e9368f8288338c25d8a339c91b15e17ebf33752dRussell King		return -EINVAL;
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14503ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	fbi = sa1100fb_init_fbinfo(&pdev->dev);
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = -ENOMEM;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!fbi)
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize video memory */
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = sa1100fb_map_video_memory(fbi);
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1460f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang	ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef ASSABET_PAL_VIDEO
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (machine_is_assabet())
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This makes sure that our colour bitfield
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * descriptors are correctly initialised.
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14773ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(pdev, fbi);
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = register_framebuffer(&fbi->fb);
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
1481e9368f8288338c25d8a339c91b15e17ebf33752dRussell King		goto err_free_irq;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_FREQ
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This driver cannot be unloaded at the moment */
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1493e9368f8288338c25d8a339c91b15e17ebf33752dRussell King err_free_irq:
1494e9368f8288338c25d8a339c91b15e17ebf33752dRussell King	free_irq(irq, fbi);
1495e9368f8288338c25d8a339c91b15e17ebf33752dRussell King failed:
14963ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(pdev, NULL);
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(fbi);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_mem_region(0xb0100000, 0x10000);
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15023ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver sa1100fb_driver = {
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= sa1100fb_probe,
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.suspend	= sa1100fb_suspend,
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.resume		= sa1100fb_resume,
15063ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
15073ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= "sa11x0-fb",
15083ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init sa1100fb_init(void)
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fb_get_options("sa1100fb", NULL))
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15163ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	return platform_driver_register(&sa1100fb_driver);
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init sa1100fb_setup(char *options)
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *this_opt;
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!options || !*options)
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((this_opt = strsep(&options, ",")) != NULL) {
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(this_opt, "bpp:", 4))
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_par.max_bpp =
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    simple_strtoul(this_opt + 4, NULL, 0);
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(this_opt, "lccr0:", 6))
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lcd_shadow.lccr0 =
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    simple_strtoul(this_opt + 6, NULL, 0);
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(this_opt, "lccr1:", 6)) {
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lcd_shadow.lccr1 =
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    simple_strtoul(this_opt + 6, NULL, 0);
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_par.max_xres =
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (lcd_shadow.lccr1 & 0x3ff) + 16;
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(this_opt, "lccr2:", 6)) {
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lcd_shadow.lccr2 =
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    simple_strtoul(this_opt + 6, NULL, 0);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			current_par.max_yres =
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (lcd_shadow.
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     lccr0 & LCCR0_SDS) ? ((lcd_shadow.
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						    lccr2 & 0x3ff) +
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   1) *
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(this_opt, "lccr3:", 6))
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lcd_shadow.lccr3 =
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    simple_strtoul(this_opt + 6, NULL, 0);
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sa1100fb_init);
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1563