sa1100fb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:59k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/video/sa1100fb.c
  3.  *
  4.  *  Copyright (C) 1999 Eric A. Thomas
  5.  *   Based on acornfb.c Copyright (C) Russell King.
  6.  *
  7.  * This file is subject to the terms and conditions of the GNU General Public
  8.  * License.  See the file COPYING in the main directory of this archive for
  9.  * more details.
  10.  *
  11.  *         StrongARM 1100 LCD Controller Frame Buffer Driver
  12.  *
  13.  * Please direct your questions and comments on this driver to the following
  14.  * email address:
  15.  *
  16.  * linux-arm-kernel@lists.arm.linux.org.uk
  17.  *
  18.  * Clean patches should be sent to the ARM Linux Patch System.  Please see the
  19.  * following web page for more information:
  20.  *
  21.  * http://www.arm.linux.org.uk/developer/patches/info.shtml
  22.  *
  23.  * Thank you.
  24.  *
  25.  * Known problems:
  26.  * - With the Neponset plugged into an Assabet, LCD powerdown
  27.  *   doesn't work (LCD stays powered up).  Therefore we shouldn't
  28.  *   blank the screen.
  29.  * - We don't limit the CPU clock rate nor the mode selection
  30.  *   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 buffer
  35.  *   drivers do not expect a linear colourmap, but a colourmap based on
  36.  *   the VT100 standard mapping.
  37.  *
  38.  *   If your _userspace_ requires a linear colourmap, then the setup of
  39.  *   such a colourmap belongs _in userspace_, not in the kernel.  Code
  40.  *   to set the colourmap correctly from user space has been sent to
  41.  *   David Neuer.  It's around 8 lines of C code, plus another 4 to
  42.  *   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_HorSnchL
  46.  *
  47.  * - The following should be specified:
  48.  *      either LCCR0_Color or LCCR0_Mono
  49.  *      either LCCR0_Sngl or LCCR0_Dual
  50.  *      either LCCR0_Act or LCCR0_Pas
  51.  *      either LCCR3_OutEnH or LCCD3_OutEnL
  52.  *      either LCCR3_PixRsEdg or LCCR3_PixFlEdg
  53.  *      either LCCR3_ACBsDiv or LCCR3_ACBsCntOff
  54.  *
  55.  * Code Status:
  56.  * 1999/04/01:
  57.  * - Driver appears to be working for Brutus 320x200x8bpp mode.  Other
  58.  *   resolutions are working, but only the 8bpp mode is supported.
  59.  *   Changes need to be made to the palette encode and decode routines
  60.  *   to support 4 and 16 bpp modes.  
  61.  *   Driver is not designed to be a module.  The FrameBuffer is statically
  62.  *   allocated since dynamic allocation of a 300k buffer cannot be 
  63.  *   guaranteed. 
  64.  *
  65.  * 1999/06/17:
  66.  * - FrameBuffer memory is now allocated at run-time when the
  67.  *   driver is initialized.    
  68.  *
  69.  * 2000/04/10: Nicolas Pitre <nico@cam.org>
  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 PLD 
  78.  *   earlier this year which broke the framebuffer driver for newer 
  79.  *   Phase 4 Assabets.  Some other parameters were changed to optimize
  80.  *   for the Sharp display.
  81.  *
  82.  * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp>
  83.  * - XP860 support added
  84.  *
  85.  * 2000/08/19: Mark Huang <mhuang@livetoy.com>
  86.  * - Allows standard options to be passed on the kernel command line
  87.  *   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_controller
  92.  *
  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 added
  98.  *
  99.  * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de>
  100.  * - Huw Webpanel support added
  101.  *
  102.  * 2000/11/23: Eric Peng <ericpeng@coventive.com>
  103.  * - Freebird add
  104.  *
  105.  * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com> 
  106.  *        Cliff Brake <cbrake@accelent.com>
  107.  * - Added PM callback
  108.  *
  109.  * 2001/05/26: <rmk@arm.linux.org.uk>
  110.  * - Fix 16bpp so that (a) we use the right colours rather than some
  111.  *   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_t
  115.  * - remove unused 'montype' stuff
  116.  * - remove redundant zero inits of init_var after the initial
  117.  *   memzero.
  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 structures
  122.  * - I've left various #warnings in - if you see one, and know
  123.  *   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 to
  127.  *   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; mainly
  131.  *   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 is
  144.  *   manufactured by Prime View, model no V16C6448AB
  145.  *
  146.  * 2001/07/23: <rmk@arm.linux.org.uk>
  147.  * - Hand merge version from handhelds.org CVS tree.  See patch
  148.  *   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't
  151.  *   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.  * 2002/02/21: <abraham@2d3d.co.za>
  163.  *  - Added support for ICP LCD-Kit01 on Frodo.
  164.  *  - Added support for backlight via CPLDs on Frodo.
  165.  */
  166. #include <linux/config.h>
  167. #include <linux/module.h>
  168. #include <linux/kernel.h>
  169. #include <linux/sched.h>
  170. #include <linux/errno.h>
  171. #include <linux/string.h>
  172. #include <linux/interrupt.h>
  173. #include <linux/slab.h>
  174. #include <linux/fb.h>
  175. #include <linux/delay.h>
  176. #include <linux/pm.h>
  177. #include <linux/init.h>
  178. #include <linux/cpufreq.h>
  179. #include <asm/hardware.h>
  180. #include <asm/io.h>
  181. #include <asm/irq.h>
  182. #include <asm/mach-types.h>
  183. #include <asm/uaccess.h>
  184. #include <asm/arch/assabet.h>
  185. #include <asm/arch/shannon.h>
  186. #include <video/fbcon.h>
  187. #include <video/fbcon-mfb.h>
  188. #include <video/fbcon-cfb4.h>
  189. #include <video/fbcon-cfb8.h>
  190. #include <video/fbcon-cfb16.h>
  191. /*
  192.  * debugging?
  193.  */
  194. #define DEBUG 0
  195. /*
  196.  * Complain if VAR is out of range.
  197.  */
  198. #define DEBUG_VAR 1
  199. #undef ASSABET_PAL_VIDEO
  200. #include "sa1100fb.h"
  201. void (*sa1100fb_blank_helper)(int blank);
  202. EXPORT_SYMBOL(sa1100fb_blank_helper);
  203. /*
  204.  * IMHO this looks wrong.  In 8BPP, length should be 8.
  205.  */
  206. static struct sa1100fb_rgb rgb_8 = {
  207. red: { offset: 0,  length: 4, },
  208. green: { offset: 0,  length: 4, },
  209. blue: { offset: 0,  length: 4, },
  210. transp: { offset: 0,  length: 0, },
  211. };
  212. static struct sa1100fb_rgb def_rgb_16 = {
  213. red: { offset: 11, length: 5, },
  214. green: { offset: 5,  length: 6, },
  215. blue: { offset: 0,  length: 5, },
  216. transp: { offset: 0,  length: 0, },
  217. };
  218. #ifdef CONFIG_SA1100_ASSABET
  219. #ifndef ASSABET_PAL_VIDEO
  220. /*
  221.  * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
  222.  * takes an RGB666 signal, but we provide it with an RGB565 signal
  223.  * instead (def_rgb_16).
  224.  */
  225. static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
  226. pixclock: 171521, bpp: 16,
  227. xres: 320, yres: 240,
  228. hsync_len: 5, vsync_len: 1,
  229. left_margin: 61, upper_margin: 3,
  230. right_margin: 9, lower_margin: 0,
  231. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  232. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  233. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
  234. };
  235. #else
  236. static struct sa1100fb_mach_info pal_info __initdata = {
  237. pixclock: 67797, bpp: 16,
  238. xres: 640, yres: 512,
  239. hsync_len: 64, vsync_len: 6,
  240. left_margin: 125, upper_margin: 70,
  241. right_margin: 115, lower_margin: 36,
  242. sync: 0,
  243. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  244. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
  245. };
  246. #endif
  247. #endif
  248. #ifdef CONFIG_SA1100_H3XXX
  249. static struct sa1100fb_mach_info h3800_info __initdata = {
  250. pixclock: 174757,  bpp: 16,
  251. xres: 320, yres: 240,
  252. hsync_len: 3, vsync_len: 3,
  253. left_margin: 12, upper_margin: 10,
  254. right_margin: 17, lower_margin: 1,
  255. sync: 0, cmap_static: 1,
  256. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  257. lccr3: LCCR3_ACBsCntOff | LCCR3_PixFlEdg | LCCR3_OutEnH,
  258. };
  259. static struct sa1100fb_mach_info h3600_info __initdata = {
  260. pixclock: 174757,  bpp: 16,
  261. xres: 320, yres: 240,
  262. hsync_len: 3, vsync_len: 3,
  263. left_margin: 12, upper_margin: 10,
  264. right_margin: 17, lower_margin: 1,
  265. sync: 0, cmap_static: 1,
  266. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  267. lccr3: LCCR3_ACBsCntOff | LCCR3_OutEnH | LCCR3_PixFlEdg,
  268. };
  269. static struct sa1100fb_rgb h3600_rgb_16 = {
  270. red: { offset: 12, length: 4, },
  271. green: { offset: 7,  length: 4, },
  272. blue: { offset: 1,  length: 4, },
  273. transp: { offset: 0,  length: 0, },
  274. };
  275. static struct sa1100fb_mach_info h3100_info __initdata = {
  276. pixclock: 406977,  bpp: 4,
  277. xres: 320, yres: 240,
  278. hsync_len: 26, vsync_len: 41,
  279. left_margin: 4, upper_margin: 0,
  280. right_margin: 4, lower_margin: 0,
  281. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  282. cmap_greyscale: 1,
  283. cmap_inverse: 1,
  284. lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
  285. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
  286. };
  287. #endif
  288. #ifdef CONFIG_SA1100_BRUTUS
  289. static struct sa1100fb_mach_info brutus_info __initdata = {
  290. pixclock: 0, bpp: 8,
  291. xres: 320, yres: 240,
  292. hsync_len: 3, vsync_len: 1,
  293. left_margin: 41, upper_margin: 0,
  294. right_margin: 101, lower_margin: 0,
  295. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  296. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
  297. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
  298. LCCR3_PixClkDiv(44),
  299. };
  300. #endif
  301. #ifdef CONFIG_SA1100_CERF
  302. static struct sa1100fb_mach_info cerf_info __initdata = {
  303. #if defined(CONFIG_CERF_LCD_72_A)
  304. pixclock:       171521,         bpp:            8,
  305. xres: 640, yres: 480,
  306. lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
  307. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
  308. LCCR3_PixClkDiv(38),
  309. #elif defined(CONFIG_CERF_LCD_57_A)
  310. pixclock:       171521,         bpp:            8,
  311. xres: 320, yres: 240,
  312. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
  313. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
  314. LCCR3_PixClkDiv(38),
  315. #elif defined(CONFIG_CERF_LCD_38_A)
  316. pixclock:       171521,         bpp:            8,
  317. xres: 240, yres: 320,
  318. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
  319. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
  320. LCCR3_PixClkDiv(38),
  321. #elif defined(CONFIG_CERF_LCD_38_B)
  322. pixclock: 171521,  bpp: 4,
  323. xres: 320, yres: 240,
  324. lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
  325. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
  326. LCCR3_PixClkDiv(38),
  327. #else
  328. #error "Must have a CerfBoard LCD form factor selected"
  329. #endif
  330. hsync_len: 5, vsync_len: 1,
  331. left_margin: 61, upper_margin: 3,
  332. right_margin: 9, lower_margin: 0,
  333. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  334. };
  335. #if 0
  336. static struct sa1100fb_rgb cerf_rgb_16 = {
  337. red: { offset: 8, length: 4, },
  338. green: { offset: 4, length: 4, },
  339. blue: { offset: 0, length: 4, },
  340. transp: { offset: 0, length: 0, },
  341. };
  342. #endif
  343. #endif
  344. #ifdef CONFIG_SA1100_FREEBIRD
  345. #warning Please check this carefully
  346. static struct sa1100fb_mach_info freebird_info __initdata = {
  347. pixclock: 171521, bpp: 16,
  348. xres: 240, yres: 320,
  349. hsync_len: 3, vsync_len: 2,
  350. left_margin: 2, upper_margin: 0,
  351. right_margin: 2, lower_margin: 0,
  352. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  353. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
  354. lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2),
  355. };
  356. static struct sa1100fb_rgb freebird_rgb_16 = {
  357. red: { offset: 8,  length: 4, },
  358. green: { offset: 4,  length: 4, },
  359. blue: { offset: 0,  length: 4, },
  360. transp: { offset: 12, length: 4, },
  361. };
  362. #endif
  363. #ifdef CONFIG_SA1100_GRAPHICSCLIENT
  364. static struct sa1100fb_mach_info graphicsclient_info __initdata = {
  365. pixclock: 53500, bpp: 8,
  366. xres: 640, yres: 480,
  367. hsync_len: 9, vsync_len: 9,
  368. left_margin: 54, upper_margin: 24,
  369. right_margin: 54, lower_margin: 32,
  370. sync: 0,
  371. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  372. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
  373. };
  374. #endif
  375. #ifdef CONFIG_SA1100_HUW_WEBPANEL
  376. static struct sa1100fb_mach_info huw_webpanel_info __initdata = {
  377. pixclock: 0, bpp: 8,
  378. xres: 640, yres: 480,
  379. hsync_len: 3, vsync_len: 1,
  380. left_margin: 41, upper_margin: 0,
  381. right_margin: 101, lower_margin: 0,
  382. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  383. lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
  384. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8,
  385. #error FIXME
  386. /*
  387.  * FIXME: please get rid of the '| 8' in preference to an
  388.  * LCCR3_PixClkDiv() version. --rmk
  389.  */
  390. };
  391. #endif
  392. #ifdef LART_GREY_LCD
  393. static struct sa1100fb_mach_info lart_grey_info __initdata = {
  394. pixclock: 150000, bpp: 4,
  395. xres: 320, yres: 240,
  396. hsync_len: 1, vsync_len: 1,
  397. left_margin: 4, upper_margin: 0,
  398. right_margin: 2, lower_margin: 0,
  399. cmap_greyscale: 1,
  400. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  401. lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
  402. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
  403. };
  404. #endif
  405. #ifdef LART_COLOR_LCD
  406. static struct sa1100fb_mach_info lart_color_info __initdata = {
  407. pixclock: 150000, bpp: 16,
  408. xres: 320, yres: 240,
  409. hsync_len: 2, vsync_len: 3,
  410. left_margin: 69, upper_margin: 14,
  411. right_margin: 8, lower_margin: 4,
  412. sync: 0,
  413. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  414. lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
  415. };
  416. #endif
  417. #ifdef LART_VIDEO_OUT
  418. static struct sa1100fb_mach_info lart_video_info __initdata = {
  419. pixclock: 39721, bpp: 16,
  420. xres: 640, yres: 480,
  421. hsync_len: 95, vsync_len: 2,
  422. left_margin: 40, upper_margin: 32,
  423. right_margin: 24, lower_margin: 11,
  424. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  425. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  426. lccr3: LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
  427. };
  428. #endif
  429. #ifdef CONFIG_SA1100_FRODO
  430. /* At the moment, this is the only LCD available
  431.    for the 2d3D, Inc. SA-1110 Development Board */
  432. #define KIT01_LCD
  433. #endif
  434. #ifdef KIT01_LCD
  435. static struct sa1100fb_mach_info kit01_info __initdata =
  436. {
  437. pixclock: 63291, bpp: 16,
  438. xres: 640, yres: 480,
  439. hsync_len: 64, vsync_len: 3,
  440. left_margin: 122, upper_margin: 45,
  441. right_margin: 10, lower_margin: 10,
  442. sync: 0,
  443. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  444. lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg
  445. };
  446. #endif
  447. #ifdef CONFIG_SA1100_SHANNON
  448. static struct sa1100fb_mach_info shannon_info __initdata = {
  449. pixclock: 152500, bpp: 8,
  450. xres: 640, yres: 480,
  451. hsync_len: 4, vsync_len: 3,
  452. left_margin: 2, upper_margin: 0,
  453. right_margin: 1, lower_margin: 0,
  454. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
  455. lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
  456. lccr3: LCCR3_ACBsDiv(512),
  457. };
  458. #endif
  459. #ifdef CONFIG_SA1100_OMNIMETER
  460. static struct sa1100fb_mach_info omnimeter_info __initdata = {
  461. pixclock: 0, bpp: 4,
  462. xres: 480, yres: 320,
  463. hsync_len: 1, vsync_len: 1,
  464. left_margin: 10, upper_margin: 0,
  465. right_margin: 10, lower_margin: 0,
  466. cmap_greyscale: 1,
  467. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  468. lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono,
  469. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) |
  470. LCCR3_PixClkDiv(44),
  471. #error FIXME: fix pixclock, ACBsDiv
  472. /*
  473.  * FIXME: I think ACBsDiv is wrong above - should it be 512 (disabled)?
  474.  *   - rmk
  475.  */
  476. };
  477. #endif
  478. #ifdef CONFIG_SA1100_PANGOLIN
  479. static struct sa1100fb_mach_info pangolin_info __initdata = {
  480. pixclock: 341521, bpp: 16,
  481. xres: 800, yres: 600,
  482. hsync_len: 64, vsync_len: 7,
  483. left_margin: 160, upper_margin: 7,
  484. right_margin: 24, lower_margin: 1,
  485. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  486. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  487. lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff,
  488. };
  489. #endif
  490. #ifdef CONFIG_SA1100_STORK
  491. #if STORK_TFT /* ie the NEC TFT */
  492. /*
  493.  * pixclock is ps per clock. say 72Hz, 800x600 clocks => (1/72)/(800*600)
  494.  * = 28935 and a bit
  495.  * NB likely to be increased to ease bus timings wrt pcmcia interface
  496.  */
  497. static struct sa1100fb_mach_info stork_tft_info __initdata = {
  498. pixclock: 28935, bpp: 16,
  499. xres: 640, yres: 480,
  500. hsync_len: 64, vsync_len: 2,
  501. left_margin: 48, upper_margin: 12,
  502. right_margin: 48, lower_margin: 31,
  503. sync: 0,
  504. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  505. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg,
  506. };
  507. static struct sa1100fb_rgb stork_tft_rgb_16 = {
  508. red: { offset: 11, length: 5, },
  509. green: { offset: 5,  length: 6, },
  510. blue: { offset: 0,  length: 5, },
  511. transp: { offset: 0,  length: 0, },
  512. };
  513. #else /* Kyocera DSTN */
  514. static struct sa1100fb_mach_info stork_dstn_info __initdata = {
  515. pixclock: 0, bpp: 16,
  516. xres: 640, yres: 480,
  517. hsync_len: 2, vsync_len: 2,
  518. left_margin: 2, upper_margin: 0,
  519. right_margin: 2, lower_margin: 0,
  520. sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
  521. lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
  522. #error Fixme
  523. lccr3: 0xff00 |
  524. 0x18 /* ought to be 0x14 but DMA isn't up to that as yet */
  525. };
  526. static struct sa1100fb_rgb stork_dstn_rgb_16 = {
  527. red: { offset: 8,  length: 4, },
  528. green: { offset: 4,  length: 4, },
  529. blue: { offset: 0,  length: 4, },
  530. transp: { offset: 0,  length: 0, },
  531. };
  532. #endif
  533. #endif
  534. #ifdef CONFIG_SA1100_XP860
  535. static struct sa1100fb_mach_info xp860_info __initdata = {
  536. pixclock: 0, bpp: 8,
  537. xres: 1024, yres: 768,
  538. hsync_len: 3, vsync_len: 3,
  539. left_margin: 3, upper_margin: 2,
  540. right_margin: 2, lower_margin: 1,
  541. sync: 0,
  542. lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
  543. lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6),
  544. };
  545. #endif
  546. static struct sa1100fb_mach_info * __init
  547. sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
  548. {
  549. struct sa1100fb_mach_info *inf = NULL;
  550. /*
  551.  *            R        G       B       T
  552.  * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
  553.  * h3600    {12,4}, { 7,4}, { 1,4}, { 0,0}
  554.  * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
  555.  */
  556. #ifdef CONFIG_SA1100_ASSABET
  557. if (machine_is_assabet()) {
  558. #ifndef ASSABET_PAL_VIDEO
  559. inf = &lq039q2ds54_info;
  560. #else
  561. inf = &pal_info;
  562. #endif
  563. }
  564. #endif
  565. #ifdef CONFIG_SA1100_H3XXX
  566. if (machine_is_h3600()) {
  567. inf = &h3600_info;
  568. fbi->rgb[RGB_16] = &h3600_rgb_16;
  569. }
  570. if (machine_is_h3100()) {
  571. inf = &h3100_info;
  572. }
  573. if (machine_is_h3800()) {
  574. inf = &h3800_info;
  575. }
  576. #endif
  577. #ifdef CONFIG_SA1100_BRUTUS
  578. if (machine_is_brutus()) {
  579. inf = &brutus_info;
  580. }
  581. #endif
  582. #ifdef CONFIG_SA1100_CERF
  583. if (machine_is_cerf()) {
  584. inf = &cerf_info;
  585. }
  586. #endif
  587. #ifdef CONFIG_SA1100_FREEBIRD
  588. if (machine_is_freebird()) {
  589. inf = &freebird_info;
  590. fbi->rgb[RGB_16] = &freebird_rgb16;
  591. }
  592. #endif
  593. #ifdef CONFIG_SA1100_GRAPHICSCLIENT
  594. if (machine_is_graphicsclient()) {
  595. inf = &graphicsclient_info;
  596. }
  597. #endif
  598. #ifdef CONFIG_SA1100_HUW_WEBPANEL
  599. if (machine_is_huw_webpanel()) {
  600. inf = &huw_webpanel_info;
  601. }
  602. #endif
  603. #ifdef CONFIG_SA1100_LART
  604. if (machine_is_lart()) {
  605. #ifdef LART_GREY_LCD
  606. inf = &lart_grey_info;
  607. #endif
  608. #ifdef LART_COLOR_LCD
  609. inf = &lart_color_info;
  610. #endif
  611. #ifdef LART_VIDEO_OUT
  612. inf = &lart_video_info;
  613. #endif
  614. #ifdef KIT01_LCD
  615. inf = &kit01_info;
  616. #endif
  617. }
  618. #endif
  619. #ifdef CONFIG_SA1100_FRODO
  620. if (machine_is_frodo()) {
  621. #ifdef KIT01_LCD
  622. inf = &kit01_info;
  623. #endif
  624. }
  625. #endif
  626. #ifdef CONFIG_SA1100_SHANNON
  627. if (machine_is_shannon()) {
  628. inf = &shannon_info;
  629. }
  630. #endif
  631. #ifdef CONFIG_SA1100_OMNIMETER
  632. if (machine_is_omnimeter()) {
  633. inf = &omnimeter_info;
  634. }
  635. #endif
  636. #ifdef CONFIG_SA1100_PANGOLIN
  637. if (machine_is_pangolin()) {
  638. inf = &pangolin_info;
  639. }
  640. #endif
  641. #ifdef CONFIG_SA1100_XP860
  642. if (machine_is_xp860()) {
  643. inf = &xp860_info;
  644. }
  645. #endif
  646. #ifdef CONFIG_SA1100_STORK
  647. if (machine_is_stork()) {
  648. #if STORK_TFT
  649. inf = &stork_tft_info;
  650. fbi->rgb[RGB_16] = &stork_tft_rgb_16;
  651. #else
  652. inf = &stork_dstn_info;
  653. fbi->rgb[RGB_16] = &stork_dstn_rgb_16;
  654. #endif
  655. }
  656. #endif
  657. return inf;
  658. }
  659. static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
  660. static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
  661. static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state)
  662. {
  663. unsigned long flags;
  664. local_irq_save(flags);
  665. /*
  666.  * We need to handle two requests being made at the same time.
  667.  * There are two important cases:
  668.  *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
  669.  *     We must perform the unblanking, which will do our REENABLE for us.
  670.  *  2. When we are blanking, but immediately unblank before we have
  671.  *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
  672.  */
  673. if (fbi->task_state == C_ENABLE && state == C_REENABLE)
  674. state = (u_int) -1;
  675. if (fbi->task_state == C_DISABLE && state == C_ENABLE)
  676. state = C_REENABLE;
  677. if (state != (u_int)-1) {
  678. fbi->task_state = state;
  679. schedule_task(&fbi->task);
  680. }
  681. local_irq_restore(flags);
  682. }
  683. /*
  684.  * Get the VAR structure pointer for the specified console
  685.  */
  686. static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
  687. {
  688. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  689. return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var;
  690. }
  691. /*
  692.  * Get the DISPLAY structure pointer for the specified console
  693.  */
  694. static inline struct display *get_con_display(struct fb_info *info, int con)
  695. {
  696. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  697. return (con < 0) ? fbi->fb.disp : &fb_display[con];
  698. }
  699. /*
  700.  * Get the CMAP pointer for the specified console
  701.  */
  702. static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
  703. {
  704. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  705. return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap;
  706. }
  707. static inline u_int
  708. chan_to_field(u_int chan, struct fb_bitfield *bf)
  709. {
  710. chan &= 0xffff;
  711. chan >>= 16 - bf->length;
  712. return chan << bf->offset;
  713. }
  714. /*
  715.  * Convert bits-per-pixel to a hardware palette PBS value.
  716.  */
  717. static inline u_int
  718. palette_pbs(struct fb_var_screeninfo *var)
  719. {
  720. int ret = 0;
  721. switch (var->bits_per_pixel) {
  722. #ifdef FBCON_HAS_CFB4
  723. case 4:  ret = 0 << 12; break;
  724. #endif
  725. #ifdef FBCON_HAS_CFB8
  726. case 8:  ret = 1 << 12; break;
  727. #endif
  728. #ifdef FBCON_HAS_CFB16
  729. case 16: ret = 2 << 12; break;
  730. #endif
  731. }
  732. return ret;
  733. }
  734. static int
  735. sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
  736.        u_int trans, struct fb_info *info)
  737. {
  738. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  739. u_int val, ret = 1;
  740. if (regno < fbi->palette_size) {
  741. val = ((red >> 4) & 0xf00);
  742. val |= ((green >> 8) & 0x0f0);
  743. val |= ((blue >> 12) & 0x00f);
  744. if (regno == 0)
  745. val |= palette_pbs(&fbi->fb.var);
  746. fbi->palette_cpu[regno] = val;
  747. ret = 0;
  748. }
  749. return ret;
  750. }
  751. static int
  752. sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  753.    u_int trans, struct fb_info *info)
  754. {
  755. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  756. struct display *disp = get_con_display(info, fbi->currcon);
  757. u_int val;
  758. int ret = 1;
  759. /*
  760.  * If inverse mode was selected, invert all the colours
  761.  * rather than the register number.  The register number
  762.  * is what you poke into the framebuffer to produce the
  763.  * colour you requested.
  764.  */
  765. if (disp->inverse) {
  766. red   = 0xffff - red;
  767. green = 0xffff - green;
  768. blue  = 0xffff - blue;
  769. }
  770. /*
  771.  * If greyscale is true, then we convert the RGB value
  772.  * to greyscale no mater what visual we are using.
  773.  */
  774. if (fbi->fb.var.grayscale)
  775. red = green = blue = (19595 * red + 38470 * green +
  776. 7471 * blue) >> 16;
  777. switch (fbi->fb.disp->visual) {
  778. case FB_VISUAL_TRUECOLOR:
  779. /*
  780.  * 12 or 16-bit True Colour.  We encode the RGB value
  781.  * according to the RGB bitfield information.
  782.  */
  783. if (regno < 16) {
  784. u16 *pal = fbi->fb.pseudo_palette;
  785. val  = chan_to_field(red, &fbi->fb.var.red);
  786. val |= chan_to_field(green, &fbi->fb.var.green);
  787. val |= chan_to_field(blue, &fbi->fb.var.blue);
  788. pal[regno] = val;
  789. ret = 0;
  790. }
  791. break;
  792. case FB_VISUAL_STATIC_PSEUDOCOLOR:
  793. case FB_VISUAL_PSEUDOCOLOR:
  794. ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
  795. break;
  796. }
  797. return ret;
  798. }
  799. /*
  800.  *  sa1100fb_display_dma_period()
  801.  *    Calculate the minimum period (in picoseconds) between two DMA
  802.  *    requests for the LCD controller.
  803.  */
  804. static unsigned int
  805. sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
  806. {
  807. unsigned int mem_bits_per_pixel;
  808. mem_bits_per_pixel = var->bits_per_pixel;
  809. if (mem_bits_per_pixel == 12)
  810. mem_bits_per_pixel = 16;
  811. /*
  812.  * Period = pixclock * bits_per_byte * bytes_per_transfer
  813.  * / memory_bits_per_pixel;
  814.  */
  815. return var->pixclock * 8 * 16 / mem_bits_per_pixel;
  816. }
  817. /*
  818.  *  sa1100fb_decode_var():
  819.  *    Get the video params out of 'var'. If a value doesn't fit, round it up,
  820.  *    if it's too big, return -EINVAL.
  821.  *
  822.  *    Suggestion: Round up in the following order: bits_per_pixel, xres,
  823.  *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
  824.  *    bitfields, horizontal timing, vertical timing.
  825.  */
  826. static int
  827. sa1100fb_validate_var(struct fb_var_screeninfo *var,
  828.       struct sa1100fb_info *fbi)
  829. {
  830. int ret = -EINVAL;
  831. if (var->xres < MIN_XRES)
  832. var->xres = MIN_XRES;
  833. if (var->yres < MIN_YRES)
  834. var->yres = MIN_YRES;
  835. if (var->xres > fbi->max_xres)
  836. var->xres = fbi->max_xres;
  837. if (var->yres > fbi->max_yres)
  838. var->yres = fbi->max_yres;
  839. var->xres_virtual =
  840.     var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
  841. var->yres_virtual =
  842.     var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
  843. DPRINTK("var->bits_per_pixel=%dn", var->bits_per_pixel);
  844. switch (var->bits_per_pixel) {
  845. #ifdef FBCON_HAS_CFB4
  846. case 4: ret = 0; break;
  847. #endif
  848. #ifdef FBCON_HAS_CFB8
  849. case 8: ret = 0; break;
  850. #endif
  851. #ifdef FBCON_HAS_CFB16
  852. case 16: ret = 0; break;
  853. #endif
  854. default:
  855. break;
  856. }
  857. #ifdef CONFIG_CPU_FREQ
  858. printk(KERN_DEBUG "dma period = %d ps, clock = %d kHzn",
  859. sa1100fb_display_dma_period(var),
  860. cpufreq_get(smp_processor_id()));
  861. #endif
  862. return ret;
  863. }
  864. static inline void sa1100fb_set_truecolor(u_int is_true_color)
  865. {
  866. DPRINTK("true_color = %dn", is_true_color);
  867. if (machine_is_assabet()) {
  868. #if 1
  869. // phase 4 or newer Assabet's
  870. if (is_true_color)
  871. ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
  872. else
  873. ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
  874. #else
  875. // older Assabet's
  876. if (is_true_color)
  877. ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
  878. else
  879. ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
  880. #endif
  881. }
  882. }
  883. static void
  884. sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
  885. {
  886. u_long palette_mem_size;
  887. fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
  888. palette_mem_size = fbi->palette_size * sizeof(u16);
  889. DPRINTK("palette_mem_size = 0x%08lxn", (u_long) palette_mem_size);
  890. fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
  891. fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
  892. fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, &fbi->fb);
  893. /* Set board control register to handle new color depth */
  894. sa1100fb_set_truecolor(var->bits_per_pixel >= 16);
  895. #ifdef CONFIG_SA1100_OMNIMETER
  896. #error Do we have to do this here?   We already do it at init time.
  897. if (machine_is_omnimeter())
  898. SetLCDContrast(DefaultLCDContrast);
  899. #endif
  900. sa1100fb_activate_var(var, fbi);
  901. fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
  902.  0xcfff) | palette_pbs(var);
  903. }
  904. /*
  905.  * sa1100fb_set_var():
  906.  * Set the user defined part of the display for the specified console
  907.  */
  908. static int
  909. sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
  910. {
  911. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  912. struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
  913. struct display *display = get_con_display(&fbi->fb, con);
  914. int err, chgvar = 0, rgbidx;
  915. DPRINTK("set_varn");
  916. /*
  917.  * Decode var contents into a par structure, adjusting any
  918.  * out of range values.
  919.  */
  920. err = sa1100fb_validate_var(var, fbi);
  921. if (err)
  922. return err;
  923. if (var->activate & FB_ACTIVATE_TEST)
  924. return 0;
  925. if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
  926. return -EINVAL;
  927. if (dvar->xres != var->xres)
  928. chgvar = 1;
  929. if (dvar->yres != var->yres)
  930. chgvar = 1;
  931. if (dvar->xres_virtual != var->xres_virtual)
  932. chgvar = 1;
  933. if (dvar->yres_virtual != var->yres_virtual)
  934. chgvar = 1;
  935. if (dvar->bits_per_pixel != var->bits_per_pixel)
  936. chgvar = 1;
  937. if (con < 0)
  938. chgvar = 0;
  939. switch (var->bits_per_pixel) {
  940. #ifdef FBCON_HAS_CFB4
  941. case 4:
  942. if (fbi->cmap_static)
  943. display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
  944. else
  945. display->visual = FB_VISUAL_PSEUDOCOLOR;
  946. display->line_length = var->xres / 2;
  947. display->dispsw = &fbcon_cfb4;
  948. rgbidx = RGB_8;
  949. break;
  950. #endif
  951. #ifdef FBCON_HAS_CFB8
  952. case 8:
  953. if (fbi->cmap_static)
  954. display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
  955. else
  956. display->visual = FB_VISUAL_PSEUDOCOLOR;
  957. display->line_length = var->xres;
  958. display->dispsw = &fbcon_cfb8;
  959. rgbidx = RGB_8;
  960. break;
  961. #endif
  962. #ifdef FBCON_HAS_CFB16
  963. case 16:
  964. display->visual = FB_VISUAL_TRUECOLOR;
  965. display->line_length = var->xres * 2;
  966. display->dispsw = &fbcon_cfb16;
  967. display->dispsw_data = fbi->fb.pseudo_palette;
  968. rgbidx = RGB_16;
  969. break;
  970. #endif
  971. default:
  972. rgbidx = 0;
  973. display->dispsw = &fbcon_dummy;
  974. break;
  975. }
  976. display->screen_base = fbi->screen_cpu;
  977. display->next_line = display->line_length;
  978. display->type = fbi->fb.fix.type;
  979. display->type_aux = fbi->fb.fix.type_aux;
  980. display->ypanstep = fbi->fb.fix.ypanstep;
  981. display->ywrapstep = fbi->fb.fix.ywrapstep;
  982. display->can_soft_blank = 1;
  983. display->inverse = fbi->cmap_inverse;
  984. *dvar = *var;
  985. dvar->activate &= ~FB_ACTIVATE_ALL;
  986. /*
  987.  * Copy the RGB parameters for this display
  988.  * from the machine specific parameters.
  989.  */
  990. dvar->red = fbi->rgb[rgbidx]->red;
  991. dvar->green = fbi->rgb[rgbidx]->green;
  992. dvar->blue = fbi->rgb[rgbidx]->blue;
  993. dvar->transp = fbi->rgb[rgbidx]->transp;
  994. DPRINTK("RGBT length = %d:%d:%d:%dn",
  995. dvar->red.length, dvar->green.length, dvar->blue.length,
  996. dvar->transp.length);
  997. DPRINTK("RGBT offset = %d:%d:%d:%dn",
  998. dvar->red.offset, dvar->green.offset, dvar->blue.offset,
  999. dvar->transp.offset);
  1000. /*
  1001.  * Update the old var.  The fbcon drivers still use this.
  1002.  * Once they are using fbi->fb.var, this can be dropped.
  1003.  */
  1004. display->var = *dvar;
  1005. /*
  1006.  * If we are setting all the virtual consoles, also set the
  1007.  * defaults used to create new consoles.
  1008.  */
  1009. if (var->activate & FB_ACTIVATE_ALL)
  1010. fbi->fb.disp->var = *dvar;
  1011. /*
  1012.  * If the console has changed and the console has defined
  1013.  * a changevar function, call that function.
  1014.  */
  1015. if (chgvar && info && fbi->fb.changevar)
  1016. fbi->fb.changevar(con);
  1017. /* If the current console is selected, activate the new var. */
  1018. if (con != fbi->currcon)
  1019. return 0;
  1020. sa1100fb_hw_set_var(dvar, fbi);
  1021. return 0;
  1022. }
  1023. static int
  1024. __do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  1025.       struct fb_info *info)
  1026. {
  1027. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  1028. struct fb_cmap *dcmap = get_con_cmap(info, con);
  1029. int err = 0;
  1030. if (con == -1)
  1031. con = fbi->currcon;
  1032. /* no colormap allocated? (we always have "this" colour map allocated) */
  1033. if (con >= 0)
  1034. err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
  1035. if (!err && con == fbi->currcon)
  1036. err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg, info);
  1037. if (!err)
  1038. fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
  1039. return err;
  1040. }
  1041. static int
  1042. sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  1043.   struct fb_info *info)
  1044. {
  1045. struct display *disp = get_con_display(info, con);
  1046. if (disp->visual == FB_VISUAL_TRUECOLOR ||
  1047.     disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
  1048. return -EINVAL;
  1049. return __do_set_cmap(cmap, kspc, con, info);
  1050. }
  1051. static int
  1052. sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
  1053. {
  1054. struct display *display = get_con_display(info, con);
  1055. *fix = info->fix;
  1056. fix->line_length = display->line_length;
  1057. fix->visual  = display->visual;
  1058. return 0;
  1059. }
  1060. static int
  1061. sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
  1062. {
  1063. *var = *get_con_var(info, con);
  1064. return 0;
  1065. }
  1066. static int
  1067. sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
  1068. {
  1069. struct fb_cmap *dcmap = get_con_cmap(info, con);
  1070. fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
  1071. return 0;
  1072. }
  1073. static struct fb_ops sa1100fb_ops = {
  1074. owner: THIS_MODULE,
  1075. fb_get_fix: sa1100fb_get_fix,
  1076. fb_get_var: sa1100fb_get_var,
  1077. fb_set_var: sa1100fb_set_var,
  1078. fb_get_cmap: sa1100fb_get_cmap,
  1079. fb_set_cmap: sa1100fb_set_cmap,
  1080. };
  1081. /*
  1082.  *  sa1100fb_switch():       
  1083.  * Change to the specified console.  Palette and video mode
  1084.  *      are changed to the console's stored parameters.
  1085.  *
  1086.  * Uh oh, this can be called from a tasklet (IRQ)
  1087.  */
  1088. static int sa1100fb_switch(int con, struct fb_info *info)
  1089. {
  1090. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  1091. struct display *disp;
  1092. struct fb_cmap *cmap;
  1093. DPRINTK("con=%d info->modename=%sn", con, fbi->fb.modename);
  1094. if (con == fbi->currcon)
  1095. return 0;
  1096. if (fbi->currcon >= 0) {
  1097. disp = fb_display + fbi->currcon;
  1098. /*
  1099.  * Save the old colormap and video mode.
  1100.  */
  1101. disp->var = fbi->fb.var;
  1102. if (disp->cmap.len)
  1103. fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
  1104. }
  1105. fbi->currcon = con;
  1106. disp = fb_display + con;
  1107. /*
  1108.  * Make sure that our colourmap contains 256 entries.
  1109.  */
  1110. fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
  1111. if (disp->cmap.len)
  1112. cmap = &disp->cmap;
  1113. else
  1114. cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
  1115. fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
  1116. fbi->fb.var = disp->var;
  1117. fbi->fb.var.activate = FB_ACTIVATE_NOW;
  1118. sa1100fb_set_var(&fbi->fb.var, con, info);
  1119. return 0;
  1120. }
  1121. /*
  1122.  * Formal definition of the VESA spec:
  1123.  *  On
  1124.  *   This refers to the state of the display when it is in full operation
  1125.  *  Stand-By
  1126.  *   This defines an optional operating state of minimal power reduction with
  1127.  *   the shortest recovery time
  1128.  *  Suspend
  1129.  *   This refers to a level of power management in which substantial power
  1130.  *   reduction is achieved by the display.  The display can have a longer 
  1131.  *   recovery time from this state than from the Stand-by state
  1132.  *  Off
  1133.  *   This indicates that the display is consuming the lowest level of power
  1134.  *   and is non-operational. Recovery from this state may optionally require
  1135.  *   the user to manually power on the monitor
  1136.  *
  1137.  *  Now, the fbdev driver adds an additional state, (blank), where they
  1138.  *  turn off the video (maybe by colormap tricks), but don't mess with the
  1139.  *  video itself: think of it semantically between on and Stand-By.
  1140.  *
  1141.  *  So here's what we should do in our fbdev blank routine:
  1142.  *
  1143.  *   VESA_NO_BLANKING (mode 0) Video on,  front/back light on
  1144.  *   VESA_VSYNC_SUSPEND (mode 1)   Video on,  front/back light off
  1145.  *   VESA_HSYNC_SUSPEND (mode 2)   Video on,  front/back light off
  1146.  *   VESA_POWERDOWN (mode 3) Video off, front/back light off
  1147.  *
  1148.  *  This will match the matrox implementation.
  1149.  */
  1150. /*
  1151.  * sa1100fb_blank():
  1152.  * Blank the display by setting all palette values to zero.  Note, the 
  1153.  *  12 and 16 bpp modes don't really use the palette, so this will not
  1154.  *      blank the display in all modes.  
  1155.  */
  1156. static void sa1100fb_blank(int blank, struct fb_info *info)
  1157. {
  1158. struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
  1159. int i;
  1160. DPRINTK("sa1100fb_blank: blank=%d info->modename=%sn", blank,
  1161. fbi->fb.modename);
  1162. switch (blank) {
  1163. case VESA_POWERDOWN:
  1164. case VESA_VSYNC_SUSPEND:
  1165. case VESA_HSYNC_SUSPEND:
  1166. if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
  1167.     fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
  1168. for (i = 0; i < fbi->palette_size; i++)
  1169. sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
  1170. sa1100fb_schedule_task(fbi, C_DISABLE);
  1171. if (sa1100fb_blank_helper)
  1172. sa1100fb_blank_helper(blank);
  1173. break;
  1174. case VESA_NO_BLANKING:
  1175. if (sa1100fb_blank_helper)
  1176. sa1100fb_blank_helper(blank);
  1177. if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
  1178.     fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
  1179. fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, info);
  1180. sa1100fb_schedule_task(fbi, C_ENABLE);
  1181. }
  1182. }
  1183. static int sa1100fb_updatevar(int con, struct fb_info *info)
  1184. {
  1185. DPRINTK("enteredn");
  1186. return 0;
  1187. }
  1188. /*
  1189.  * Calculate the PCD value from the clock rate (in picoseconds).
  1190.  * We take account of the PPCR clock setting.
  1191.  */
  1192. static inline int get_pcd(unsigned int pixclock)
  1193. {
  1194. unsigned int pcd;
  1195. if (pixclock) {
  1196. pcd = cpufreq_get(0) / 100;
  1197. pcd *= pixclock;
  1198. pcd /= 10000000;
  1199. pcd += 1; /* make up for integer math truncations */
  1200. } else {
  1201. /*
  1202.  * People seem to be missing this message.  Make it big.
  1203.  * Make it stand out.  Make sure people see it.
  1204.  */
  1205. printk(KERN_WARNING "******************************************************n");
  1206. printk(KERN_WARNING "**            ZERO PIXEL CLOCK DETECTED             **n");
  1207. printk(KERN_WARNING "** You are using a zero pixclock.  This means that  **n");
  1208. printk(KERN_WARNING "** clock scaling will not be able to adjust your    **n");
  1209. printk(KERN_WARNING "** your timing parameters appropriately, and the    **n");
  1210. printk(KERN_WARNING "** bandwidth calculations will fail to work.  This  **n");
  1211. printk(KERN_WARNING "** will shortly become an error condition, which    **n");
  1212. printk(KERN_WARNING "** will prevent your LCD display working.  Please   **n");
  1213. printk(KERN_WARNING "** send your patches in as soon as possible to shut **n");
  1214. printk(KERN_WARNING "** this message up.                                 **n");
  1215. printk(KERN_WARNING "******************************************************n");
  1216. pcd = 0;
  1217. }
  1218. return pcd;
  1219. }
  1220. /*
  1221.  * sa1100fb_activate_var():
  1222.  * Configures LCD Controller based on entries in var parameter.  Settings are      
  1223.  * only written to the controller if changes were made.  
  1224.  */
  1225. static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
  1226. {
  1227. struct sa1100fb_lcd_reg new_regs;
  1228. u_int half_screen_size, yres, pcd = get_pcd(var->pixclock);
  1229. u_long flags;
  1230. DPRINTK("Configuring SA1100 LCDn");
  1231. DPRINTK("var: xres=%d hslen=%d lm=%d rm=%dn",
  1232. var->xres, var->hsync_len,
  1233. var->left_margin, var->right_margin);
  1234. DPRINTK("var: yres=%d vslen=%d um=%d bm=%dn",
  1235. var->yres, var->vsync_len,
  1236. var->upper_margin, var->lower_margin);
  1237. #if DEBUG_VAR
  1238. if (var->xres < 16        || var->xres > 1024)
  1239. printk(KERN_ERR "%s: invalid xres %dn",
  1240. fbi->fb.fix.id, var->xres);
  1241. if (var->hsync_len < 1    || var->hsync_len > 64)
  1242. printk(KERN_ERR "%s: invalid hsync_len %dn",
  1243. fbi->fb.fix.id, var->hsync_len);
  1244. if (var->left_margin < 1  || var->left_margin > 255)
  1245. printk(KERN_ERR "%s: invalid left_margin %dn",
  1246. fbi->fb.fix.id, var->left_margin);
  1247. if (var->right_margin < 1 || var->right_margin > 255)
  1248. printk(KERN_ERR "%s: invalid right_margin %dn",
  1249. fbi->fb.fix.id, var->right_margin);
  1250. if (var->yres < 1         || var->yres > 1024)
  1251. printk(KERN_ERR "%s: invalid yres %dn",
  1252. fbi->fb.fix.id, var->yres);
  1253. if (var->vsync_len < 1    || var->vsync_len > 64)
  1254. printk(KERN_ERR "%s: invalid vsync_len %dn",
  1255. fbi->fb.fix.id, var->vsync_len);
  1256. if (var->upper_margin < 0 || var->upper_margin > 255)
  1257. printk(KERN_ERR "%s: invalid upper_margin %dn",
  1258. fbi->fb.fix.id, var->upper_margin);
  1259. if (var->lower_margin < 0 || var->lower_margin > 255)
  1260. printk(KERN_ERR "%s: invalid lower_margin %dn",
  1261. fbi->fb.fix.id, var->lower_margin);
  1262. #endif
  1263. new_regs.lccr0 = fbi->lccr0 |
  1264. LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
  1265. LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
  1266. new_regs.lccr1 =
  1267. LCCR1_DisWdth(var->xres) +
  1268. LCCR1_HorSnchWdth(var->hsync_len) +
  1269. LCCR1_BegLnDel(var->left_margin) +
  1270. LCCR1_EndLnDel(var->right_margin);
  1271. /*
  1272.  * If we have a dual scan LCD, then we need to halve
  1273.  * the YRES parameter.
  1274.  */
  1275. yres = var->yres;
  1276. if (fbi->lccr0 & LCCR0_Dual)
  1277. yres /= 2;
  1278. new_regs.lccr2 =
  1279. LCCR2_DisHght(yres) +
  1280. LCCR2_VrtSnchWdth(var->vsync_len) +
  1281. LCCR2_BegFrmDel(var->upper_margin) +
  1282. LCCR2_EndFrmDel(var->lower_margin);
  1283. new_regs.lccr3 = fbi->lccr3 |
  1284. (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
  1285. (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
  1286. LCCR3_ACBsCntOff;
  1287. if (pcd)
  1288. new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
  1289. DPRINTK("nlccr0 = 0x%08xn", new_regs.lccr0);
  1290. DPRINTK("nlccr1 = 0x%08xn", new_regs.lccr1);
  1291. DPRINTK("nlccr2 = 0x%08xn", new_regs.lccr2);
  1292. DPRINTK("nlccr3 = 0x%08xn", new_regs.lccr3);
  1293. half_screen_size = var->bits_per_pixel;
  1294. half_screen_size = half_screen_size * var->xres * var->yres / 16;
  1295. /* Update shadow copy atomically */
  1296. local_irq_save(flags);
  1297. fbi->dbar1 = fbi->palette_dma;
  1298. fbi->dbar2 = fbi->screen_dma + half_screen_size;
  1299. fbi->reg_lccr0 = new_regs.lccr0;
  1300. fbi->reg_lccr1 = new_regs.lccr1;
  1301. fbi->reg_lccr2 = new_regs.lccr2;
  1302. fbi->reg_lccr3 = new_regs.lccr3;
  1303. local_irq_restore(flags);
  1304. /*
  1305.  * Only update the registers if the controller is enabled
  1306.  * and something has changed.
  1307.  */
  1308. if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
  1309.     (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
  1310.     (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
  1311. sa1100fb_schedule_task(fbi, C_REENABLE);
  1312. return 0;
  1313. }
  1314. /*
  1315.  * NOTE!  The following functions are purely helpers for set_ctrlr_state.
  1316.  * Do not call them directly; set_ctrlr_state does the correct serialisation
  1317.  * to ensure that things happen in the right way 100% of time time.
  1318.  * -- rmk
  1319.  */
  1320. /*
  1321.  * FIXME: move LCD power stuff into sa1100fb_power_up_lcd()
  1322.  * Also, I'm expecting that the backlight stuff should
  1323.  * be handled differently.
  1324.  */
  1325. static void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
  1326. {
  1327. DPRINTK("backlight onn");
  1328. #ifdef CONFIG_SA1100_FREEBIRD
  1329. #error FIXME
  1330. if (machine_is_freebird()) {
  1331. BCR_set(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP);
  1332. }
  1333. #endif
  1334. #ifdef CONFIG_SA1100_FREEBIRD
  1335. if (machine_is_freebird()) {
  1336. /* Turn on backlight ,Chester */
  1337. BCR_set(BCR_FREEBIRD_LCD_BACKLIGHT);
  1338. }
  1339. #endif
  1340. #ifdef CONFIG_SA1100_HUW_WEBPANEL
  1341. #error FIXME
  1342. if (machine_is_huw_webpanel()) {
  1343. BCR_set(BCR_CCFL_POW + BCR_PWM_BACKLIGHT);
  1344. set_current_state(TASK_UNINTERRUPTIBLE);
  1345. schedule_task(200 * HZ / 1000);
  1346. BCR_set(BCR_TFT_ENA);
  1347. }
  1348. #endif
  1349. #ifdef CONFIG_SA1100_OMNIMETER
  1350. if (machine_is_omnimeter())
  1351. LEDBacklightOn();
  1352. #endif
  1353. #ifdef CONFIG_SA1100_FRODO
  1354. if (machine_is_frodo())
  1355. FRODO_CPLD_GENERAL |= FRODO_LCD_BACKLIGHT;
  1356. #endif
  1357. }
  1358. /*
  1359.  * FIXME: move LCD power stuf into sa1100fb_power_down_lcd()
  1360.  * Also, I'm expecting that the backlight stuff should
  1361.  * be handled differently.
  1362.  */
  1363. static void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
  1364. {
  1365. DPRINTK("backlight offn");
  1366. #ifdef CONFIG_SA1100_FREEBIRD
  1367. #error FIXME
  1368. if (machine_is_freebird()) {
  1369. BCR_clear(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP
  1370.   /*| BCR_FREEBIRD_LCD_BACKLIGHT */ );
  1371. }
  1372. #endif
  1373. #ifdef CONFIG_SA1100_OMNIMETER
  1374. if (machine_is_omnimeter())
  1375. LEDBacklightOff();
  1376. #endif
  1377. #ifdef CONFIG_SA1100_FRODO
  1378. if (machine_is_frodo())
  1379. FRODO_CPLD_GENERAL &= ~FRODO_LCD_BACKLIGHT;
  1380. #endif
  1381. }
  1382. static void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
  1383. {
  1384. DPRINTK("LCD power onn");
  1385. #ifndef ASSABET_PAL_VIDEO
  1386. if (machine_is_assabet())
  1387. ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
  1388. #endif
  1389. #ifdef CONFIG_SA1100_HUW_WEBPANEL
  1390. if (machine_is_huw_webpanel())
  1391. BCR_clear(BCR_TFT_NPWR);
  1392. #endif
  1393. #ifdef CONFIG_SA1100_OMNIMETER
  1394. if (machine_is_omnimeter())
  1395. LCDPowerOn();
  1396. #endif
  1397. if (machine_is_h3xxx())
  1398. set_h3600_egpio( IPAQ_EGPIO_LCD_ON );     /* Turn on power to the LCD */
  1399. #ifdef CONFIG_SA1100_STORK
  1400. if (machine_is_stork()) {
  1401. storkSetLCDCPLD(0, 1);
  1402. storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
  1403.   }
  1404. #endif
  1405. #ifdef CONFIG_SA1100_FRODO
  1406. if (machine_is_frodo())
  1407. sa1100fb_backlight_on(fbi);
  1408. #endif
  1409. }
  1410. static void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
  1411. {
  1412. DPRINTK("LCD power offn");
  1413. #ifndef ASSABET_PAL_VIDEO
  1414. if (machine_is_assabet())
  1415. ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
  1416. #endif
  1417. #ifdef CONFIG_SA1100_HUW_WEBPANEL
  1418. // dont forget to set the control lines to zero (?)
  1419. if (machine_is_huw_webpanel())
  1420. BCR_set(BCR_TFT_NPWR);
  1421. #endif
  1422. if (machine_is_h3xxx())
  1423. clr_h3600_egpio( IPAQ_EGPIO_LCD_ON );
  1424. #ifdef CONFIG_SA1100_STORK
  1425. if (machine_is_stork()) {
  1426. storkSetLCDCPLD(0, 0);
  1427. storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
  1428. }
  1429. #endif
  1430. #ifdef CONFIG_SA1100_FRODO
  1431. if (machine_is_frodo())
  1432. sa1100fb_backlight_off(fbi);
  1433. #endif
  1434. }
  1435. static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
  1436. {
  1437. u_int mask = 0;
  1438. /*
  1439.  * Enable GPIO<9:2> for LCD use if:
  1440.  *  1. Active display, or
  1441.  *  2. Color Dual Passive display
  1442.  *
  1443.  * see table 11.8 on page 11-27 in the SA1100 manual
  1444.  *   -- Erik.
  1445.  *
  1446.  * SA1110 spec update nr. 25 says we can and should
  1447.  * clear LDD15 to 12 for 4 or 8bpp modes with active
  1448.  * panels.  
  1449.  */
  1450. if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
  1451.     (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
  1452. mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
  1453. if (fbi->fb.var.bits_per_pixel > 8 ||
  1454.     (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
  1455. mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
  1456. }
  1457. #ifdef CONFIG_SA1100_FREEBIRD
  1458. #error Please contact <rmk@arm.linux.org.uk> about this
  1459. if (machine_is_freebird()) {
  1460. /* Color single passive */
  1461. mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
  1462. GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
  1463. }
  1464. #endif
  1465. if (machine_is_cerf()) {
  1466. /* GPIO15 is used as a bypass for 3.8" displays */
  1467. mask |= GPIO_GPIO15;
  1468. #ifdef CONFIG_SA1100_CERF
  1469. #warning Read Me Now!
  1470. #endif
  1471. #if 0 /* if this causes you problems, mail <rmk@arm.linux.org.uk> please. */
  1472.       /*
  1473.        * This was enabled for the 72_A version only, which is a _color_
  1474.        * _dual_ LCD.  Now look at the generic test above, and calculate
  1475.        * the mask value for a colour dual display...
  1476.        *
  1477.        * I therefore conclude that the code below is redundant, and will
  1478.        * be killed at the start of November 2001.
  1479.        */
  1480. /* FIXME: why is this? The Cerf's display doesn't seem
  1481.  * to be dual scan or active. I just leave it here,
  1482.  * but in my opinion this is definitively wrong.
  1483.  *  -- Erik <J.A.K.Mouw@its.tudelft.nl>
  1484.  */
  1485. /* REPLY: Umm.. Well to be honest, the 5.7" LCD which
  1486.  * this was used for does not use these pins, but
  1487.  * apparently all hell breaks loose if they are not
  1488.  * set on the Cerf, so we decided to leave them in ;)
  1489.  *  -- Daniel Chemko <dchemko@intrinsyc.com>
  1490.  */
  1491. /* color {dual/single} passive */
  1492. mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
  1493. GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
  1494. #endif
  1495. }
  1496. if (mask) {
  1497. GPDR |= mask;
  1498. GAFR |= mask;
  1499. }
  1500. }
  1501. static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
  1502. {
  1503. DPRINTK("Enabling LCD controllern");
  1504. /*
  1505.  * Make sure the mode bits are present in the first palette entry
  1506.  */
  1507. fbi->palette_cpu[0] &= 0xcfff;
  1508. fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
  1509. /* Sequence from 11.7.10 */
  1510. LCCR3 = fbi->reg_lccr3;
  1511. LCCR2 = fbi->reg_lccr2;
  1512. LCCR1 = fbi->reg_lccr1;
  1513. LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
  1514. DBAR1 = fbi->dbar1;
  1515. DBAR2 = fbi->dbar2;
  1516. LCCR0 |= LCCR0_LEN;
  1517. #ifdef CONFIG_SA1100_GRAPHICSCLIENT
  1518. #error Where is GPIO24 set as an output?  Can we fit this in somewhere else?
  1519. if (machine_is_graphicsclient()) {
  1520. // From ADS doc again...same as disable
  1521. set_current_state(TASK_UNINTERRUPTIBLE);
  1522. schedule_timeout(20 * HZ / 1000);
  1523. GPSR |= GPIO_GPIO24;
  1524. }
  1525. #endif
  1526. if (machine_is_shannon()) {
  1527. GPDR |= SHANNON_GPIO_DISP_EN;
  1528. GPSR |= SHANNON_GPIO_DISP_EN;
  1529. }
  1530. DPRINTK("DBAR1 = %pn", DBAR1);
  1531. DPRINTK("DBAR2 = %pn", DBAR2);
  1532. DPRINTK("LCCR0 = 0x%08xn", LCCR0);
  1533. DPRINTK("LCCR1 = 0x%08xn", LCCR1);
  1534. DPRINTK("LCCR2 = 0x%08xn", LCCR2);
  1535. DPRINTK("LCCR3 = 0x%08xn", LCCR3);
  1536. }
  1537. static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
  1538. {
  1539. DECLARE_WAITQUEUE(wait, current);
  1540. DPRINTK("Disabling LCD controllern");
  1541. #ifdef CONFIG_SA1100_GRAPHICSCLIENT
  1542. #error Where is GPIO24 set as an output?  Can we fit this in somewhere else?
  1543. if (machine_is_graphicsclient()) {
  1544. /*
  1545.  * From ADS internal document:
  1546.  *  GPIO24 should be LOW at least 10msec prior to disabling
  1547.  *  the LCD interface.
  1548.  *
  1549.  * We'll wait 20msec.
  1550.  */
  1551. GPCR |= GPIO_GPIO24;
  1552. set_current_state(TASK_UNINTERRUPTIBLE);
  1553. schedule_timeout(20 * HZ / 1000);
  1554. }
  1555. #endif
  1556. #ifdef CONFIG_SA1100_HUW_WEBPANEL
  1557. #error Move me into sa1100fb_power_up_lcd and/or sa1100fb_backlight_on
  1558. if (machine_is_huw_webpanel()) {
  1559. // dont forget to set the control lines to zero (?)
  1560. DPRINTK("ShutDown HuW LCD controllern");
  1561. BCR_clear(BCR_TFT_ENA + BCR_CCFL_POW + BCR_PWM_BACKLIGHT);
  1562. }
  1563. #endif
  1564. if (machine_is_shannon()) {
  1565. GPCR |= SHANNON_GPIO_DISP_EN;
  1566. }
  1567. add_wait_queue(&fbi->ctrlr_wait, &wait);
  1568. set_current_state(TASK_UNINTERRUPTIBLE);
  1569. LCSR = 0xffffffff; /* Clear LCD Status Register */
  1570. LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
  1571. enable_irq(IRQ_LCD); /* Enable LCD IRQ */
  1572. LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */
  1573. schedule_timeout(20 * HZ / 1000);
  1574. current->state = TASK_RUNNING;
  1575. remove_wait_queue(&fbi->ctrlr_wait, &wait);
  1576. }
  1577. /*
  1578.  *  sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
  1579.  */
  1580. static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
  1581. {
  1582. struct sa1100fb_info *fbi = dev_id;
  1583. unsigned int lcsr = LCSR;
  1584. if (lcsr & LCSR_LDD) {
  1585. LCCR0 |= LCCR0_LDM;
  1586. wake_up(&fbi->ctrlr_wait);
  1587. }
  1588. LCSR = lcsr;
  1589. }
  1590. /*
  1591.  * This function must be called from task context only, since it will
  1592.  * sleep when disabling the LCD controller, or if we get two contending
  1593.  * processes trying to alter state.
  1594.  */
  1595. static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
  1596. {
  1597. u_int old_state;
  1598. down(&fbi->ctrlr_sem);
  1599. old_state = fbi->state;
  1600. switch (state) {
  1601. case C_DISABLE_CLKCHANGE:
  1602. /*
  1603.  * Disable controller for clock change.  If the
  1604.  * controller is already disabled, then do nothing.
  1605.  */
  1606. if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
  1607. fbi->state = state;
  1608. sa1100fb_disable_controller(fbi);
  1609. }
  1610. break;
  1611. case C_DISABLE_PM:
  1612. case C_DISABLE:
  1613. /*
  1614.  * Disable controller
  1615.  */
  1616. if (old_state != C_DISABLE) {
  1617. fbi->state = state;
  1618. sa1100fb_backlight_off(fbi);
  1619. if (old_state != C_DISABLE_CLKCHANGE)
  1620. sa1100fb_disable_controller(fbi);
  1621. sa1100fb_power_down_lcd(fbi);
  1622. }
  1623. break;
  1624. case C_ENABLE_CLKCHANGE:
  1625. /*
  1626.  * Enable the controller after clock change.  Only
  1627.  * do this if we were disabled for the clock change.
  1628.  */
  1629. if (old_state == C_DISABLE_CLKCHANGE) {
  1630. fbi->state = C_ENABLE;
  1631. sa1100fb_enable_controller(fbi);
  1632. }
  1633. break;
  1634. case C_REENABLE:
  1635. /*
  1636.  * Re-enable the controller only if it was already
  1637.  * enabled.  This is so we reprogram the control
  1638.  * registers.
  1639.  */
  1640. if (old_state == C_ENABLE) {
  1641. sa1100fb_disable_controller(fbi);
  1642. sa1100fb_setup_gpio(fbi);
  1643. sa1100fb_enable_controller(fbi);
  1644. }
  1645. break;
  1646. case C_ENABLE_PM:
  1647. /*
  1648.  * Re-enable the controller after PM.  This is not
  1649.  * perfect - think about the case where we were doing
  1650.  * a clock change, and we suspended half-way through.
  1651.  */
  1652. if (old_state != C_DISABLE_PM)
  1653. break;
  1654. /* fall through */
  1655. case C_ENABLE:
  1656. /*
  1657.  * Power up the LCD screen, enable controller, and
  1658.  * turn on the backlight.
  1659.  */
  1660. if (old_state != C_ENABLE) {
  1661. fbi->state = C_ENABLE;
  1662. sa1100fb_setup_gpio(fbi);
  1663. sa1100fb_power_up_lcd(fbi);
  1664. sa1100fb_enable_controller(fbi);
  1665. sa1100fb_backlight_on(fbi);
  1666. }
  1667. break;
  1668. }
  1669. up(&fbi->ctrlr_sem);
  1670. }
  1671. /*
  1672.  * Our LCD controller task (which is called when we blank or unblank)
  1673.  * via keventd.
  1674.  */
  1675. static void sa1100fb_task(void *dummy)
  1676. {
  1677. struct sa1100fb_info *fbi = dummy;
  1678. u_int state = xchg(&fbi->task_state, -1);
  1679. set_ctrlr_state(fbi, state);
  1680. }
  1681. #ifdef CONFIG_CPU_FREQ
  1682. /*
  1683.  * Calculate the minimum DMA period over all displays that we own.
  1684.  * This, together with the SDRAM bandwidth defines the slowest CPU
  1685.  * frequency that can be selected.
  1686.  */
  1687. static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
  1688. {
  1689. unsigned int min_period = (unsigned int)-1;
  1690. int i;
  1691. for (i = 0; i < MAX_NR_CONSOLES; i++) {
  1692. unsigned int period;
  1693. /*
  1694.  * Do we own this display?
  1695.  */
  1696. if (fb_display[i].fb_info != &fbi->fb)
  1697. continue;
  1698. /*
  1699.  * Ok, calculate its DMA period
  1700.  */
  1701. period = sa1100fb_display_dma_period(get_con_var(&fbi->fb, i));
  1702. if (period < min_period)
  1703. min_period = period;
  1704. }
  1705. return min_period;
  1706. }
  1707. /*
  1708.  * CPU clock speed change handler.  We need to adjust the LCD timing
  1709.  * parameters when the CPU clock is adjusted by the power management
  1710.  * subsystem.
  1711.  */
  1712. static int
  1713. sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
  1714.  void *data)
  1715. {
  1716. struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
  1717. struct cpufreq_minmax *mm = data;
  1718. u_int pcd;
  1719. switch (val) {
  1720. case CPUFREQ_MINMAX:
  1721. printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
  1722. "new clock %d kHzn", sa1100fb_min_dma_period(fbi),
  1723. mm->cur_freq, mm->new_freq);
  1724. /* todo: fill in min/max values */
  1725. break;
  1726. case CPUFREQ_PRECHANGE:
  1727. set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
  1728. break;
  1729. case CPUFREQ_POSTCHANGE:
  1730. pcd = get_pcd(fbi->fb.var.pixclock);
  1731. fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
  1732. set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
  1733. break;
  1734. }
  1735. return 0;
  1736. }
  1737. #endif
  1738. #ifdef CONFIG_PM
  1739. /*
  1740.  * Power management hook.  Note that we won't be called from IRQ context,
  1741.  * unlike the blank functions above, so we may sleep.
  1742.  */
  1743. static int
  1744. sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
  1745. {
  1746. struct sa1100fb_info *fbi = pm_dev->data;
  1747. DPRINTK("pm_callback: %dn", req);
  1748. if (req == PM_SUSPEND || req == PM_RESUME) {
  1749. int state = (int)data;
  1750. if (state == 0) {
  1751. /* Enter D0. */
  1752. set_ctrlr_state(fbi, C_ENABLE_PM);
  1753. } else {
  1754. /* Enter D1-D3.  Disable the LCD controller.  */
  1755. set_ctrlr_state(fbi, C_DISABLE_PM);
  1756. }
  1757. }
  1758. DPRINTK("donen");
  1759. return 0;
  1760. }
  1761. #endif
  1762. /*
  1763.  * sa1100fb_map_video_memory():
  1764.  *      Allocates the DRAM memory for the frame buffer.  This buffer is  
  1765.  * remapped into a non-cached, non-buffered, memory region to  
  1766.  *      allow palette and pixel writes to occur without flushing the 
  1767.  *      cache.  Once this area is remapped, all virtual memory
  1768.  *      access to the video memory should occur at the new region.
  1769.  */
  1770. static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
  1771. {
  1772. /*
  1773.  * We reserve one page for the palette, plus the size
  1774.  * of the framebuffer.
  1775.  */
  1776. fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
  1777. fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
  1778. &fbi->map_dma);
  1779. if (fbi->map_cpu) {
  1780. fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
  1781. fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
  1782. fbi->fb.fix.smem_start = fbi->screen_dma;
  1783. }
  1784. return fbi->map_cpu ? 0 : -ENOMEM;
  1785. }
  1786. /* Fake monspecs to fill in fbinfo structure */
  1787. static struct fb_monspecs monspecs __initdata = {
  1788. 30000, 70000, 50, 65, 0 /* Generic */
  1789. };
  1790. static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
  1791. {
  1792. struct sa1100fb_mach_info *inf;
  1793. struct sa1100fb_info *fbi;
  1794. fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) +
  1795.       sizeof(u16) * 16, GFP_KERNEL);
  1796. if (!fbi)
  1797. return NULL;
  1798. memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
  1799. fbi->currcon = -1;
  1800. strcpy(fbi->fb.fix.id, SA1100_NAME);
  1801. fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
  1802. fbi->fb.fix.type_aux = 0;
  1803. fbi->fb.fix.xpanstep = 0;
  1804. fbi->fb.fix.ypanstep = 0;
  1805. fbi->fb.fix.ywrapstep = 0;
  1806. fbi->fb.fix.accel = FB_ACCEL_NONE;
  1807. fbi->fb.var.nonstd = 0;
  1808. fbi->fb.var.activate = FB_ACTIVATE_NOW;
  1809. fbi->fb.var.height = -1;
  1810. fbi->fb.var.width = -1;
  1811. fbi->fb.var.accel_flags = 0;
  1812. fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
  1813. strcpy(fbi->fb.modename, SA1100_NAME);
  1814. strcpy(fbi->fb.fontname, "Acorn8x8");
  1815. fbi->fb.fbops = &sa1100fb_ops;
  1816. fbi->fb.changevar = NULL;
  1817. fbi->fb.switch_con = sa1100fb_switch;
  1818. fbi->fb.updatevar = sa1100fb_updatevar;
  1819. fbi->fb.blank = sa1100fb_blank;
  1820. fbi->fb.flags = FBINFO_FLAG_DEFAULT;
  1821. fbi->fb.node = -1;
  1822. fbi->fb.monspecs = monspecs;
  1823. fbi->fb.disp = (struct display *)(fbi + 1);
  1824. fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
  1825. fbi->rgb[RGB_8] = &rgb_8;
  1826. fbi->rgb[RGB_16] = &def_rgb_16;
  1827. inf = sa1100fb_get_machine_info(fbi);
  1828. fbi->max_xres = inf->xres;
  1829. fbi->fb.var.xres = inf->xres;
  1830. fbi->fb.var.xres_virtual = inf->xres;
  1831. fbi->max_yres = inf->yres;
  1832. fbi->fb.var.yres = inf->yres;
  1833. fbi->fb.var.yres_virtual = inf->yres;
  1834. fbi->max_bpp = inf->bpp;
  1835. fbi->fb.var.bits_per_pixel = inf->bpp;
  1836. fbi->fb.var.pixclock = inf->pixclock;
  1837. fbi->fb.var.hsync_len = inf->hsync_len;
  1838. fbi->fb.var.left_margin = inf->left_margin;
  1839. fbi->fb.var.right_margin = inf->right_margin;
  1840. fbi->fb.var.vsync_len = inf->vsync_len;
  1841. fbi->fb.var.upper_margin = inf->upper_margin;
  1842. fbi->fb.var.lower_margin = inf->lower_margin;
  1843. fbi->fb.var.sync = inf->sync;
  1844. fbi->fb.var.grayscale = inf->cmap_greyscale;
  1845. fbi->cmap_inverse = inf->cmap_inverse;
  1846. fbi->cmap_static = inf->cmap_static;
  1847. fbi->lccr0 = inf->lccr0;
  1848. fbi->lccr3 = inf->lccr3;
  1849. fbi->state = C_DISABLE;
  1850. fbi->task_state = (u_char)-1;
  1851. fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
  1852.   fbi->max_bpp / 8;
  1853. init_waitqueue_head(&fbi->ctrlr_wait);
  1854. INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
  1855. init_MUTEX(&fbi->ctrlr_sem);
  1856. return fbi;
  1857. }
  1858. int __init sa1100fb_init(void)
  1859. {
  1860. struct sa1100fb_info *fbi;
  1861. int ret;
  1862. fbi = sa1100fb_init_fbinfo();
  1863. ret = -ENOMEM;
  1864. if (!fbi)
  1865. goto failed;
  1866. /* Initialize video memory */
  1867. ret = sa1100fb_map_video_memory(fbi);
  1868. if (ret)
  1869. goto failed;
  1870. ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
  1871.   "LCD", fbi);
  1872. if (ret) {
  1873. printk(KERN_ERR "sa1100fb: request_irq failed: %dn", ret);
  1874. goto failed;
  1875. }
  1876. #ifdef ASSABET_PAL_VIDEO
  1877. if (machine_is_assabet())
  1878. ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
  1879. #endif
  1880. #ifdef CONFIG_SA1100_FREEBIRD
  1881. #error Please move this into sa1100fb_power_up_lcd
  1882. if (machine_is_freebird()) {
  1883. BCR_set(BCR_FREEBIRD_LCD_DISP);
  1884. mdelay(20);
  1885. BCR_set(BCR_FREEBIRD_LCD_PWR);
  1886. mdelay(20);
  1887. }
  1888. #endif
  1889. sa1100fb_set_var(&fbi->fb.var, -1, &fbi->fb);
  1890. ret = register_framebuffer(&fbi->fb);
  1891. if (ret < 0)
  1892. goto failed;
  1893. #ifdef CONFIG_PM
  1894. /*
  1895.  * Note that the console registers this as well, but we want to
  1896.  * power down the display prior to sleeping.
  1897.  */
  1898. fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
  1899. if (fbi->pm)
  1900. fbi->pm->data = fbi;
  1901. #endif
  1902. #ifdef CONFIG_CPU_FREQ
  1903. fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
  1904. cpufreq_register_notifier(&fbi->clockchg);
  1905. #endif
  1906. /*
  1907.  * Ok, now enable the LCD controller
  1908.  */
  1909. set_ctrlr_state(fbi, C_ENABLE);
  1910. /* This driver cannot be unloaded at the moment */
  1911. MOD_INC_USE_COUNT;
  1912. return 0;
  1913. failed:
  1914. if (fbi)
  1915. kfree(fbi);
  1916. return ret;
  1917. }
  1918. int __init sa1100fb_setup(char *options)
  1919. {
  1920. #if 0
  1921. char *this_opt;
  1922. if (!options || !*options)
  1923. return 0;
  1924. while ((this_opt = strsep(&options, ",")) != NULL) {
  1925. if (!strncmp(this_opt, "bpp:", 4))
  1926. current_par.max_bpp =
  1927.     simple_strtoul(this_opt + 4, NULL, 0);
  1928. if (!strncmp(this_opt, "lccr0:", 6))
  1929. lcd_shadow.lccr0 =
  1930.     simple_strtoul(this_opt + 6, NULL, 0);
  1931. if (!strncmp(this_opt, "lccr1:", 6)) {
  1932. lcd_shadow.lccr1 =
  1933.     simple_strtoul(this_opt + 6, NULL, 0);
  1934. current_par.max_xres =
  1935.     (lcd_shadow.lccr1 & 0x3ff) + 16;
  1936. }
  1937. if (!strncmp(this_opt, "lccr2:", 6)) {
  1938. lcd_shadow.lccr2 =
  1939.     simple_strtoul(this_opt + 6, NULL, 0);
  1940. current_par.max_yres =
  1941.     (lcd_shadow.
  1942.      lccr0 & LCCR0_SDS) ? ((lcd_shadow.
  1943.     lccr2 & 0x3ff) +
  1944.    1) *
  1945.     2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
  1946. }
  1947. if (!strncmp(this_opt, "lccr3:", 6))
  1948. lcd_shadow.lccr3 =
  1949.     simple_strtoul(this_opt + 6, NULL, 0);
  1950. }
  1951. #endif
  1952. return 0;
  1953. }
  1954. MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver");
  1955. MODULE_LICENSE("GPL");