cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

macfb.c (22554B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
      4 * don't know how to set.
      5 *
      6 * (c) 1999 David Huggins-Daines <dhd@debian.org>
      7 *
      8 * Primarily based on vesafb.c, by Gerd Knorr
      9 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
     10 *
     11 * Also uses information and code from:
     12 *
     13 * The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
     14 * Mellinger, Mikael Forselius, Michael Schmitz, and others.
     15 *
     16 * valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
     17 * Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
     18 *
     19 * The VideoToolbox "Bugs" web page at
     20 * http://rajsky.psych.nyu.edu/Tips/VideoBugs.html
     21 */
     22
     23#include <linux/module.h>
     24#include <linux/kernel.h>
     25#include <linux/errno.h>
     26#include <linux/string.h>
     27#include <linux/mm.h>
     28#include <linux/delay.h>
     29#include <linux/nubus.h>
     30#include <linux/init.h>
     31#include <linux/fb.h>
     32
     33#include <asm/setup.h>
     34#include <asm/macintosh.h>
     35#include <asm/io.h>
     36
     37/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
     38#define DAC_BASE 0x50f24000
     39
     40/* Some addresses for the DAFB */
     41#define DAFB_BASE 0xf9800200
     42
     43/* Address for the built-in Civic framebuffer in Quadra AVs */
     44#define CIVIC_BASE 0x50f30800
     45
     46/* GSC (Gray Scale Controller) base address */
     47#define GSC_BASE 0x50F20000
     48
     49/* CSC (Color Screen Controller) base address */
     50#define CSC_BASE 0x50F20000
     51
     52static int (*macfb_setpalette)(unsigned int regno, unsigned int red,
     53			       unsigned int green, unsigned int blue,
     54			       struct fb_info *info);
     55
     56static struct {
     57	unsigned char addr;
     58	unsigned char lut;
     59} __iomem *v8_brazil_cmap_regs;
     60
     61static struct {
     62	unsigned char addr;
     63	char pad1[3]; /* word aligned */
     64	unsigned char lut;
     65	char pad2[3]; /* word aligned */
     66	unsigned char cntl; /* a guess as to purpose */
     67} __iomem *rbv_cmap_regs;
     68
     69static struct {
     70	unsigned long reset;
     71	unsigned long pad1[3];
     72	unsigned char pad2[3];
     73	unsigned char lut;
     74} __iomem *dafb_cmap_regs;
     75
     76static struct {
     77	unsigned char addr;	/* OFFSET: 0x00 */
     78	unsigned char pad1[15];
     79	unsigned char lut;	/* OFFSET: 0x10 */
     80	unsigned char pad2[15];
     81	unsigned char status;	/* OFFSET: 0x20 */
     82	unsigned char pad3[7];
     83	unsigned long vbl_addr;	/* OFFSET: 0x28 */
     84	unsigned int  status2;	/* OFFSET: 0x2C */
     85} __iomem *civic_cmap_regs;
     86
     87static struct {
     88	char pad1[0x40];
     89	unsigned char clut_waddr;	/* 0x40 */
     90	char pad2;
     91	unsigned char clut_data;	/* 0x42 */
     92	char pad3[0x3];
     93	unsigned char clut_raddr;	/* 0x46 */
     94} __iomem *csc_cmap_regs;
     95
     96/* The registers in these structs are in NuBus slot space */
     97struct mdc_cmap_regs {
     98	char pad1[0x200200];
     99	unsigned char addr;
    100	char pad2[6];
    101	unsigned char lut;
    102};
    103
    104struct toby_cmap_regs {
    105	char pad1[0x90018];
    106	unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
    107	char pad2[3];
    108	unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
    109};
    110
    111struct jet_cmap_regs {
    112	char pad1[0xe0e000];
    113	unsigned char addr;
    114	unsigned char lut;
    115};
    116
    117#define PIXEL_TO_MM(a)	(((a)*10)/28)	/* width in mm at 72 dpi */
    118
    119static struct fb_var_screeninfo macfb_defined = {
    120	.activate	= FB_ACTIVATE_NOW,
    121	.right_margin	= 32,
    122	.upper_margin	= 16,
    123	.lower_margin	= 4,
    124	.vsync_len	= 4,
    125	.vmode		= FB_VMODE_NONINTERLACED,
    126};
    127
    128static struct fb_fix_screeninfo macfb_fix = {
    129	.type	= FB_TYPE_PACKED_PIXELS,
    130	.accel	= FB_ACCEL_NONE,
    131};
    132
    133static void *slot_addr;
    134static struct fb_info fb_info;
    135static u32 pseudo_palette[16];
    136static int vidtest;
    137
    138/*
    139 * Unlike the Valkyrie, the DAFB cannot set individual colormap
    140 * registers.  Therefore, we do what the MacOS driver does (no
    141 * kidding!) and simply set them one by one until we hit the one we
    142 * want.
    143 */
    144static int dafb_setpalette(unsigned int regno, unsigned int red,
    145			   unsigned int green, unsigned int blue,
    146			   struct fb_info *info)
    147{
    148	static int lastreg = -2;
    149	unsigned long flags;
    150
    151	local_irq_save(flags);
    152
    153	/*
    154	 * fbdev will set an entire colourmap, but X won't.  Hopefully
    155	 * this should accommodate both of them
    156	 */
    157	if (regno != lastreg + 1) {
    158		int i;
    159
    160		/* Stab in the dark trying to reset the CLUT pointer */
    161		nubus_writel(0, &dafb_cmap_regs->reset);
    162		nop();
    163
    164		/* Loop until we get to the register we want */
    165		for (i = 0; i < regno; i++) {
    166			nubus_writeb(info->cmap.red[i] >> 8,
    167				     &dafb_cmap_regs->lut);
    168			nop();
    169			nubus_writeb(info->cmap.green[i] >> 8,
    170				     &dafb_cmap_regs->lut);
    171			nop();
    172			nubus_writeb(info->cmap.blue[i] >> 8,
    173				     &dafb_cmap_regs->lut);
    174			nop();
    175		}
    176	}
    177
    178	nubus_writeb(red, &dafb_cmap_regs->lut);
    179	nop();
    180	nubus_writeb(green, &dafb_cmap_regs->lut);
    181	nop();
    182	nubus_writeb(blue, &dafb_cmap_regs->lut);
    183
    184	local_irq_restore(flags);
    185	lastreg = regno;
    186	return 0;
    187}
    188
    189/* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
    190static int v8_brazil_setpalette(unsigned int regno, unsigned int red,
    191				unsigned int green, unsigned int blue,
    192				struct fb_info *info)
    193{
    194	unsigned int bpp = info->var.bits_per_pixel;
    195	unsigned long flags;
    196
    197	local_irq_save(flags);
    198
    199	/* On these chips, the CLUT register numbers are spread out
    200	 * across the register space.  Thus:
    201	 * In 8bpp, all regnos are valid.
    202	 * In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
    203	 * In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff
    204	 */
    205	regno = (regno << (8 - bpp)) | (0xFF >> bpp);
    206	nubus_writeb(regno, &v8_brazil_cmap_regs->addr);
    207	nop();
    208
    209	/* send one color channel at a time */
    210	nubus_writeb(red, &v8_brazil_cmap_regs->lut);
    211	nop();
    212	nubus_writeb(green, &v8_brazil_cmap_regs->lut);
    213	nop();
    214	nubus_writeb(blue, &v8_brazil_cmap_regs->lut);
    215
    216	local_irq_restore(flags);
    217	return 0;
    218}
    219
    220/* RAM-Based Video */
    221static int rbv_setpalette(unsigned int regno, unsigned int red,
    222			  unsigned int green, unsigned int blue,
    223			  struct fb_info *info)
    224{
    225	unsigned long flags;
    226
    227	local_irq_save(flags);
    228
    229	/* From the VideoToolbox driver.  Seems to be saying that
    230	 * regno #254 and #255 are the important ones for 1-bit color,
    231	 * regno #252-255 are the important ones for 2-bit color, etc.
    232	 */
    233	regno += 256 - (1 << info->var.bits_per_pixel);
    234
    235	/* reset clut? (VideoToolbox sez "not necessary") */
    236	nubus_writeb(0xFF, &rbv_cmap_regs->cntl);
    237	nop();
    238
    239	/* tell clut which address to use. */
    240	nubus_writeb(regno, &rbv_cmap_regs->addr);
    241	nop();
    242
    243	/* send one color channel at a time. */
    244	nubus_writeb(red, &rbv_cmap_regs->lut);
    245	nop();
    246	nubus_writeb(green, &rbv_cmap_regs->lut);
    247	nop();
    248	nubus_writeb(blue, &rbv_cmap_regs->lut);
    249
    250	local_irq_restore(flags);
    251	return 0;
    252}
    253
    254/* Macintosh Display Card (8*24) */
    255static int mdc_setpalette(unsigned int regno, unsigned int red,
    256			  unsigned int green, unsigned int blue,
    257			  struct fb_info *info)
    258{
    259	struct mdc_cmap_regs *cmap_regs = slot_addr;
    260	unsigned long flags;
    261
    262	local_irq_save(flags);
    263
    264	/* the nop's are there to order writes. */
    265	nubus_writeb(regno, &cmap_regs->addr);
    266	nop();
    267	nubus_writeb(red, &cmap_regs->lut);
    268	nop();
    269	nubus_writeb(green, &cmap_regs->lut);
    270	nop();
    271	nubus_writeb(blue, &cmap_regs->lut);
    272
    273	local_irq_restore(flags);
    274	return 0;
    275}
    276
    277/* Toby frame buffer */
    278static int toby_setpalette(unsigned int regno, unsigned int red,
    279			   unsigned int green, unsigned int blue,
    280			   struct fb_info *info)
    281{
    282	struct toby_cmap_regs *cmap_regs = slot_addr;
    283	unsigned int bpp = info->var.bits_per_pixel;
    284	unsigned long flags;
    285
    286	red = ~red;
    287	green = ~green;
    288	blue = ~blue;
    289	regno = (regno << (8 - bpp)) | (0xFF >> bpp);
    290
    291	local_irq_save(flags);
    292
    293	nubus_writeb(regno, &cmap_regs->addr);
    294	nop();
    295	nubus_writeb(red, &cmap_regs->lut);
    296	nop();
    297	nubus_writeb(green, &cmap_regs->lut);
    298	nop();
    299	nubus_writeb(blue, &cmap_regs->lut);
    300
    301	local_irq_restore(flags);
    302	return 0;
    303}
    304
    305/* Jet frame buffer */
    306static int jet_setpalette(unsigned int regno, unsigned int red,
    307			  unsigned int green, unsigned int blue,
    308			  struct fb_info *info)
    309{
    310	struct jet_cmap_regs *cmap_regs = slot_addr;
    311	unsigned long flags;
    312
    313	local_irq_save(flags);
    314
    315	nubus_writeb(regno, &cmap_regs->addr);
    316	nop();
    317	nubus_writeb(red, &cmap_regs->lut);
    318	nop();
    319	nubus_writeb(green, &cmap_regs->lut);
    320	nop();
    321	nubus_writeb(blue, &cmap_regs->lut);
    322
    323	local_irq_restore(flags);
    324	return 0;
    325}
    326
    327/*
    328 * Civic framebuffer -- Quadra AV built-in video.  A chip
    329 * called Sebastian holds the actual color palettes, and
    330 * apparently, there are two different banks of 512K RAM
    331 * which can act as separate framebuffers for doing video
    332 * input and viewing the screen at the same time!  The 840AV
    333 * Can add another 1MB RAM to give the two framebuffers
    334 * 1MB RAM apiece.
    335 */
    336static int civic_setpalette(unsigned int regno, unsigned int red,
    337			    unsigned int green, unsigned int blue,
    338			    struct fb_info *info)
    339{
    340	unsigned long flags;
    341	int clut_status;
    342	
    343	local_irq_save(flags);
    344
    345	/* Set the register address */
    346	nubus_writeb(regno, &civic_cmap_regs->addr);
    347	nop();
    348
    349	/*
    350	 * Grab a status word and do some checking;
    351	 * Then finally write the clut!
    352	 */
    353	clut_status =  nubus_readb(&civic_cmap_regs->status2);
    354
    355	if ((clut_status & 0x0008) == 0)
    356	{
    357#if 0
    358		if ((clut_status & 0x000D) != 0)
    359		{
    360			nubus_writeb(0x00, &civic_cmap_regs->lut);
    361			nop();
    362			nubus_writeb(0x00, &civic_cmap_regs->lut);
    363			nop();
    364		}
    365#endif
    366
    367		nubus_writeb(red, &civic_cmap_regs->lut);
    368		nop();
    369		nubus_writeb(green, &civic_cmap_regs->lut);
    370		nop();
    371		nubus_writeb(blue, &civic_cmap_regs->lut);
    372		nop();
    373		nubus_writeb(0x00, &civic_cmap_regs->lut);
    374	}
    375	else
    376	{
    377		unsigned char junk;
    378
    379		junk = nubus_readb(&civic_cmap_regs->lut);
    380		nop();
    381		junk = nubus_readb(&civic_cmap_regs->lut);
    382		nop();
    383		junk = nubus_readb(&civic_cmap_regs->lut);
    384		nop();
    385		junk = nubus_readb(&civic_cmap_regs->lut);
    386		nop();
    387
    388		if ((clut_status & 0x000D) != 0)
    389		{
    390			nubus_writeb(0x00, &civic_cmap_regs->lut);
    391			nop();
    392			nubus_writeb(0x00, &civic_cmap_regs->lut);
    393			nop();
    394		}
    395
    396		nubus_writeb(red, &civic_cmap_regs->lut);
    397		nop();
    398		nubus_writeb(green, &civic_cmap_regs->lut);
    399		nop();
    400		nubus_writeb(blue, &civic_cmap_regs->lut);
    401		nop();
    402		nubus_writeb(junk, &civic_cmap_regs->lut);
    403	}
    404
    405	local_irq_restore(flags);
    406	return 0;
    407}
    408
    409/*
    410 * The CSC is the framebuffer on the PowerBook 190 series
    411 * (and the 5300 too, but that's a PowerMac). This function
    412 * brought to you in part by the ECSC driver for MkLinux.
    413 */
    414static int csc_setpalette(unsigned int regno, unsigned int red,
    415			  unsigned int green, unsigned int blue,
    416			  struct fb_info *info)
    417{
    418	unsigned long flags;
    419
    420	local_irq_save(flags);
    421
    422	udelay(1); /* mklinux on PB 5300 waits for 260 ns */
    423	nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
    424	nubus_writeb(red, &csc_cmap_regs->clut_data);
    425	nubus_writeb(green, &csc_cmap_regs->clut_data);
    426	nubus_writeb(blue, &csc_cmap_regs->clut_data);
    427
    428	local_irq_restore(flags);
    429	return 0;
    430}
    431
    432static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
    433			   unsigned blue, unsigned transp,
    434			   struct fb_info *fb_info)
    435{
    436	/*
    437	 * Set a single color register. The values supplied are
    438	 * already rounded down to the hardware's capabilities
    439	 * (according to the entries in the `var' structure).
    440	 * Return non-zero for invalid regno.
    441	 */
    442	
    443	if (regno >= fb_info->cmap.len)
    444		return 1;
    445
    446	if (fb_info->var.bits_per_pixel <= 8) {
    447		switch (fb_info->var.bits_per_pixel) {
    448		case 1:
    449			/* We shouldn't get here */
    450			break;
    451		case 2:
    452		case 4:
    453		case 8:
    454			if (macfb_setpalette)
    455				macfb_setpalette(regno, red >> 8, green >> 8,
    456						 blue >> 8, fb_info);
    457			else
    458				return 1;
    459			break;
    460		}
    461	} else if (regno < 16) {
    462		switch (fb_info->var.bits_per_pixel) {
    463		case 16:
    464			if (fb_info->var.red.offset == 10) {
    465				/* 1:5:5:5 */
    466				((u32*) (fb_info->pseudo_palette))[regno] =
    467					((red   & 0xf800) >>  1) |
    468					((green & 0xf800) >>  6) |
    469					((blue  & 0xf800) >> 11) |
    470					((transp != 0) << 15);
    471			} else {
    472				/* 0:5:6:5 */
    473				((u32*) (fb_info->pseudo_palette))[regno] =
    474					((red   & 0xf800) >>  0) |
    475					((green & 0xfc00) >>  5) |
    476					((blue  & 0xf800) >> 11);
    477			}
    478			break;
    479		/*
    480		 * 24-bit colour almost doesn't exist on 68k Macs --
    481		 * https://support.apple.com/kb/TA28634 (Old Article: 10992)
    482		 */
    483		case 24:
    484		case 32:
    485			red   >>= 8;
    486			green >>= 8;
    487			blue  >>= 8;
    488			((u32 *)(fb_info->pseudo_palette))[regno] =
    489				(red   << fb_info->var.red.offset) |
    490				(green << fb_info->var.green.offset) |
    491				(blue  << fb_info->var.blue.offset);
    492			break;
    493		}
    494	}
    495
    496	return 0;
    497}
    498
    499static const struct fb_ops macfb_ops = {
    500	.owner		= THIS_MODULE,
    501	.fb_setcolreg	= macfb_setcolreg,
    502	.fb_fillrect	= cfb_fillrect,
    503	.fb_copyarea	= cfb_copyarea,
    504	.fb_imageblit	= cfb_imageblit,
    505};
    506
    507static void __init macfb_setup(char *options)
    508{
    509	char *this_opt;
    510
    511	if (!options || !*options)
    512		return;
    513
    514	while ((this_opt = strsep(&options, ",")) != NULL) {
    515		if (!*this_opt)
    516			continue;
    517
    518		if (!strcmp(this_opt, "inverse"))
    519			fb_invert_cmaps();
    520		else
    521			if (!strcmp(this_opt, "vidtest"))
    522				vidtest = 1; /* enable experimental CLUT code */
    523	}
    524}
    525
    526static void __init iounmap_macfb(void)
    527{
    528	if (dafb_cmap_regs)
    529		iounmap(dafb_cmap_regs);
    530	if (v8_brazil_cmap_regs)
    531		iounmap(v8_brazil_cmap_regs);
    532	if (rbv_cmap_regs)
    533		iounmap(rbv_cmap_regs);
    534	if (civic_cmap_regs)
    535		iounmap(civic_cmap_regs);
    536	if (csc_cmap_regs)
    537		iounmap(csc_cmap_regs);
    538}
    539
    540static int __init macfb_init(void)
    541{
    542	int video_cmap_len, video_is_nubus = 0;
    543	struct nubus_rsrc *ndev = NULL;
    544	char *option = NULL;
    545	int err;
    546
    547	if (fb_get_options("macfb", &option))
    548		return -ENODEV;
    549	macfb_setup(option);
    550
    551	if (!MACH_IS_MAC) 
    552		return -ENODEV;
    553
    554	if (mac_bi_data.id == MAC_MODEL_Q630 ||
    555	    mac_bi_data.id == MAC_MODEL_P588)
    556		return -ENODEV; /* See valkyriefb.c */
    557
    558	macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
    559	macfb_defined.yres = mac_bi_data.dimensions >> 16;
    560	macfb_defined.bits_per_pixel = mac_bi_data.videodepth;
    561
    562	macfb_fix.line_length = mac_bi_data.videorow;
    563	macfb_fix.smem_len    = macfb_fix.line_length * macfb_defined.yres;
    564	/* Note: physical address (since 2.1.127) */
    565	macfb_fix.smem_start  = mac_bi_data.videoaddr;
    566
    567	/*
    568	 * This is actually redundant with the initial mappings.
    569	 * However, there are some non-obvious aspects to the way
    570	 * those mappings are set up, so this is in fact the safest
    571	 * way to ensure that this driver will work on every possible Mac
    572	 */
    573	fb_info.screen_base = ioremap(mac_bi_data.videoaddr,
    574				      macfb_fix.smem_len);
    575	if (!fb_info.screen_base)
    576		return -ENODEV;
    577
    578	pr_info("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
    579	        macfb_fix.smem_start, fb_info.screen_base,
    580	        macfb_fix.smem_len / 1024);
    581	pr_info("macfb: mode is %dx%dx%d, linelength=%d\n",
    582	        macfb_defined.xres, macfb_defined.yres,
    583	        macfb_defined.bits_per_pixel, macfb_fix.line_length);
    584
    585	/* Fill in the available video resolution */
    586	macfb_defined.xres_virtual = macfb_defined.xres;
    587	macfb_defined.yres_virtual = macfb_defined.yres;
    588	macfb_defined.height       = PIXEL_TO_MM(macfb_defined.yres);
    589	macfb_defined.width        = PIXEL_TO_MM(macfb_defined.xres);
    590
    591	/* Some dummy values for timing to make fbset happy */
    592	macfb_defined.pixclock     = 10000000 / macfb_defined.xres *
    593				     1000 / macfb_defined.yres;
    594	macfb_defined.left_margin  = (macfb_defined.xres / 8) & 0xf8;
    595	macfb_defined.hsync_len    = (macfb_defined.xres / 8) & 0xf8;
    596
    597	switch (macfb_defined.bits_per_pixel) {
    598	case 1:
    599		macfb_defined.red.length = macfb_defined.bits_per_pixel;
    600		macfb_defined.green.length = macfb_defined.bits_per_pixel;
    601		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
    602		video_cmap_len = 2;
    603		macfb_fix.visual = FB_VISUAL_MONO01;
    604		break;
    605	case 2:
    606	case 4:
    607	case 8:
    608		macfb_defined.red.length = macfb_defined.bits_per_pixel;
    609		macfb_defined.green.length = macfb_defined.bits_per_pixel;
    610		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
    611		video_cmap_len = 1 << macfb_defined.bits_per_pixel;
    612		macfb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
    613		break;
    614	case 16:
    615		macfb_defined.transp.offset = 15;
    616		macfb_defined.transp.length = 1;
    617		macfb_defined.red.offset = 10;
    618		macfb_defined.red.length = 5;
    619		macfb_defined.green.offset = 5;
    620		macfb_defined.green.length = 5;
    621		macfb_defined.blue.offset = 0;
    622		macfb_defined.blue.length = 5;
    623		video_cmap_len = 16;
    624		/*
    625		 * Should actually be FB_VISUAL_DIRECTCOLOR, but this
    626		 * works too
    627		 */
    628		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
    629		break;
    630	case 24:
    631	case 32:
    632		macfb_defined.red.offset = 16;
    633		macfb_defined.red.length = 8;
    634		macfb_defined.green.offset = 8;
    635		macfb_defined.green.length = 8;
    636		macfb_defined.blue.offset = 0;
    637		macfb_defined.blue.length = 8;
    638		video_cmap_len = 16;
    639		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
    640		break;
    641	default:
    642		pr_err("macfb: unknown or unsupported bit depth: %d\n",
    643		       macfb_defined.bits_per_pixel);
    644		err = -EINVAL;
    645		goto fail_unmap;
    646	}
    647	
    648	/*
    649	 * We take a wild guess that if the video physical address is
    650	 * in nubus slot space, that the nubus card is driving video.
    651	 * Penguin really ought to tell us whether we are using internal
    652	 * video or not.
    653	 * Hopefully we only find one of them.  Otherwise our NuBus
    654	 * code is really broken :-)
    655	 */
    656
    657	for_each_func_rsrc(ndev) {
    658		unsigned long base = ndev->board->slot_addr;
    659
    660		if (mac_bi_data.videoaddr < base ||
    661		    mac_bi_data.videoaddr - base > 0xFFFFFF)
    662			continue;
    663
    664		if (ndev->category != NUBUS_CAT_DISPLAY ||
    665		    ndev->type != NUBUS_TYPE_VIDEO)
    666			continue;
    667
    668		video_is_nubus = 1;
    669		slot_addr = (unsigned char *)base;
    670
    671		switch(ndev->dr_hw) {
    672		case NUBUS_DRHW_APPLE_MDC:
    673			strcpy(macfb_fix.id, "Mac Disp. Card");
    674			macfb_setpalette = mdc_setpalette;
    675			break;
    676		case NUBUS_DRHW_APPLE_TFB:
    677			strcpy(macfb_fix.id, "Toby");
    678			macfb_setpalette = toby_setpalette;
    679			break;
    680		case NUBUS_DRHW_APPLE_JET:
    681			strcpy(macfb_fix.id, "Jet");
    682			macfb_setpalette = jet_setpalette;
    683			break;
    684		default:
    685			strcpy(macfb_fix.id, "Generic NuBus");
    686			break;
    687		}
    688	}
    689
    690	/* If it's not a NuBus card, it must be internal video */
    691	if (!video_is_nubus)
    692		switch (mac_bi_data.id) {
    693		/*
    694		 * DAFB Quadras
    695		 * Note: these first four have the v7 DAFB, which is
    696		 * known to be rather unlike the ones used in the
    697		 * other models
    698		 */
    699		case MAC_MODEL_P475:
    700		case MAC_MODEL_P475F:
    701		case MAC_MODEL_P575:
    702		case MAC_MODEL_Q605:
    703
    704		case MAC_MODEL_Q800:
    705		case MAC_MODEL_Q650:
    706		case MAC_MODEL_Q610:
    707		case MAC_MODEL_C650:
    708		case MAC_MODEL_C610:
    709		case MAC_MODEL_Q700:
    710		case MAC_MODEL_Q900:
    711		case MAC_MODEL_Q950:
    712			strcpy(macfb_fix.id, "DAFB");
    713			macfb_setpalette = dafb_setpalette;
    714			dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
    715			break;
    716
    717		/*
    718		 * LC II uses the V8 framebuffer
    719		 */
    720		case MAC_MODEL_LCII:
    721			strcpy(macfb_fix.id, "V8");
    722			macfb_setpalette = v8_brazil_setpalette;
    723			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
    724			break;
    725
    726		/*
    727		 * IIvi, IIvx use the "Brazil" framebuffer (which is
    728		 * very much like the V8, it seems, and probably uses
    729		 * the same DAC)
    730		 */
    731		case MAC_MODEL_IIVI:
    732		case MAC_MODEL_IIVX:
    733		case MAC_MODEL_P600:
    734			strcpy(macfb_fix.id, "Brazil");
    735			macfb_setpalette = v8_brazil_setpalette;
    736			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
    737			break;
    738
    739		/*
    740		 * LC III (and friends) use the Sonora framebuffer
    741		 * Incidentally this is also used in the non-AV models
    742		 * of the x100 PowerMacs
    743		 * These do in fact seem to use the same DAC interface
    744		 * as the LC II.
    745		 */
    746		case MAC_MODEL_LCIII:
    747		case MAC_MODEL_P520:
    748		case MAC_MODEL_P550:
    749		case MAC_MODEL_P460:
    750			strcpy(macfb_fix.id, "Sonora");
    751			macfb_setpalette = v8_brazil_setpalette;
    752			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
    753			break;
    754
    755		/*
    756		 * IIci and IIsi use the infamous RBV chip
    757		 * (the IIsi is just a rebadged and crippled
    758		 * IIci in a different case, BTW)
    759		 */
    760		case MAC_MODEL_IICI:
    761		case MAC_MODEL_IISI:
    762			strcpy(macfb_fix.id, "RBV");
    763			macfb_setpalette = rbv_setpalette;
    764			rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
    765			break;
    766
    767		/*
    768		 * AVs use the Civic framebuffer
    769		 */
    770		case MAC_MODEL_Q840:
    771		case MAC_MODEL_C660:
    772			strcpy(macfb_fix.id, "Civic");
    773			macfb_setpalette = civic_setpalette;
    774			civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
    775			break;
    776
    777		
    778		/*
    779		 * Assorted weirdos
    780		 * We think this may be like the LC II
    781		 */
    782		case MAC_MODEL_LC:
    783			strcpy(macfb_fix.id, "LC");
    784			if (vidtest) {
    785				macfb_setpalette = v8_brazil_setpalette;
    786				v8_brazil_cmap_regs =
    787					ioremap(DAC_BASE, 0x1000);
    788			}
    789			break;
    790
    791		/*
    792		 * We think this may be like the LC II
    793		 */
    794		case MAC_MODEL_CCL:
    795			strcpy(macfb_fix.id, "Color Classic");
    796			if (vidtest) {
    797				macfb_setpalette = v8_brazil_setpalette;
    798				v8_brazil_cmap_regs =
    799					ioremap(DAC_BASE, 0x1000);
    800			}
    801			break;
    802
    803		/*
    804		 * And we *do* mean "weirdos"
    805		 */
    806		case MAC_MODEL_TV:
    807			strcpy(macfb_fix.id, "Mac TV");
    808			break;
    809
    810		/*
    811		 * These don't have colour, so no need to worry
    812		 */
    813		case MAC_MODEL_SE30:
    814		case MAC_MODEL_CLII:
    815			strcpy(macfb_fix.id, "Monochrome");
    816			break;
    817
    818		/*
    819		 * Powerbooks are particularly difficult.  Many of
    820		 * them have separate framebuffers for external and
    821		 * internal video, which is admittedly pretty cool,
    822		 * but will be a bit of a headache to support here.
    823		 * Also, many of them are grayscale, and we don't
    824		 * really support that.
    825		 */
    826
    827		/*
    828		 * Slot 0 ROM says TIM. No external video. B&W.
    829		 */
    830		case MAC_MODEL_PB140:
    831		case MAC_MODEL_PB145:
    832		case MAC_MODEL_PB170:
    833			strcpy(macfb_fix.id, "DDC");
    834			break;
    835
    836		/*
    837		 * Internal is GSC, External (if present) is ViSC
    838		 */
    839		case MAC_MODEL_PB150:	/* no external video */
    840		case MAC_MODEL_PB160:
    841		case MAC_MODEL_PB165:
    842		case MAC_MODEL_PB180:
    843		case MAC_MODEL_PB210:
    844		case MAC_MODEL_PB230:
    845			strcpy(macfb_fix.id, "GSC");
    846			break;
    847
    848		/*
    849		 * Internal is TIM, External is ViSC
    850		 */
    851		case MAC_MODEL_PB165C:
    852		case MAC_MODEL_PB180C:
    853			strcpy(macfb_fix.id, "TIM");
    854			break;
    855
    856		/*
    857		 * Internal is CSC, External is Keystone+Ariel.
    858		 */
    859		case MAC_MODEL_PB190:	/* external video is optional */
    860		case MAC_MODEL_PB520:
    861		case MAC_MODEL_PB250:
    862		case MAC_MODEL_PB270C:
    863		case MAC_MODEL_PB280:
    864		case MAC_MODEL_PB280C:
    865			strcpy(macfb_fix.id, "CSC");
    866			macfb_setpalette = csc_setpalette;
    867			csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
    868			break;
    869
    870		default:
    871			strcpy(macfb_fix.id, "Unknown");
    872			break;
    873		}
    874
    875	fb_info.fbops		= &macfb_ops;
    876	fb_info.var		= macfb_defined;
    877	fb_info.fix		= macfb_fix;
    878	fb_info.pseudo_palette	= pseudo_palette;
    879	fb_info.flags		= FBINFO_DEFAULT;
    880
    881	err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
    882	if (err)
    883		goto fail_unmap;
    884
    885	err = register_framebuffer(&fb_info);
    886	if (err)
    887		goto fail_dealloc;
    888
    889	fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id);
    890
    891	return 0;
    892
    893fail_dealloc:
    894	fb_dealloc_cmap(&fb_info.cmap);
    895fail_unmap:
    896	iounmap(fb_info.screen_base);
    897	iounmap_macfb();
    898	return err;
    899}
    900
    901module_init(macfb_init);
    902MODULE_LICENSE("GPL");