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