diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/pm3fb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video/pm3fb.c')
-rw-r--r-- | drivers/video/pm3fb.c | 3646 |
1 files changed, 3646 insertions, 0 deletions
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c new file mode 100644 index 00000000000..8e024aad1b5 --- /dev/null +++ b/drivers/video/pm3fb.c @@ -0,0 +1,3646 @@ +/* + * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device + * + * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr> + * Based on code written by: + * Sven Luther, <luther@dpt-info.u-strasbg.fr> + * Alan Hourihane, <alanh@fairlite.demon.co.uk> + * Russel King, <rmk@arm.linux.org.uk> + * Based on linux/drivers/video/skeletonfb.c: + * Copyright (C) 1997 Geert Uytterhoeven + * Based on linux/driver/video/pm2fb.c: + * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $ + * + * CHANGELOG: + * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. + * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. + * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. + * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings. + * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes. + * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix. + * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG. + * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL. + * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning. + * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option. + * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support. + * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates. + * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup + * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added). + * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian. + * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov). + * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes. + * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option. + * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support. + * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove) + * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix. + * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes. + * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4 + * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested) + * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode + * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up + * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix + * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default + * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix + * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning + * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/ioport.h> + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> +#include <video/fbcon-cfb2.h> +#include <video/fbcon-cfb4.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> +#include <video/pm3fb.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_FB_OF +#include <asm/prom.h> +#endif + +/* ************************************* */ +/* ***** The various "global" data ***** */ +/* ************************************* */ + +/* those will need a rework for multiple board support */ +/* Driver name */ +static const char permedia3_name[16] = "Permedia3"; + +/* the fb_par struct, mandatory */ +struct pm3fb_par { + u32 pixclock; /* pixclock in KHz */ + + u32 width; /* width of virtual screen */ + u32 height; /* height of virtual screen */ + + u32 hsstart; /* horiz. sync start */ + u32 hsend; /* horiz. sync end */ + u32 hbend; /* horiz. blank end (also gate end) */ + u32 htotal; /* total width (w/ sync & blank) */ + + u32 vsstart; /* vert. sync start */ + u32 vsend; /* vert. sync end */ + u32 vbend; /* vert. blank end */ + u32 vtotal; /* total height (w/ sync & blank) */ + + u32 stride; /* screen stride */ + u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ + /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */ + u32 depth; /* screen depth (8, 12, 15, 16 or 32) */ + u32 video; /* video control (hsync,vsync) */ +}; + +/* memory timings */ +struct pm3fb_timings +{ + unsigned long caps; + unsigned long timings; + unsigned long control; + unsigned long refresh; + unsigned long powerdown; +}; +typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result; +#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1) +#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE } + +/* the fb_info struct, mandatory */ +struct pm3fb_info { + struct fb_info_gen gen; + unsigned long board_num; /* internal board number */ + unsigned long use_current; + struct pm3fb_par *current_par; + struct pci_dev *dev; /* PCI device */ + unsigned long board_type; /* index in the cardbase */ + unsigned char *fb_base; /* framebuffer memory base */ + u32 fb_size; /* framebuffer memory size */ + unsigned char *p_fb; /* physical address of frame buffer */ + unsigned char *v_fb; /* virtual address of frame buffer */ + unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ + unsigned char *vIOBase; /* address of registers after ioremap() */ + struct { + u8 transp; + u8 red; + u8 green; + u8 blue; + } palette[256]; + union { +#ifdef FBCON_HAS_CFB16 + u16 cmap12[16]; /* RGBA 4444 */ + u16 cmap15[16]; /* RGBA 5551 */ + u16 cmap16[16]; /* RGBA 5650 */ +#endif +#ifdef FBCON_HAS_CFB32 + u32 cmap32[16]; +#endif + } cmap; + struct pm3fb_timings memt; +}; + +/* regular resolution database*/ +static struct { + char name[16]; + struct pm3fb_par user_mode; +} mode_base[] __initdata = { + { + "default-800x600", { + 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, { + "1024x768-74", { + 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, + 806, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, { + "1024x768-74-32", { + 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, + 806, 1024, 0, 32, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_32BIT}}, +/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/ + { + "SGI1600SW", { + 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32, + 1056, 1600, 0, 8, + PM3VideoControl_ENABLE| + PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW| + PM3VideoControl_PIXELSIZE_32BIT}}, +/* ##### auto-generated mode, by fbtimings2pm3 */ +/* Generated mode : "640x480-60" */ + { + "640x480-60", { + 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45, + 525, 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-72" */ + { + "640x480-72", { + 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520, + 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-75" */ + { + "640x480-75", { + 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500, + 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-90" */ + { + "640x480-90", { + 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533, + 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "640x480-100" */ + { + "640x480-100", { + 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51, + 531, 640, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-48-lace" */ +/* INTERLACED NOT SUPPORTED + {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "800x600-56" */ + { + "800x600-56", { + 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-60" */ + { + "800x600-60", { + 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-70" */ + { + "800x600-70", { + 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36, + 636, 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-72" */ + { + "800x600-72", { + 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66, + 666, 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-75" */ + { + "800x600-75", { + 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-90" */ + { + "800x600-90", { + 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "800x600-100", from /etc/fb.modes */ +/* DISABLED, hsstart == 0 + { + "800x600-100", { + 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625, + 800, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +*/ +/* Generated mode : "800x600-100", from ??? */ + { + "800x600-100", { + 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8, + PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| + PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-43-lace" */ +/* INTERLACED NOT SUPPORTED + {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1024x768-60" */ + { + "1024x768-60", { + 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38, + 806, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-70" */ + { + "1024x768-70", { + 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38, + 806, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-72" */ + { + "1024x768-72", { + 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38, + 806, 10224, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-75" */ + { + "1024x768-75", { + 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32, + 800, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-90" */ + { + "1024x768-90", { + 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77, + 845, 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1024x768-100", from /etc/fb.modes */ +/* DISABLED, vsstart == 0 + { + "1024x768-100", { + 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792, + 1024, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +*/ +/* Generated mode : "1024x768-100", from ??? */ + { + "1024x768-100", { + 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8, + PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| + PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-43-lace" */ +/* INTERLACED NOT SUPPORTED + {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1152x864-47-lace" */ +/* INTERLACED NOT SUPPORTED + {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1152x864-60" */ + { + "1152x864-60", { + 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52, + 916, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-70" */ + { + "1152x864-70", { + 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81, + 945, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-75" */ + { + "1152x864-75", { + 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138, + 1002, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1152x864-80" */ + { + "1152x864-80", { + 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94, + 958, 1152, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-43-lace" */ +/* INTERLACED NOT SUPPORTED + {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1280x1024-47-lace" */ +/* INTERLACED NOT SUPPORTED + {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, + INTERLACED NOT SUPPORTED */ +/* Generated mode : "1280x1024-60" */ + { + "1280x1024-60", { + 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42, + 1066, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-70" */ + { + "1280x1024-70", { + 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42, + 1066, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-74" */ + { + "1280x1024-74", { + 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40, + 1064, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1280x1024-75" */ + { + "1280x1024-75", { + 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42, + 1066, 1280, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_HIGH + | + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1600x1200-60" */ + { + "1600x1200-60", { + 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70, + 1270, 1600, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1600x1200-66" */ + { + "1600x1200-66", { + 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53, + 1253, 1600, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* Generated mode : "1600x1200-76" */ + { + "1600x1200-76", { + 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50, + 1250, 1600, 0, 8, + PM3VideoControl_ENABLE | + PM3VideoControl_HSYNC_ACTIVE_LOW + | + PM3VideoControl_VSYNC_ACTIVE_LOW + | PM3VideoControl_PIXELSIZE_8BIT}}, +/* ##### end of auto-generated mode */ + { + "\0",} +}; + +/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */ +static struct pm3fb_info fb_info[PM3_MAX_BOARD]; +static struct pm3fb_par current_par[PM3_MAX_BOARD]; +static int current_par_valid[PM3_MAX_BOARD]; +/* to allow explicit filtering of board */ +short bus[PM3_MAX_BOARD]; +short slot[PM3_MAX_BOARD]; +short func[PM3_MAX_BOARD]; +short disable[PM3_MAX_BOARD]; +short noaccel[PM3_MAX_BOARD]; +char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE]; +short depth[PM3_MAX_BOARD]; +short flatpanel[PM3_MAX_BOARD]; +static struct display disp[PM3_MAX_BOARD]; +static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy"; +short printtimings = 0; +short forcesize[PM3_MAX_BOARD]; + +/* ********************* */ +/* ***** prototype ***** */ +/* ********************* */ +/* card-specific */ +static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info); +/* permedia3-specific */ +static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); +static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info); +static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info); +static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, + unsigned long r); +static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ + unsigned long refclock, /* In kHz units */ + unsigned char *prescale, /* ClkPreScale */ + unsigned char *feedback, /* ClkFeedBackScale */ + unsigned char *postscale + /* ClkPostScale */ ); +static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc); +static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b); +static void pm3fb_common_init(struct pm3fb_info *l_fb_info); +static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v); +static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v); +static void pm3fb_mapIO(struct pm3fb_info *l_fb_info); +static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info); +#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) +static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info); +#endif +static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info); +static void pm3fb_write_mode(struct pm3fb_info *l_fb_info); +static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, + struct pm3fb_par *curpar); +static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info); +/* accelerated permedia3-specific */ +#ifdef PM3FB_USE_ACCEL +static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info); +static void pm3fb_init_engine(struct pm3fb_info *l_fb_info); +#ifdef FBCON_HAS_CFB32 +static void pm3fb_cfb32_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width); +static void pm3fb_cfb32_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only); +#endif /* FBCON_HAS_CFB32 */ +#ifdef FBCON_HAS_CFB16 +static void pm3fb_cfb16_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width); +static void pm3fb_cfb16_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only); +#endif /* FBCON_HAS_CFB16 */ +#ifdef FBCON_HAS_CFB8 +static void pm3fb_cfb8_clear(struct vc_data *conp, + struct display *p, + int sy, int sx, int height, int width); +static void pm3fb_cfb8_clear_margins(struct vc_data *conp, + struct display *p, int bottom_only); +#endif /* FBCON_HAS_CFB8 */ +#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) +static void pm3fb_cfbX_bmove(struct display *p, + int sy, int sx, + int dy, int dx, int height, int width); +static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, + int c, int yy, int xx); +static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, + int xx); +static void pm3fb_cfbX_revc(struct display *p, int xx, int yy); +#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ +#endif /* PM3FB_USE_ACCEL */ +/* pre-init */ +static void pm3fb_mode_setup(char *mode, unsigned long board_num); +static void pm3fb_pciid_setup(char *pciid, unsigned long board_num); +static char *pm3fb_boardnum_setup(char *options, unsigned long *bn); +static void pm3fb_real_setup(char *options); +/* fbdev */ +static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, + const void *par, struct fb_info_gen *info); +static int pm3fb_decode_var(const struct fb_var_screeninfo *var, + void *par, struct fb_info_gen *info); +static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d); +static int pm3fb_encode_var(struct fb_var_screeninfo *var, + const void *par, struct fb_info_gen *info); +static void pm3fb_get_par(void *par, struct fb_info_gen *info); +static void pm3fb_set_par(const void *par, struct fb_info_gen *info); +static void pm3fb_set_color(struct pm3fb_info *l_fb_info, + unsigned char regno, unsigned char r, + unsigned char g, unsigned char b); +static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *info); +static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); +static int pm3fb_blank(int blank_mode, struct fb_info_gen *info); +static void pm3fb_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info); +static void pm3fb_detect(void); +static int pm3fb_pan_display(const struct fb_var_screeninfo *var, + struct fb_info_gen *info); +static int pm3fb_ioctl(struct inode *inode, struct file *file, + u_int cmd, u_long arg, int con, + struct fb_info *info); + + +/* the struct that hold them together */ +struct fbgen_hwswitch pm3fb_switch = { + pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var, + pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, + pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp +}; + +static struct fb_ops pm3fb_ops = { + .owner = THIS_MODULE, + .fb_get_fix = fbgen_get_fix, + .fb_get_var = fbgen_get_var, + .fb_set_var = fbgen_set_var, + .fb_get_cmap = fbgen_get_cmap, + .fb_set_cmap = fbgen_set_cmap, + .fb_setcolreg = pm3fb_setcolreg, + .fb_pan_display =fbgen_pan_display, + .fb_blank = fbgen_blank, + .fb_ioctl = pm3fb_ioctl, +}; + +#ifdef PM3FB_USE_ACCEL +#ifdef FBCON_HAS_CFB32 +static struct display_switch pm3fb_cfb32 = { + fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear, + pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, + NULL /* cursor() */ , NULL /* set_font() */ , + pm3fb_cfb32_clear_margins, + FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ +}; +#endif /* FBCON_HAS_CFB32 */ +#ifdef FBCON_HAS_CFB16 +static struct display_switch pm3fb_cfb16 = { + fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear, + pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, + NULL /* cursor() */ , NULL /* set_font() */ , + pm3fb_cfb16_clear_margins, + FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ +}; +#endif /* FBCON_HAS_CFB16 */ +#ifdef FBCON_HAS_CFB8 +static struct display_switch pm3fb_cfb8 = { + fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear, + pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, + NULL /* cursor() */ , NULL /* set_font() */ , + pm3fb_cfb8_clear_margins, + FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ +}; +#endif /* FBCON_HAS_CFB8 */ +#endif /* PM3FB_USE_ACCEL */ + +/* ****************************** */ +/* ***** card-specific data ***** */ +/* ****************************** */ +struct pm3fb_card_timings { + unsigned long memsize; /* 0 for last value (i.e. default) */ + struct pm3fb_timings memt; +}; + +static struct pm3fb_card_timings t_FormacProFormance3[] = { + { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} }, + { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */ +}; + +static struct pm3fb_card_timings t_AppianJeronimo2000[] = { + { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} }, + { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */ +}; + +static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = { + { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} }, + { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */ +}; + +static struct { + char cardname[32]; /* recognized card name */ + u16 subvendor; /* subvendor of the card */ + u16 subdevice; /* subdevice of the card */ + u8 func; /* function of the card to which the extra init apply */ + void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */ + struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */ +} cardbase[] = { + { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL }, + { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, + t_AppianJeronimo2000 + }, + { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup, + t_AppianJeronimo2000 + }, + { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */ + t_FormacProFormance3 + }, + { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL }, + { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL, + t_3DLabsOxygenVX1 + }, + { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL }, + { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL }, + { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL }, + { "\0", 0x0, 0x0, 0, NULL, NULL } +}; + +/* ********************************** */ +/* ***** card-specific function ***** */ +/* ********************************** */ +static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info) +{ /* the appian j2000 require more initialization of the second head */ + /* l_fb_info must point to the _second_ head of the J2000 */ + + DTRACE; + + l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */ + + pm3fb_write_memory_timings(l_fb_info); +} + +/* *************************************** */ +/* ***** permedia3-specific function ***** */ +/* *************************************** */ +static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) +{ + l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps); + l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings); + l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl); + l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh); + l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown); + + if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) || + (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE)) + { + printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num); + return(pm3fb_try_memory_timings(l_fb_info)); + } + return(pm3fb_timing_ok); +} + +static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) +{ + if (cardbase[l_fb_info->board_type].c_memt) + { + int i = 0, done = 0; + while (!done) + { + if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size) + || !(cardbase[l_fb_info->board_type].c_memt[i].memsize)) + { /* will use the 0-sized timings by default */ + done = 1; + l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt; + printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n", + l_fb_info->board_num, + cardbase[l_fb_info->board_type].cardname, + cardbase[l_fb_info->board_type].c_memt[i].memsize); + pm3fb_write_memory_timings(l_fb_info); + return(pm3fb_timing_retry); + } + i++; + } + } else + return(pm3fb_timing_problem); + return(pm3fb_timing_ok); +} + +static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) +{ + unsigned char m, n, p; + unsigned long clockused; + + PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps); + PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings); + PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control); + PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh); + PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown); + + clockused = + pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m, + &n, &p); + + PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m); + PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n); + PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p); + PM3_WRITE_DAC_REG(PM3RD_KClkControl, + PM3RD_KClkControl_STATE_RUN | + PM3RD_KClkControl_SOURCE_PLL | + PM3RD_KClkControl_ENABLE); + PM3_WRITE_DAC_REG(PM3RD_MClkControl, + PM3RD_MClkControl_STATE_RUN | + PM3RD_MClkControl_SOURCE_KCLK | + PM3RD_MClkControl_ENABLE); + PM3_WRITE_DAC_REG(PM3RD_SClkControl, + PM3RD_SClkControl_STATE_RUN | + PM3RD_SClkControl_SOURCE_PCLK | + PM3RD_SClkControl_ENABLE); +} + +static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, + unsigned long r) +{ + DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)), + "l_fb_info->vIOBase mapped in read dac reg\n"); + PM3_SET_INDEX(r); + mb(); + return (PM3_READ_REG(PM3RD_IndexedData)); +} + +/* Calculating various clock parameter */ +static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ + unsigned long refclock, /* In kHz units */ + unsigned char *prescale, /* ClkPreScale */ + unsigned char *feedback, /* ClkFeedBackScale */ + unsigned char *postscale + /* ClkPostScale */ ) +{ + int f, pre, post; + unsigned long freq; + long freqerr = 1000; + unsigned long actualclock = 0; + + DTRACE; + + for (f = 1; f < 256; f++) { + for (pre = 1; pre < 256; pre++) { + for (post = 0; post < 5; post++) { + freq = + ((2 * refclock * f) / + (pre * (1 << post))); + if ((reqclock > freq - freqerr) + && (reqclock < freq + freqerr)) { + freqerr = + (reqclock > + freq) ? reqclock - + freq : freq - reqclock; + *feedback = f; + *prescale = pre; + *postscale = post; + actualclock = freq; + } + } + } + } + + return (actualclock); +} + +static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v) +{ + DTRACE; + + switch (depth) { + case 8: + return (v >> 4); + case 12: + case 15: + case 16: + return (v >> 3); + case 32: + return (v >> 2); + } + DPRINTK(1, "Unsupported depth %ld\n", depth); + return (0); +} + +static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, + unsigned long depth, int v) +{ + DTRACE; + + switch (depth) { + case 8: + return (v << 4); + case 12: + case 15: + case 16: + return (v << 3); + case 32: + return (v << 2); + } + DPRINTK(1, "Unsupported depth %ld\n", depth); + return (0); +} + +static void pm3fb_mapIO(struct pm3fb_info *l_fb_info) +{ + DTRACE; + + l_fb_info->vIOBase = + ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE); + l_fb_info->v_fb = + ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size); + DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n", + (unsigned long) l_fb_info->pIOBase, + (unsigned long) l_fb_info->vIOBase, + (unsigned long) l_fb_info->p_fb, + (unsigned long) l_fb_info->v_fb); +} + +static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info) +{ + DTRACE; + + iounmap(l_fb_info->vIOBase); + iounmap(l_fb_info->v_fb); + l_fb_info->vIOBase = (unsigned char *) -1; + l_fb_info->v_fb = (unsigned char *) -1; +} + +#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) +static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info) +{ + DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0)); + DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1)); + DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n", + PM3_READ_REG |