brintos

brintos / linux-shallow public Read only

0
0
Text · 34.5 KiB · 0d362d2 Raw
1229 lines · c
1/*2 *  linux/drivers/video/sa1100fb.c3 *4 *  Copyright (C) 1999 Eric A. Thomas5 *   Based on acornfb.c Copyright (C) Russell King.6 *7 * This file is subject to the terms and conditions of the GNU General Public8 * License.  See the file COPYING in the main directory of this archive for9 * more details.10 *11 *	        StrongARM 1100 LCD Controller Frame Buffer Driver12 *13 * Please direct your questions and comments on this driver to the following14 * email address:15 *16 *	linux-arm-kernel@lists.arm.linux.org.uk17 *18 * Clean patches should be sent to the ARM Linux Patch System.  Please see the19 * following web page for more information:20 *21 *	https://www.arm.linux.org.uk/developer/patches/info.shtml22 *23 * Thank you.24 *25 * Known problems:26 *	- With the Neponset plugged into an Assabet, LCD powerdown27 *	  doesn't work (LCD stays powered up).  Therefore we shouldn't28 *	  blank the screen.29 *	- We don't limit the CPU clock rate nor the mode selection30 *	  according to the available SDRAM bandwidth.31 *32 * Other notes:33 *	- Linear grayscale palettes and the kernel.34 *	  Such code does not belong in the kernel.  The kernel frame buffer35 *	  drivers do not expect a linear colourmap, but a colourmap based on36 *	  the VT100 standard mapping.37 *38 *	  If your _userspace_ requires a linear colourmap, then the setup of39 *	  such a colourmap belongs _in userspace_, not in the kernel.  Code40 *	  to set the colourmap correctly from user space has been sent to41 *	  David Neuer.  It's around 8 lines of C code, plus another 4 to42 *	  detect if we are using grayscale.43 *44 *	- The following must never be specified in a panel definition:45 *	     LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL46 *47 *	- The following should be specified:48 *	     either LCCR0_Color or LCCR0_Mono49 *	     either LCCR0_Sngl or LCCR0_Dual50 *	     either LCCR0_Act or LCCR0_Pas51 *	     either LCCR3_OutEnH or LCCD3_OutEnL52 *	     either LCCR3_PixRsEdg or LCCR3_PixFlEdg53 *	     either LCCR3_ACBsDiv or LCCR3_ACBsCntOff54 *55 * Code Status:56 * 1999/04/01:57 *	- Driver appears to be working for Brutus 320x200x8bpp mode.  Other58 *	  resolutions are working, but only the 8bpp mode is supported.59 *	  Changes need to be made to the palette encode and decode routines60 *	  to support 4 and 16 bpp modes.61 *	  Driver is not designed to be a module.  The FrameBuffer is statically62 *	  allocated since dynamic allocation of a 300k buffer cannot be63 *	  guaranteed.64 *65 * 1999/06/17:66 *	- FrameBuffer memory is now allocated at run-time when the67 *	  driver is initialized.68 *69 * 2000/04/10: Nicolas Pitre <nico@fluxnic.net>70 *	- Big cleanup for dynamic selection of machine type at run time.71 *72 * 2000/07/19: Jamey Hicks <jamey@crl.dec.com>73 *	- Support for Bitsy aka Compaq iPAQ H3600 added.74 *75 * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com>76 *	       Jeff Sutherland <jsutherland@accelent.com>77 *	- Resolved an issue caused by a change made to the Assabet's PLD78 *	  earlier this year which broke the framebuffer driver for newer79 *	  Phase 4 Assabets.  Some other parameters were changed to optimize80 *	  for the Sharp display.81 *82 * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp>83 *	- XP860 support added84 *85 * 2000/08/19: Mark Huang <mhuang@livetoy.com>86 *	- Allows standard options to be passed on the kernel command line87 *	  for most common passive displays.88 *89 * 2000/08/29:90 *	- s/save_flags_cli/local_irq_save/91 *	- remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller92 *93 * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>94 *	- Updated LART stuff. Fixed some minor bugs.95 *96 * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw>97 *	- Pangolin support added98 *99 * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de>100 *	- Huw Webpanel support added101 *102 * 2000/11/23: Eric Peng <ericpeng@coventive.com>103 *	- Freebird add104 *105 * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com>106 *	       Cliff Brake <cbrake@accelent.com>107 *	- Added PM callback108 *109 * 2001/05/26: <rmk@arm.linux.org.uk>110 *	- Fix 16bpp so that (a) we use the right colours rather than some111 *	  totally random colour depending on what was in page 0, and (b)112 *	  we don't de-reference a NULL pointer.113 *	- remove duplicated implementation of consistent_alloc()114 *	- convert dma address types to dma_addr_t115 *	- remove unused 'montype' stuff116 *	- remove redundant zero inits of init_var after the initial117 *	  memset.118 *	- remove allow_modeset (acornfb idea does not belong here)119 *120 * 2001/05/28: <rmk@arm.linux.org.uk>121 *	- massive cleanup - move machine dependent data into structures122 *	- I've left various #warnings in - if you see one, and know123 *	  the hardware concerned, please get in contact with me.124 *125 * 2001/05/31: <rmk@arm.linux.org.uk>126 *	- Fix LCCR1 HSW value, fix all machine type specifications to127 *	  keep values in line.  (Please check your machine type specs)128 *129 * 2001/06/10: <rmk@arm.linux.org.uk>130 *	- Fiddle with the LCD controller from task context only; mainly131 *	  so that we can run with interrupts on, and sleep.132 *	- Convert #warnings into #errors.  No pain, no gain. ;)133 *134 * 2001/06/14: <rmk@arm.linux.org.uk>135 *	- Make the palette BPS value for 12bpp come out correctly.136 *	- Take notice of "greyscale" on any colour depth.137 *	- Make truecolor visuals use the RGB channel encoding information.138 *139 * 2001/07/02: <rmk@arm.linux.org.uk>140 *	- Fix colourmap problems.141 *142 * 2001/07/13: <abraham@2d3d.co.za>143 *	- Added support for the ICP LCD-Kit01 on LART. This LCD is144 *	  manufactured by Prime View, model no V16C6448AB145 *146 * 2001/07/23: <rmk@arm.linux.org.uk>147 *	- Hand merge version from handhelds.org CVS tree.  See patch148 *	  notes for 595/1 for more information.149 *	- Drop 12bpp (it's 16bpp with different colour register mappings).150 *	- This hardware can not do direct colour.  Therefore we don't151 *	  support it.152 *153 * 2001/07/27: <rmk@arm.linux.org.uk>154 *	- Halve YRES on dual scan LCDs.155 *156 * 2001/08/22: <rmk@arm.linux.org.uk>157 *	- Add b/w iPAQ pixclock value.158 *159 * 2001/10/12: <rmk@arm.linux.org.uk>160 *	- Add patch 681/1 and clean up stork definitions.161 */162 163#include <linux/module.h>164#include <linux/kernel.h>165#include <linux/sched.h>166#include <linux/errno.h>167#include <linux/string.h>168#include <linux/interrupt.h>169#include <linux/slab.h>170#include <linux/mm.h>171#include <linux/fb.h>172#include <linux/delay.h>173#include <linux/init.h>174#include <linux/ioport.h>175#include <linux/cpufreq.h>176#include <linux/gpio/consumer.h>177#include <linux/platform_device.h>178#include <linux/dma-mapping.h>179#include <linux/mutex.h>180#include <linux/io.h>181#include <linux/clk.h>182 183#include <video/sa1100fb.h>184 185#include <mach/hardware.h>186#include <asm/mach-types.h>187 188/*189 * Complain if VAR is out of range.190 */191#define DEBUG_VAR 1192 193#include "sa1100fb.h"194 195static const struct sa1100fb_rgb rgb_4 = {196	.red	= { .offset = 0,  .length = 4, },197	.green	= { .offset = 0,  .length = 4, },198	.blue	= { .offset = 0,  .length = 4, },199	.transp	= { .offset = 0,  .length = 0, },200};201 202static const struct sa1100fb_rgb rgb_8 = {203	.red	= { .offset = 0,  .length = 8, },204	.green	= { .offset = 0,  .length = 8, },205	.blue	= { .offset = 0,  .length = 8, },206	.transp	= { .offset = 0,  .length = 0, },207};208 209static const struct sa1100fb_rgb def_rgb_16 = {210	.red	= { .offset = 11, .length = 5, },211	.green	= { .offset = 5,  .length = 6, },212	.blue	= { .offset = 0,  .length = 5, },213	.transp	= { .offset = 0,  .length = 0, },214};215 216 217 218static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);219static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);220 221static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state)222{223	unsigned long flags;224 225	local_irq_save(flags);226	/*227	 * We need to handle two requests being made at the same time.228	 * There are two important cases:229	 *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)230	 *     We must perform the unblanking, which will do our REENABLE for us.231	 *  2. When we are blanking, but immediately unblank before we have232	 *     blanked.  We do the "REENABLE" thing here as well, just to be sure.233	 */234	if (fbi->task_state == C_ENABLE && state == C_REENABLE)235		state = (u_int) -1;236	if (fbi->task_state == C_DISABLE && state == C_ENABLE)237		state = C_REENABLE;238 239	if (state != (u_int)-1) {240		fbi->task_state = state;241		schedule_work(&fbi->task);242	}243	local_irq_restore(flags);244}245 246static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)247{248	chan &= 0xffff;249	chan >>= 16 - bf->length;250	return chan << bf->offset;251}252 253/*254 * Convert bits-per-pixel to a hardware palette PBS value.255 */256static inline u_int palette_pbs(struct fb_var_screeninfo *var)257{258	int ret = 0;259	switch (var->bits_per_pixel) {260	case 4:  ret = 0 << 12;	break;261	case 8:  ret = 1 << 12; break;262	case 16: ret = 2 << 12; break;263	}264	return ret;265}266 267static int268sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,269		       u_int trans, struct fb_info *info)270{271	struct sa1100fb_info *fbi =272		container_of(info, struct sa1100fb_info, fb);273	u_int val, ret = 1;274 275	if (regno < fbi->palette_size) {276		val = ((red >> 4) & 0xf00);277		val |= ((green >> 8) & 0x0f0);278		val |= ((blue >> 12) & 0x00f);279 280		if (regno == 0)281			val |= palette_pbs(&fbi->fb.var);282 283		fbi->palette_cpu[regno] = val;284		ret = 0;285	}286	return ret;287}288 289static int290sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,291		   u_int trans, struct fb_info *info)292{293	struct sa1100fb_info *fbi =294		container_of(info, struct sa1100fb_info, fb);295	unsigned int val;296	int ret = 1;297 298	/*299	 * If inverse mode was selected, invert all the colours300	 * rather than the register number.  The register number301	 * is what you poke into the framebuffer to produce the302	 * colour you requested.303	 */304	if (fbi->inf->cmap_inverse) {305		red   = 0xffff - red;306		green = 0xffff - green;307		blue  = 0xffff - blue;308	}309 310	/*311	 * If greyscale is true, then we convert the RGB value312	 * to greyscale no mater what visual we are using.313	 */314	if (fbi->fb.var.grayscale)315		red = green = blue = (19595 * red + 38470 * green +316					7471 * blue) >> 16;317 318	switch (fbi->fb.fix.visual) {319	case FB_VISUAL_TRUECOLOR:320		/*321		 * 12 or 16-bit True Colour.  We encode the RGB value322		 * according to the RGB bitfield information.323		 */324		if (regno < 16) {325			val  = chan_to_field(red, &fbi->fb.var.red);326			val |= chan_to_field(green, &fbi->fb.var.green);327			val |= chan_to_field(blue, &fbi->fb.var.blue);328 329			fbi->pseudo_palette[regno] = val;330			ret = 0;331		}332		break;333 334	case FB_VISUAL_STATIC_PSEUDOCOLOR:335	case FB_VISUAL_PSEUDOCOLOR:336		ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);337		break;338	}339 340	return ret;341}342 343#ifdef CONFIG_CPU_FREQ344/*345 *  sa1100fb_display_dma_period()346 *    Calculate the minimum period (in picoseconds) between two DMA347 *    requests for the LCD controller.  If we hit this, it means we're348 *    doing nothing but LCD DMA.349 */350static inline unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)351{352	/*353	 * Period = pixclock * bits_per_byte * bytes_per_transfer354	 *		/ memory_bits_per_pixel;355	 */356	return var->pixclock * 8 * 16 / var->bits_per_pixel;357}358#endif359 360/*361 *  sa1100fb_check_var():362 *    Round up in the following order: bits_per_pixel, xres,363 *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,364 *    bitfields, horizontal timing, vertical timing.365 */366static int367sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)368{369	struct sa1100fb_info *fbi =370		container_of(info, struct sa1100fb_info, fb);371	int rgbidx;372 373	if (var->xres < MIN_XRES)374		var->xres = MIN_XRES;375	if (var->yres < MIN_YRES)376		var->yres = MIN_YRES;377	if (var->xres > fbi->inf->xres)378		var->xres = fbi->inf->xres;379	if (var->yres > fbi->inf->yres)380		var->yres = fbi->inf->yres;381	var->xres_virtual = max(var->xres_virtual, var->xres);382	var->yres_virtual = max(var->yres_virtual, var->yres);383 384	dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);385	switch (var->bits_per_pixel) {386	case 4:387		rgbidx = RGB_4;388		break;389	case 8:390		rgbidx = RGB_8;391		break;392	case 16:393		rgbidx = RGB_16;394		break;395	default:396		return -EINVAL;397	}398 399	/*400	 * Copy the RGB parameters for this display401	 * from the machine specific parameters.402	 */403	var->red    = fbi->rgb[rgbidx]->red;404	var->green  = fbi->rgb[rgbidx]->green;405	var->blue   = fbi->rgb[rgbidx]->blue;406	var->transp = fbi->rgb[rgbidx]->transp;407 408	dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",409		var->red.length, var->green.length, var->blue.length,410		var->transp.length);411 412	dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",413		var->red.offset, var->green.offset, var->blue.offset,414		var->transp.offset);415 416#ifdef CONFIG_CPU_FREQ417	dev_dbg(fbi->dev, "dma period = %d ps, clock = %ld kHz\n",418		sa1100fb_display_dma_period(var),419		clk_get_rate(fbi->clk) / 1000);420#endif421 422	return 0;423}424 425static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)426{427	if (fbi->inf->set_visual)428		fbi->inf->set_visual(visual);429}430 431/*432 * sa1100fb_set_par():433 *	Set the user defined part of the display for the specified console434 */435static int sa1100fb_set_par(struct fb_info *info)436{437	struct sa1100fb_info *fbi =438		container_of(info, struct sa1100fb_info, fb);439	struct fb_var_screeninfo *var = &info->var;440	unsigned long palette_mem_size;441 442	dev_dbg(fbi->dev, "set_par\n");443 444	if (var->bits_per_pixel == 16)445		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;446	else if (!fbi->inf->cmap_static)447		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;448	else {449		/*450		 * Some people have weird ideas about wanting static451		 * pseudocolor maps.  I suspect their user space452		 * applications are broken.453		 */454		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;455	}456 457	fbi->fb.fix.line_length = var->xres_virtual *458				  var->bits_per_pixel / 8;459	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;460 461	palette_mem_size = fbi->palette_size * sizeof(u16);462 463	dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);464 465	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);466	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;467 468	/*469	 * Set (any) board control register to handle new color depth470	 */471	sa1100fb_set_visual(fbi, fbi->fb.fix.visual);472	sa1100fb_activate_var(var, fbi);473 474	return 0;475}476 477#if 0478static int479sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,480		  struct fb_info *info)481{482	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;483 484	/*485	 * Make sure the user isn't doing something stupid.486	 */487	if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))488		return -EINVAL;489 490	return gen_set_cmap(cmap, kspc, con, info);491}492#endif493 494/*495 * Formal definition of the VESA spec:496 *  On497 *  	This refers to the state of the display when it is in full operation498 *  Stand-By499 *  	This defines an optional operating state of minimal power reduction with500 *  	the shortest recovery time501 *  Suspend502 *  	This refers to a level of power management in which substantial power503 *  	reduction is achieved by the display.  The display can have a longer504 *  	recovery time from this state than from the Stand-by state505 *  Off506 *  	This indicates that the display is consuming the lowest level of power507 *  	and is non-operational. Recovery from this state may optionally require508 *  	the user to manually power on the monitor509 *510 *  Now, the fbdev driver adds an additional state, (blank), where they511 *  turn off the video (maybe by colormap tricks), but don't mess with the512 *  video itself: think of it semantically between on and Stand-By.513 *514 *  So here's what we should do in our fbdev blank routine:515 *516 *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on517 *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off518 *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off519 *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off520 *521 *  This will match the matrox implementation.522 */523/*524 * sa1100fb_blank():525 *	Blank the display by setting all palette values to zero.  Note, the526 * 	12 and 16 bpp modes don't really use the palette, so this will not527 *      blank the display in all modes.528 */529static int sa1100fb_blank(int blank, struct fb_info *info)530{531	struct sa1100fb_info *fbi =532		container_of(info, struct sa1100fb_info, fb);533	int i;534 535	dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);536 537	switch (blank) {538	case FB_BLANK_POWERDOWN:539	case FB_BLANK_VSYNC_SUSPEND:540	case FB_BLANK_HSYNC_SUSPEND:541	case FB_BLANK_NORMAL:542		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||543		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)544			for (i = 0; i < fbi->palette_size; i++)545				sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);546		sa1100fb_schedule_work(fbi, C_DISABLE);547		break;548 549	case FB_BLANK_UNBLANK:550		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||551		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)552			fb_set_cmap(&fbi->fb.cmap, info);553		sa1100fb_schedule_work(fbi, C_ENABLE);554	}555	return 0;556}557 558static int sa1100fb_mmap(struct fb_info *info,559			 struct vm_area_struct *vma)560{561	struct sa1100fb_info *fbi =562		container_of(info, struct sa1100fb_info, fb);563	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;564 565	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);566 567	if (off < info->fix.smem_len) {568		vma->vm_pgoff += 1; /* skip over the palette */569		return dma_mmap_wc(fbi->dev, vma, fbi->map_cpu, fbi->map_dma,570				   fbi->map_size);571	}572 573	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);574 575	return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len);576}577 578static const struct fb_ops sa1100fb_ops = {579	.owner		= THIS_MODULE,580	__FB_DEFAULT_IOMEM_OPS_RDWR,581	.fb_check_var	= sa1100fb_check_var,582	.fb_set_par	= sa1100fb_set_par,583//	.fb_set_cmap	= sa1100fb_set_cmap,584	.fb_setcolreg	= sa1100fb_setcolreg,585	.fb_blank	= sa1100fb_blank,586	__FB_DEFAULT_IOMEM_OPS_DRAW,587	.fb_mmap	= sa1100fb_mmap,588};589 590/*591 * Calculate the PCD value from the clock rate (in picoseconds).592 * We take account of the PPCR clock setting.593 */594static inline unsigned int get_pcd(struct sa1100fb_info *fbi,595		unsigned int pixclock)596{597	unsigned int pcd = clk_get_rate(fbi->clk) / 100 / 1000;598 599	pcd *= pixclock;600	pcd /= 10000000;601 602	return pcd + 1;	/* make up for integer math truncations */603}604 605/*606 * sa1100fb_activate_var():607 *	Configures LCD Controller based on entries in var parameter.  Settings are608 *	only written to the controller if changes were made.609 */610static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)611{612	struct sa1100fb_lcd_reg new_regs;613	u_int half_screen_size, yres, pcd;614	u_long flags;615 616	dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");617 618	dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",619		var->xres, var->hsync_len,620		var->left_margin, var->right_margin);621	dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",622		var->yres, var->vsync_len,623		var->upper_margin, var->lower_margin);624 625#if DEBUG_VAR626	if (var->xres < 16        || var->xres > 1024)627		dev_err(fbi->dev, "%s: invalid xres %d\n",628			fbi->fb.fix.id, var->xres);629	if (var->hsync_len < 1    || var->hsync_len > 64)630		dev_err(fbi->dev, "%s: invalid hsync_len %d\n",631			fbi->fb.fix.id, var->hsync_len);632	if (var->left_margin < 1  || var->left_margin > 255)633		dev_err(fbi->dev, "%s: invalid left_margin %d\n",634			fbi->fb.fix.id, var->left_margin);635	if (var->right_margin < 1 || var->right_margin > 255)636		dev_err(fbi->dev, "%s: invalid right_margin %d\n",637			fbi->fb.fix.id, var->right_margin);638	if (var->yres < 1         || var->yres > 1024)639		dev_err(fbi->dev, "%s: invalid yres %d\n",640			fbi->fb.fix.id, var->yres);641	if (var->vsync_len < 1    || var->vsync_len > 64)642		dev_err(fbi->dev, "%s: invalid vsync_len %d\n",643			fbi->fb.fix.id, var->vsync_len);644	if (var->upper_margin < 0 || var->upper_margin > 255)645		dev_err(fbi->dev, "%s: invalid upper_margin %d\n",646			fbi->fb.fix.id, var->upper_margin);647	if (var->lower_margin < 0 || var->lower_margin > 255)648		dev_err(fbi->dev, "%s: invalid lower_margin %d\n",649			fbi->fb.fix.id, var->lower_margin);650#endif651 652	new_regs.lccr0 = fbi->inf->lccr0 |653		LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |654		LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);655 656	new_regs.lccr1 =657		LCCR1_DisWdth(var->xres) +658		LCCR1_HorSnchWdth(var->hsync_len) +659		LCCR1_BegLnDel(var->left_margin) +660		LCCR1_EndLnDel(var->right_margin);661 662	/*663	 * If we have a dual scan LCD, then we need to halve664	 * the YRES parameter.665	 */666	yres = var->yres;667	if (fbi->inf->lccr0 & LCCR0_Dual)668		yres /= 2;669 670	new_regs.lccr2 =671		LCCR2_DisHght(yres) +672		LCCR2_VrtSnchWdth(var->vsync_len) +673		LCCR2_BegFrmDel(var->upper_margin) +674		LCCR2_EndFrmDel(var->lower_margin);675 676	pcd = get_pcd(fbi, var->pixclock);677	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |678		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |679		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);680 681	dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);682	dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);683	dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);684	dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);685 686	half_screen_size = var->bits_per_pixel;687	half_screen_size = half_screen_size * var->xres * var->yres / 16;688 689	/* Update shadow copy atomically */690	local_irq_save(flags);691	fbi->dbar1 = fbi->palette_dma;692	fbi->dbar2 = fbi->screen_dma + half_screen_size;693 694	fbi->reg_lccr0 = new_regs.lccr0;695	fbi->reg_lccr1 = new_regs.lccr1;696	fbi->reg_lccr2 = new_regs.lccr2;697	fbi->reg_lccr3 = new_regs.lccr3;698	local_irq_restore(flags);699 700	/*701	 * Only update the registers if the controller is enabled702	 * and something has changed.703	 */704	if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||705	    readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||706	    readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||707	    readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||708	    readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||709	    readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)710		sa1100fb_schedule_work(fbi, C_REENABLE);711 712	return 0;713}714 715/*716 * NOTE!  The following functions are purely helpers for set_ctrlr_state.717 * Do not call them directly; set_ctrlr_state does the correct serialisation718 * to ensure that things happen in the right way 100% of time time.719 *	-- rmk720 */721static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)722{723	dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");724 725	if (fbi->inf->backlight_power)726		fbi->inf->backlight_power(on);727}728 729static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)730{731	dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");732 733	if (fbi->inf->lcd_power)734		fbi->inf->lcd_power(on);735}736 737static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)738{739	u_int mask = 0;740 741	/*742	 * Enable GPIO<9:2> for LCD use if:743	 *  1. Active display, or744	 *  2. Color Dual Passive display745	 *746	 * see table 11.8 on page 11-27 in the SA1100 manual747	 *   -- Erik.748	 *749	 * SA1110 spec update nr. 25 says we can and should750	 * clear LDD15 to 12 for 4 or 8bpp modes with active751	 * panels.752	 */753	if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&754	    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {755		mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;756 757		if (fbi->fb.var.bits_per_pixel > 8 ||758		    (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)759			mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;760 761	}762 763	if (mask) {764		unsigned long flags;765 766		/*767		 * SA-1100 requires the GPIO direction register set768		 * appropriately for the alternate function.  Hence769		 * we set it here via bitmask rather than excessive770		 * fiddling via the GPIO subsystem - and even then771		 * we'll still have to deal with GAFR.772		 */773		local_irq_save(flags);774		GPDR |= mask;775		GAFR |= mask;776		local_irq_restore(flags);777	}778}779 780static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)781{782	dev_dbg(fbi->dev, "Enabling LCD controller\n");783 784	/*785	 * Make sure the mode bits are present in the first palette entry786	 */787	fbi->palette_cpu[0] &= 0xcfff;788	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);789 790	/* enable LCD controller clock */791	clk_prepare_enable(fbi->clk);792 793	/* Sequence from 11.7.10 */794	writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);795	writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);796	writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);797	writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);798	writel_relaxed(fbi->dbar1, fbi->base + DBAR1);799	writel_relaxed(fbi->dbar2, fbi->base + DBAR2);800	writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);801 802	if (fbi->shannon_lcden)803		gpiod_set_value(fbi->shannon_lcden, 1);804 805	dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));806	dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));807	dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));808	dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));809	dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));810	dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));811}812 813static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)814{815	DECLARE_WAITQUEUE(wait, current);816	u32 lccr0;817 818	dev_dbg(fbi->dev, "Disabling LCD controller\n");819 820	if (fbi->shannon_lcden)821		gpiod_set_value(fbi->shannon_lcden, 0);822 823	set_current_state(TASK_UNINTERRUPTIBLE);824	add_wait_queue(&fbi->ctrlr_wait, &wait);825 826	/* Clear LCD Status Register */827	writel_relaxed(~0, fbi->base + LCSR);828 829	lccr0 = readl_relaxed(fbi->base + LCCR0);830	lccr0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */831	writel_relaxed(lccr0, fbi->base + LCCR0);832	lccr0 &= ~LCCR0_LEN;	/* Disable LCD Controller */833	writel_relaxed(lccr0, fbi->base + LCCR0);834 835	schedule_timeout(20 * HZ / 1000);836	remove_wait_queue(&fbi->ctrlr_wait, &wait);837 838	/* disable LCD controller clock */839	clk_disable_unprepare(fbi->clk);840}841 842/*843 *  sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.844 */845static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)846{847	struct sa1100fb_info *fbi = dev_id;848	unsigned int lcsr = readl_relaxed(fbi->base + LCSR);849 850	if (lcsr & LCSR_LDD) {851		u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;852		writel_relaxed(lccr0, fbi->base + LCCR0);853		wake_up(&fbi->ctrlr_wait);854	}855 856	writel_relaxed(lcsr, fbi->base + LCSR);857	return IRQ_HANDLED;858}859 860/*861 * This function must be called from task context only, since it will862 * sleep when disabling the LCD controller, or if we get two contending863 * processes trying to alter state.864 */865static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)866{867	u_int old_state;868 869	mutex_lock(&fbi->ctrlr_lock);870 871	old_state = fbi->state;872 873	/*874	 * Hack around fbcon initialisation.875	 */876	if (old_state == C_STARTUP && state == C_REENABLE)877		state = C_ENABLE;878 879	switch (state) {880	case C_DISABLE_CLKCHANGE:881		/*882		 * Disable controller for clock change.  If the883		 * controller is already disabled, then do nothing.884		 */885		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {886			fbi->state = state;887			sa1100fb_disable_controller(fbi);888		}889		break;890 891	case C_DISABLE_PM:892	case C_DISABLE:893		/*894		 * Disable controller895		 */896		if (old_state != C_DISABLE) {897			fbi->state = state;898 899			__sa1100fb_backlight_power(fbi, 0);900			if (old_state != C_DISABLE_CLKCHANGE)901				sa1100fb_disable_controller(fbi);902			__sa1100fb_lcd_power(fbi, 0);903		}904		break;905 906	case C_ENABLE_CLKCHANGE:907		/*908		 * Enable the controller after clock change.  Only909		 * do this if we were disabled for the clock change.910		 */911		if (old_state == C_DISABLE_CLKCHANGE) {912			fbi->state = C_ENABLE;913			sa1100fb_enable_controller(fbi);914		}915		break;916 917	case C_REENABLE:918		/*919		 * Re-enable the controller only if it was already920		 * enabled.  This is so we reprogram the control921		 * registers.922		 */923		if (old_state == C_ENABLE) {924			sa1100fb_disable_controller(fbi);925			sa1100fb_setup_gpio(fbi);926			sa1100fb_enable_controller(fbi);927		}928		break;929 930	case C_ENABLE_PM:931		/*932		 * Re-enable the controller after PM.  This is not933		 * perfect - think about the case where we were doing934		 * a clock change, and we suspended half-way through.935		 */936		if (old_state != C_DISABLE_PM)937			break;938		fallthrough;939 940	case C_ENABLE:941		/*942		 * Power up the LCD screen, enable controller, and943		 * turn on the backlight.944		 */945		if (old_state != C_ENABLE) {946			fbi->state = C_ENABLE;947			sa1100fb_setup_gpio(fbi);948			__sa1100fb_lcd_power(fbi, 1);949			sa1100fb_enable_controller(fbi);950			__sa1100fb_backlight_power(fbi, 1);951		}952		break;953	}954	mutex_unlock(&fbi->ctrlr_lock);955}956 957/*958 * Our LCD controller task (which is called when we blank or unblank)959 * via keventd.960 */961static void sa1100fb_task(struct work_struct *w)962{963	struct sa1100fb_info *fbi = container_of(w, struct sa1100fb_info, task);964	u_int state = xchg(&fbi->task_state, -1);965 966	set_ctrlr_state(fbi, state);967}968 969#ifdef CONFIG_CPU_FREQ970/*971 * CPU clock speed change handler.  We need to adjust the LCD timing972 * parameters when the CPU clock is adjusted by the power management973 * subsystem.974 */975static int976sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,977			 void *data)978{979	struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);980	u_int pcd;981 982	switch (val) {983	case CPUFREQ_PRECHANGE:984		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);985		break;986 987	case CPUFREQ_POSTCHANGE:988		pcd = get_pcd(fbi, fbi->fb.var.pixclock);989		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);990		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);991		break;992	}993	return 0;994}995#endif996 997#ifdef CONFIG_PM998/*999 * Power management hooks.  Note that we won't be called from IRQ context,1000 * unlike the blank functions above, so we may sleep.1001 */1002static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state)1003{1004	struct sa1100fb_info *fbi = platform_get_drvdata(dev);1005 1006	set_ctrlr_state(fbi, C_DISABLE_PM);1007	return 0;1008}1009 1010static int sa1100fb_resume(struct platform_device *dev)1011{1012	struct sa1100fb_info *fbi = platform_get_drvdata(dev);1013 1014	set_ctrlr_state(fbi, C_ENABLE_PM);1015	return 0;1016}1017#else1018#define sa1100fb_suspend	NULL1019#define sa1100fb_resume		NULL1020#endif1021 1022/*1023 * sa1100fb_map_video_memory():1024 *      Allocates the DRAM memory for the frame buffer.  This buffer is1025 *	remapped into a non-cached, non-buffered, memory region to1026 *      allow palette and pixel writes to occur without flushing the1027 *      cache.  Once this area is remapped, all virtual memory1028 *      access to the video memory should occur at the new region.1029 */1030static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)1031{1032	/*1033	 * We reserve one page for the palette, plus the size1034	 * of the framebuffer.1035	 */1036	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);1037	fbi->map_cpu = dma_alloc_wc(fbi->dev, fbi->map_size, &fbi->map_dma,1038				    GFP_KERNEL);1039 1040	if (fbi->map_cpu) {1041		fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;1042		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;1043		/*1044		 * FIXME: this is actually the wrong thing to place in1045		 * smem_start.  But fbdev suffers from the problem that1046		 * it needs an API which doesn't exist (in this case,1047		 * dma_writecombine_mmap)1048		 */1049		fbi->fb.fix.smem_start = fbi->screen_dma;1050	}1051 1052	return fbi->map_cpu ? 0 : -ENOMEM;1053}1054 1055/* Fake monspecs to fill in fbinfo structure */1056static const struct fb_monspecs monspecs = {1057	.hfmin	= 30000,1058	.hfmax	= 70000,1059	.vfmin	= 50,1060	.vfmax	= 65,1061};1062 1063 1064static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)1065{1066	struct sa1100fb_mach_info *inf = dev_get_platdata(dev);1067	struct sa1100fb_info *fbi;1068	unsigned i;1069 1070	fbi = devm_kzalloc(dev, sizeof(struct sa1100fb_info), GFP_KERNEL);1071	if (!fbi)1072		return NULL;1073 1074	fbi->dev = dev;1075 1076	strcpy(fbi->fb.fix.id, SA1100_NAME);1077 1078	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;1079	fbi->fb.fix.type_aux	= 0;1080	fbi->fb.fix.xpanstep	= 0;1081	fbi->fb.fix.ypanstep	= 0;1082	fbi->fb.fix.ywrapstep	= 0;1083	fbi->fb.fix.accel	= FB_ACCEL_NONE;1084 1085	fbi->fb.var.nonstd	= 0;1086	fbi->fb.var.activate	= FB_ACTIVATE_NOW;1087	fbi->fb.var.height	= -1;1088	fbi->fb.var.width	= -1;1089	fbi->fb.var.accel_flags	= 0;1090	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;1091 1092	fbi->fb.fbops		= &sa1100fb_ops;1093	fbi->fb.monspecs	= monspecs;1094	fbi->fb.pseudo_palette	= fbi->pseudo_palette;1095 1096	fbi->rgb[RGB_4]		= &rgb_4;1097	fbi->rgb[RGB_8]		= &rgb_8;1098	fbi->rgb[RGB_16]	= &def_rgb_16;1099 1100	/*1101	 * People just don't seem to get this.  We don't support1102	 * anything but correct entries now, so panic if someone1103	 * does something stupid.1104	 */1105	if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||1106	    inf->pixclock == 0)1107		panic("sa1100fb error: invalid LCCR3 fields set or zero "1108			"pixclock.");1109 1110	fbi->fb.var.xres		= inf->xres;1111	fbi->fb.var.xres_virtual	= inf->xres;1112	fbi->fb.var.yres		= inf->yres;1113	fbi->fb.var.yres_virtual	= inf->yres;1114	fbi->fb.var.bits_per_pixel	= inf->bpp;1115	fbi->fb.var.pixclock		= inf->pixclock;1116	fbi->fb.var.hsync_len		= inf->hsync_len;1117	fbi->fb.var.left_margin		= inf->left_margin;1118	fbi->fb.var.right_margin	= inf->right_margin;1119	fbi->fb.var.vsync_len		= inf->vsync_len;1120	fbi->fb.var.upper_margin	= inf->upper_margin;1121	fbi->fb.var.lower_margin	= inf->lower_margin;1122	fbi->fb.var.sync		= inf->sync;1123	fbi->fb.var.grayscale		= inf->cmap_greyscale;1124	fbi->state			= C_STARTUP;1125	fbi->task_state			= (u_char)-1;1126	fbi->fb.fix.smem_len		= inf->xres * inf->yres *1127					  inf->bpp / 8;1128	fbi->inf			= inf;1129 1130	/* Copy the RGB bitfield overrides */1131	for (i = 0; i < NR_RGB; i++)1132		if (inf->rgb[i])1133			fbi->rgb[i] = inf->rgb[i];1134 1135	init_waitqueue_head(&fbi->ctrlr_wait);1136	INIT_WORK(&fbi->task, sa1100fb_task);1137	mutex_init(&fbi->ctrlr_lock);1138 1139	return fbi;1140}1141 1142static int sa1100fb_probe(struct platform_device *pdev)1143{1144	struct sa1100fb_info *fbi;1145	int ret, irq;1146 1147	if (!dev_get_platdata(&pdev->dev)) {1148		dev_err(&pdev->dev, "no platform LCD data\n");1149		return -EINVAL;1150	}1151 1152	irq = platform_get_irq(pdev, 0);1153	if (irq < 0)1154		return -EINVAL;1155 1156	fbi = sa1100fb_init_fbinfo(&pdev->dev);1157	if (!fbi)1158		return -ENOMEM;1159 1160	fbi->base = devm_platform_ioremap_resource(pdev, 0);1161	if (IS_ERR(fbi->base))1162		return PTR_ERR(fbi->base);1163 1164	fbi->clk = devm_clk_get(&pdev->dev, NULL);1165	if (IS_ERR(fbi->clk))1166		return PTR_ERR(fbi->clk);1167 1168	ret = devm_request_irq(&pdev->dev, irq, sa1100fb_handle_irq, 0,1169			       "LCD", fbi);1170	if (ret) {1171		dev_err(&pdev->dev, "request_irq failed: %d\n", ret);1172		return ret;1173	}1174 1175	fbi->shannon_lcden = gpiod_get_optional(&pdev->dev, "shannon-lcden",1176						GPIOD_OUT_LOW);1177	if (IS_ERR(fbi->shannon_lcden))1178		return PTR_ERR(fbi->shannon_lcden);1179 1180	/* Initialize video memory */1181	ret = sa1100fb_map_video_memory(fbi);1182	if (ret)1183		return ret;1184 1185	/*1186	 * This makes sure that our colour bitfield1187	 * descriptors are correctly initialised.1188	 */1189	sa1100fb_check_var(&fbi->fb.var, &fbi->fb);1190 1191	platform_set_drvdata(pdev, fbi);1192 1193	ret = register_framebuffer(&fbi->fb);1194	if (ret < 0) {1195		dma_free_wc(fbi->dev, fbi->map_size, fbi->map_cpu,1196			    fbi->map_dma);1197		return ret;1198	}1199 1200#ifdef CONFIG_CPU_FREQ1201	fbi->freq_transition.notifier_call = sa1100fb_freq_transition;1202	cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);1203#endif1204 1205	/* This driver cannot be unloaded at the moment */1206	return 0;1207}1208 1209static struct platform_driver sa1100fb_driver = {1210	.probe		= sa1100fb_probe,1211	.suspend	= sa1100fb_suspend,1212	.resume		= sa1100fb_resume,1213	.driver		= {1214		.name	= "sa11x0-fb",1215	},1216};1217 1218static int __init sa1100fb_init(void)1219{1220	if (fb_get_options("sa1100fb", NULL))1221		return -ENODEV;1222 1223	return platform_driver_register(&sa1100fb_driver);1224}1225 1226module_init(sa1100fb_init);1227MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");1228MODULE_LICENSE("GPL");1229