162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
462306a36Sopenharmony_ci * don't know how to set.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * (c) 1999 David Huggins-Daines <dhd@debian.org>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Primarily based on vesafb.c, by Gerd Knorr
962306a36Sopenharmony_ci * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Also uses information and code from:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
1462306a36Sopenharmony_ci * Mellinger, Mikael Forselius, Michael Schmitz, and others.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
1762306a36Sopenharmony_ci * Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * The VideoToolbox "Bugs" web page at
2062306a36Sopenharmony_ci * http://rajsky.psych.nyu.edu/Tips/VideoBugs.html
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci#include <linux/kernel.h>
2562306a36Sopenharmony_ci#include <linux/errno.h>
2662306a36Sopenharmony_ci#include <linux/string.h>
2762306a36Sopenharmony_ci#include <linux/mm.h>
2862306a36Sopenharmony_ci#include <linux/delay.h>
2962306a36Sopenharmony_ci#include <linux/nubus.h>
3062306a36Sopenharmony_ci#include <linux/init.h>
3162306a36Sopenharmony_ci#include <linux/fb.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <asm/setup.h>
3462306a36Sopenharmony_ci#include <asm/macintosh.h>
3562306a36Sopenharmony_ci#include <asm/io.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
3862306a36Sopenharmony_ci#define DAC_BASE 0x50f24000
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* Some addresses for the DAFB */
4162306a36Sopenharmony_ci#define DAFB_BASE 0xf9800200
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Address for the built-in Civic framebuffer in Quadra AVs */
4462306a36Sopenharmony_ci#define CIVIC_BASE 0x50f30800
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* GSC (Gray Scale Controller) base address */
4762306a36Sopenharmony_ci#define GSC_BASE 0x50F20000
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* CSC (Color Screen Controller) base address */
5062306a36Sopenharmony_ci#define CSC_BASE 0x50F20000
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int (*macfb_setpalette)(unsigned int regno, unsigned int red,
5362306a36Sopenharmony_ci			       unsigned int green, unsigned int blue,
5462306a36Sopenharmony_ci			       struct fb_info *info);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic struct {
5762306a36Sopenharmony_ci	unsigned char addr;
5862306a36Sopenharmony_ci	unsigned char lut;
5962306a36Sopenharmony_ci} __iomem *v8_brazil_cmap_regs;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic struct {
6262306a36Sopenharmony_ci	unsigned char addr;
6362306a36Sopenharmony_ci	char pad1[3]; /* word aligned */
6462306a36Sopenharmony_ci	unsigned char lut;
6562306a36Sopenharmony_ci	char pad2[3]; /* word aligned */
6662306a36Sopenharmony_ci	unsigned char cntl; /* a guess as to purpose */
6762306a36Sopenharmony_ci} __iomem *rbv_cmap_regs;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic struct {
7062306a36Sopenharmony_ci	unsigned long reset;
7162306a36Sopenharmony_ci	unsigned long pad1[3];
7262306a36Sopenharmony_ci	unsigned char pad2[3];
7362306a36Sopenharmony_ci	unsigned char lut;
7462306a36Sopenharmony_ci} __iomem *dafb_cmap_regs;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic struct {
7762306a36Sopenharmony_ci	unsigned char addr;	/* OFFSET: 0x00 */
7862306a36Sopenharmony_ci	unsigned char pad1[15];
7962306a36Sopenharmony_ci	unsigned char lut;	/* OFFSET: 0x10 */
8062306a36Sopenharmony_ci	unsigned char pad2[15];
8162306a36Sopenharmony_ci	unsigned char status;	/* OFFSET: 0x20 */
8262306a36Sopenharmony_ci	unsigned char pad3[7];
8362306a36Sopenharmony_ci	unsigned long vbl_addr;	/* OFFSET: 0x28 */
8462306a36Sopenharmony_ci	unsigned int  status2;	/* OFFSET: 0x2C */
8562306a36Sopenharmony_ci} __iomem *civic_cmap_regs;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic struct {
8862306a36Sopenharmony_ci	char pad1[0x40];
8962306a36Sopenharmony_ci	unsigned char clut_waddr;	/* 0x40 */
9062306a36Sopenharmony_ci	char pad2;
9162306a36Sopenharmony_ci	unsigned char clut_data;	/* 0x42 */
9262306a36Sopenharmony_ci	char pad3[0x3];
9362306a36Sopenharmony_ci	unsigned char clut_raddr;	/* 0x46 */
9462306a36Sopenharmony_ci} __iomem *csc_cmap_regs;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* The registers in these structs are in NuBus slot space */
9762306a36Sopenharmony_cistruct mdc_cmap_regs {
9862306a36Sopenharmony_ci	char pad1[0x200200];
9962306a36Sopenharmony_ci	unsigned char addr;
10062306a36Sopenharmony_ci	char pad2[6];
10162306a36Sopenharmony_ci	unsigned char lut;
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct toby_cmap_regs {
10562306a36Sopenharmony_ci	char pad1[0x90018];
10662306a36Sopenharmony_ci	unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
10762306a36Sopenharmony_ci	char pad2[3];
10862306a36Sopenharmony_ci	unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct jet_cmap_regs {
11262306a36Sopenharmony_ci	char pad1[0xe0e000];
11362306a36Sopenharmony_ci	unsigned char addr;
11462306a36Sopenharmony_ci	unsigned char lut;
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define PIXEL_TO_MM(a)	(((a)*10)/28)	/* width in mm at 72 dpi */
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic struct fb_var_screeninfo macfb_defined = {
12062306a36Sopenharmony_ci	.activate	= FB_ACTIVATE_NOW,
12162306a36Sopenharmony_ci	.right_margin	= 32,
12262306a36Sopenharmony_ci	.upper_margin	= 16,
12362306a36Sopenharmony_ci	.lower_margin	= 4,
12462306a36Sopenharmony_ci	.vsync_len	= 4,
12562306a36Sopenharmony_ci	.vmode		= FB_VMODE_NONINTERLACED,
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic struct fb_fix_screeninfo macfb_fix = {
12962306a36Sopenharmony_ci	.type	= FB_TYPE_PACKED_PIXELS,
13062306a36Sopenharmony_ci	.accel	= FB_ACCEL_NONE,
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void *slot_addr;
13462306a36Sopenharmony_cistatic struct fb_info fb_info;
13562306a36Sopenharmony_cistatic u32 pseudo_palette[16];
13662306a36Sopenharmony_cistatic int vidtest;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * Unlike the Valkyrie, the DAFB cannot set individual colormap
14062306a36Sopenharmony_ci * registers.  Therefore, we do what the MacOS driver does (no
14162306a36Sopenharmony_ci * kidding!) and simply set them one by one until we hit the one we
14262306a36Sopenharmony_ci * want.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_cistatic int dafb_setpalette(unsigned int regno, unsigned int red,
14562306a36Sopenharmony_ci			   unsigned int green, unsigned int blue,
14662306a36Sopenharmony_ci			   struct fb_info *info)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	static int lastreg = -2;
14962306a36Sopenharmony_ci	unsigned long flags;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	local_irq_save(flags);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/*
15462306a36Sopenharmony_ci	 * fbdev will set an entire colourmap, but X won't.  Hopefully
15562306a36Sopenharmony_ci	 * this should accommodate both of them
15662306a36Sopenharmony_ci	 */
15762306a36Sopenharmony_ci	if (regno != lastreg + 1) {
15862306a36Sopenharmony_ci		int i;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		/* Stab in the dark trying to reset the CLUT pointer */
16162306a36Sopenharmony_ci		nubus_writel(0, &dafb_cmap_regs->reset);
16262306a36Sopenharmony_ci		nop();
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		/* Loop until we get to the register we want */
16562306a36Sopenharmony_ci		for (i = 0; i < regno; i++) {
16662306a36Sopenharmony_ci			nubus_writeb(info->cmap.red[i] >> 8,
16762306a36Sopenharmony_ci				     &dafb_cmap_regs->lut);
16862306a36Sopenharmony_ci			nop();
16962306a36Sopenharmony_ci			nubus_writeb(info->cmap.green[i] >> 8,
17062306a36Sopenharmony_ci				     &dafb_cmap_regs->lut);
17162306a36Sopenharmony_ci			nop();
17262306a36Sopenharmony_ci			nubus_writeb(info->cmap.blue[i] >> 8,
17362306a36Sopenharmony_ci				     &dafb_cmap_regs->lut);
17462306a36Sopenharmony_ci			nop();
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	nubus_writeb(red, &dafb_cmap_regs->lut);
17962306a36Sopenharmony_ci	nop();
18062306a36Sopenharmony_ci	nubus_writeb(green, &dafb_cmap_regs->lut);
18162306a36Sopenharmony_ci	nop();
18262306a36Sopenharmony_ci	nubus_writeb(blue, &dafb_cmap_regs->lut);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	local_irq_restore(flags);
18562306a36Sopenharmony_ci	lastreg = regno;
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
19062306a36Sopenharmony_cistatic int v8_brazil_setpalette(unsigned int regno, unsigned int red,
19162306a36Sopenharmony_ci				unsigned int green, unsigned int blue,
19262306a36Sopenharmony_ci				struct fb_info *info)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	unsigned int bpp = info->var.bits_per_pixel;
19562306a36Sopenharmony_ci	unsigned long flags;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	local_irq_save(flags);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* On these chips, the CLUT register numbers are spread out
20062306a36Sopenharmony_ci	 * across the register space.  Thus:
20162306a36Sopenharmony_ci	 * In 8bpp, all regnos are valid.
20262306a36Sopenharmony_ci	 * In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
20362306a36Sopenharmony_ci	 * In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff
20462306a36Sopenharmony_ci	 */
20562306a36Sopenharmony_ci	regno = (regno << (8 - bpp)) | (0xFF >> bpp);
20662306a36Sopenharmony_ci	nubus_writeb(regno, &v8_brazil_cmap_regs->addr);
20762306a36Sopenharmony_ci	nop();
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* send one color channel at a time */
21062306a36Sopenharmony_ci	nubus_writeb(red, &v8_brazil_cmap_regs->lut);
21162306a36Sopenharmony_ci	nop();
21262306a36Sopenharmony_ci	nubus_writeb(green, &v8_brazil_cmap_regs->lut);
21362306a36Sopenharmony_ci	nop();
21462306a36Sopenharmony_ci	nubus_writeb(blue, &v8_brazil_cmap_regs->lut);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	local_irq_restore(flags);
21762306a36Sopenharmony_ci	return 0;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* RAM-Based Video */
22162306a36Sopenharmony_cistatic int rbv_setpalette(unsigned int regno, unsigned int red,
22262306a36Sopenharmony_ci			  unsigned int green, unsigned int blue,
22362306a36Sopenharmony_ci			  struct fb_info *info)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	unsigned long flags;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	local_irq_save(flags);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* From the VideoToolbox driver.  Seems to be saying that
23062306a36Sopenharmony_ci	 * regno #254 and #255 are the important ones for 1-bit color,
23162306a36Sopenharmony_ci	 * regno #252-255 are the important ones for 2-bit color, etc.
23262306a36Sopenharmony_ci	 */
23362306a36Sopenharmony_ci	regno += 256 - (1 << info->var.bits_per_pixel);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* reset clut? (VideoToolbox sez "not necessary") */
23662306a36Sopenharmony_ci	nubus_writeb(0xFF, &rbv_cmap_regs->cntl);
23762306a36Sopenharmony_ci	nop();
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* tell clut which address to use. */
24062306a36Sopenharmony_ci	nubus_writeb(regno, &rbv_cmap_regs->addr);
24162306a36Sopenharmony_ci	nop();
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* send one color channel at a time. */
24462306a36Sopenharmony_ci	nubus_writeb(red, &rbv_cmap_regs->lut);
24562306a36Sopenharmony_ci	nop();
24662306a36Sopenharmony_ci	nubus_writeb(green, &rbv_cmap_regs->lut);
24762306a36Sopenharmony_ci	nop();
24862306a36Sopenharmony_ci	nubus_writeb(blue, &rbv_cmap_regs->lut);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	local_irq_restore(flags);
25162306a36Sopenharmony_ci	return 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/* Macintosh Display Card (8*24) */
25562306a36Sopenharmony_cistatic int mdc_setpalette(unsigned int regno, unsigned int red,
25662306a36Sopenharmony_ci			  unsigned int green, unsigned int blue,
25762306a36Sopenharmony_ci			  struct fb_info *info)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct mdc_cmap_regs *cmap_regs = slot_addr;
26062306a36Sopenharmony_ci	unsigned long flags;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	local_irq_save(flags);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/* the nop's are there to order writes. */
26562306a36Sopenharmony_ci	nubus_writeb(regno, &cmap_regs->addr);
26662306a36Sopenharmony_ci	nop();
26762306a36Sopenharmony_ci	nubus_writeb(red, &cmap_regs->lut);
26862306a36Sopenharmony_ci	nop();
26962306a36Sopenharmony_ci	nubus_writeb(green, &cmap_regs->lut);
27062306a36Sopenharmony_ci	nop();
27162306a36Sopenharmony_ci	nubus_writeb(blue, &cmap_regs->lut);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	local_irq_restore(flags);
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/* Toby frame buffer */
27862306a36Sopenharmony_cistatic int toby_setpalette(unsigned int regno, unsigned int red,
27962306a36Sopenharmony_ci			   unsigned int green, unsigned int blue,
28062306a36Sopenharmony_ci			   struct fb_info *info)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct toby_cmap_regs *cmap_regs = slot_addr;
28362306a36Sopenharmony_ci	unsigned int bpp = info->var.bits_per_pixel;
28462306a36Sopenharmony_ci	unsigned long flags;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	red = ~red;
28762306a36Sopenharmony_ci	green = ~green;
28862306a36Sopenharmony_ci	blue = ~blue;
28962306a36Sopenharmony_ci	regno = (regno << (8 - bpp)) | (0xFF >> bpp);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	local_irq_save(flags);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	nubus_writeb(regno, &cmap_regs->addr);
29462306a36Sopenharmony_ci	nop();
29562306a36Sopenharmony_ci	nubus_writeb(red, &cmap_regs->lut);
29662306a36Sopenharmony_ci	nop();
29762306a36Sopenharmony_ci	nubus_writeb(green, &cmap_regs->lut);
29862306a36Sopenharmony_ci	nop();
29962306a36Sopenharmony_ci	nubus_writeb(blue, &cmap_regs->lut);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	local_irq_restore(flags);
30262306a36Sopenharmony_ci	return 0;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/* Jet frame buffer */
30662306a36Sopenharmony_cistatic int jet_setpalette(unsigned int regno, unsigned int red,
30762306a36Sopenharmony_ci			  unsigned int green, unsigned int blue,
30862306a36Sopenharmony_ci			  struct fb_info *info)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct jet_cmap_regs *cmap_regs = slot_addr;
31162306a36Sopenharmony_ci	unsigned long flags;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	local_irq_save(flags);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	nubus_writeb(regno, &cmap_regs->addr);
31662306a36Sopenharmony_ci	nop();
31762306a36Sopenharmony_ci	nubus_writeb(red, &cmap_regs->lut);
31862306a36Sopenharmony_ci	nop();
31962306a36Sopenharmony_ci	nubus_writeb(green, &cmap_regs->lut);
32062306a36Sopenharmony_ci	nop();
32162306a36Sopenharmony_ci	nubus_writeb(blue, &cmap_regs->lut);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	local_irq_restore(flags);
32462306a36Sopenharmony_ci	return 0;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/*
32862306a36Sopenharmony_ci * Civic framebuffer -- Quadra AV built-in video.  A chip
32962306a36Sopenharmony_ci * called Sebastian holds the actual color palettes, and
33062306a36Sopenharmony_ci * apparently, there are two different banks of 512K RAM
33162306a36Sopenharmony_ci * which can act as separate framebuffers for doing video
33262306a36Sopenharmony_ci * input and viewing the screen at the same time!  The 840AV
33362306a36Sopenharmony_ci * Can add another 1MB RAM to give the two framebuffers
33462306a36Sopenharmony_ci * 1MB RAM apiece.
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_cistatic int civic_setpalette(unsigned int regno, unsigned int red,
33762306a36Sopenharmony_ci			    unsigned int green, unsigned int blue,
33862306a36Sopenharmony_ci			    struct fb_info *info)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	unsigned long flags;
34162306a36Sopenharmony_ci	int clut_status;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	local_irq_save(flags);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Set the register address */
34662306a36Sopenharmony_ci	nubus_writeb(regno, &civic_cmap_regs->addr);
34762306a36Sopenharmony_ci	nop();
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/*
35062306a36Sopenharmony_ci	 * Grab a status word and do some checking;
35162306a36Sopenharmony_ci	 * Then finally write the clut!
35262306a36Sopenharmony_ci	 */
35362306a36Sopenharmony_ci	clut_status =  nubus_readb(&civic_cmap_regs->status2);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if ((clut_status & 0x0008) == 0)
35662306a36Sopenharmony_ci	{
35762306a36Sopenharmony_ci#if 0
35862306a36Sopenharmony_ci		if ((clut_status & 0x000D) != 0)
35962306a36Sopenharmony_ci		{
36062306a36Sopenharmony_ci			nubus_writeb(0x00, &civic_cmap_regs->lut);
36162306a36Sopenharmony_ci			nop();
36262306a36Sopenharmony_ci			nubus_writeb(0x00, &civic_cmap_regs->lut);
36362306a36Sopenharmony_ci			nop();
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci#endif
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		nubus_writeb(red, &civic_cmap_regs->lut);
36862306a36Sopenharmony_ci		nop();
36962306a36Sopenharmony_ci		nubus_writeb(green, &civic_cmap_regs->lut);
37062306a36Sopenharmony_ci		nop();
37162306a36Sopenharmony_ci		nubus_writeb(blue, &civic_cmap_regs->lut);
37262306a36Sopenharmony_ci		nop();
37362306a36Sopenharmony_ci		nubus_writeb(0x00, &civic_cmap_regs->lut);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci	else
37662306a36Sopenharmony_ci	{
37762306a36Sopenharmony_ci		unsigned char junk;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		junk = nubus_readb(&civic_cmap_regs->lut);
38062306a36Sopenharmony_ci		nop();
38162306a36Sopenharmony_ci		junk = nubus_readb(&civic_cmap_regs->lut);
38262306a36Sopenharmony_ci		nop();
38362306a36Sopenharmony_ci		junk = nubus_readb(&civic_cmap_regs->lut);
38462306a36Sopenharmony_ci		nop();
38562306a36Sopenharmony_ci		junk = nubus_readb(&civic_cmap_regs->lut);
38662306a36Sopenharmony_ci		nop();
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		if ((clut_status & 0x000D) != 0)
38962306a36Sopenharmony_ci		{
39062306a36Sopenharmony_ci			nubus_writeb(0x00, &civic_cmap_regs->lut);
39162306a36Sopenharmony_ci			nop();
39262306a36Sopenharmony_ci			nubus_writeb(0x00, &civic_cmap_regs->lut);
39362306a36Sopenharmony_ci			nop();
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		nubus_writeb(red, &civic_cmap_regs->lut);
39762306a36Sopenharmony_ci		nop();
39862306a36Sopenharmony_ci		nubus_writeb(green, &civic_cmap_regs->lut);
39962306a36Sopenharmony_ci		nop();
40062306a36Sopenharmony_ci		nubus_writeb(blue, &civic_cmap_regs->lut);
40162306a36Sopenharmony_ci		nop();
40262306a36Sopenharmony_ci		nubus_writeb(junk, &civic_cmap_regs->lut);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	local_irq_restore(flags);
40662306a36Sopenharmony_ci	return 0;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci/*
41062306a36Sopenharmony_ci * The CSC is the framebuffer on the PowerBook 190 series
41162306a36Sopenharmony_ci * (and the 5300 too, but that's a PowerMac). This function
41262306a36Sopenharmony_ci * brought to you in part by the ECSC driver for MkLinux.
41362306a36Sopenharmony_ci */
41462306a36Sopenharmony_cistatic int csc_setpalette(unsigned int regno, unsigned int red,
41562306a36Sopenharmony_ci			  unsigned int green, unsigned int blue,
41662306a36Sopenharmony_ci			  struct fb_info *info)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	unsigned long flags;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	local_irq_save(flags);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	udelay(1); /* mklinux on PB 5300 waits for 260 ns */
42362306a36Sopenharmony_ci	nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
42462306a36Sopenharmony_ci	nubus_writeb(red, &csc_cmap_regs->clut_data);
42562306a36Sopenharmony_ci	nubus_writeb(green, &csc_cmap_regs->clut_data);
42662306a36Sopenharmony_ci	nubus_writeb(blue, &csc_cmap_regs->clut_data);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	local_irq_restore(flags);
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
43362306a36Sopenharmony_ci			   unsigned blue, unsigned transp,
43462306a36Sopenharmony_ci			   struct fb_info *fb_info)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	/*
43762306a36Sopenharmony_ci	 * Set a single color register. The values supplied are
43862306a36Sopenharmony_ci	 * already rounded down to the hardware's capabilities
43962306a36Sopenharmony_ci	 * (according to the entries in the `var' structure).
44062306a36Sopenharmony_ci	 * Return non-zero for invalid regno.
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (regno >= fb_info->cmap.len)
44462306a36Sopenharmony_ci		return 1;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (fb_info->var.bits_per_pixel <= 8) {
44762306a36Sopenharmony_ci		switch (fb_info->var.bits_per_pixel) {
44862306a36Sopenharmony_ci		case 1:
44962306a36Sopenharmony_ci			/* We shouldn't get here */
45062306a36Sopenharmony_ci			break;
45162306a36Sopenharmony_ci		case 2:
45262306a36Sopenharmony_ci		case 4:
45362306a36Sopenharmony_ci		case 8:
45462306a36Sopenharmony_ci			if (macfb_setpalette)
45562306a36Sopenharmony_ci				macfb_setpalette(regno, red >> 8, green >> 8,
45662306a36Sopenharmony_ci						 blue >> 8, fb_info);
45762306a36Sopenharmony_ci			else
45862306a36Sopenharmony_ci				return 1;
45962306a36Sopenharmony_ci			break;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci	} else if (regno < 16) {
46262306a36Sopenharmony_ci		switch (fb_info->var.bits_per_pixel) {
46362306a36Sopenharmony_ci		case 16:
46462306a36Sopenharmony_ci			if (fb_info->var.red.offset == 10) {
46562306a36Sopenharmony_ci				/* 1:5:5:5 */
46662306a36Sopenharmony_ci				((u32*) (fb_info->pseudo_palette))[regno] =
46762306a36Sopenharmony_ci					((red   & 0xf800) >>  1) |
46862306a36Sopenharmony_ci					((green & 0xf800) >>  6) |
46962306a36Sopenharmony_ci					((blue  & 0xf800) >> 11) |
47062306a36Sopenharmony_ci					((transp != 0) << 15);
47162306a36Sopenharmony_ci			} else {
47262306a36Sopenharmony_ci				/* 0:5:6:5 */
47362306a36Sopenharmony_ci				((u32*) (fb_info->pseudo_palette))[regno] =
47462306a36Sopenharmony_ci					((red   & 0xf800) >>  0) |
47562306a36Sopenharmony_ci					((green & 0xfc00) >>  5) |
47662306a36Sopenharmony_ci					((blue  & 0xf800) >> 11);
47762306a36Sopenharmony_ci			}
47862306a36Sopenharmony_ci			break;
47962306a36Sopenharmony_ci		/*
48062306a36Sopenharmony_ci		 * 24-bit colour almost doesn't exist on 68k Macs --
48162306a36Sopenharmony_ci		 * https://support.apple.com/kb/TA28634 (Old Article: 10992)
48262306a36Sopenharmony_ci		 */
48362306a36Sopenharmony_ci		case 24:
48462306a36Sopenharmony_ci		case 32:
48562306a36Sopenharmony_ci			red   >>= 8;
48662306a36Sopenharmony_ci			green >>= 8;
48762306a36Sopenharmony_ci			blue  >>= 8;
48862306a36Sopenharmony_ci			((u32 *)(fb_info->pseudo_palette))[regno] =
48962306a36Sopenharmony_ci				(red   << fb_info->var.red.offset) |
49062306a36Sopenharmony_ci				(green << fb_info->var.green.offset) |
49162306a36Sopenharmony_ci				(blue  << fb_info->var.blue.offset);
49262306a36Sopenharmony_ci			break;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return 0;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic const struct fb_ops macfb_ops = {
50062306a36Sopenharmony_ci	.owner		= THIS_MODULE,
50162306a36Sopenharmony_ci	FB_DEFAULT_IOMEM_OPS,
50262306a36Sopenharmony_ci	.fb_setcolreg	= macfb_setcolreg,
50362306a36Sopenharmony_ci};
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic void __init macfb_setup(char *options)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	char *this_opt;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (!options || !*options)
51062306a36Sopenharmony_ci		return;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
51362306a36Sopenharmony_ci		if (!*this_opt)
51462306a36Sopenharmony_ci			continue;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		if (!strcmp(this_opt, "inverse"))
51762306a36Sopenharmony_ci			fb_invert_cmaps();
51862306a36Sopenharmony_ci		else
51962306a36Sopenharmony_ci			if (!strcmp(this_opt, "vidtest"))
52062306a36Sopenharmony_ci				vidtest = 1; /* enable experimental CLUT code */
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic void __init iounmap_macfb(void)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	if (dafb_cmap_regs)
52762306a36Sopenharmony_ci		iounmap(dafb_cmap_regs);
52862306a36Sopenharmony_ci	if (v8_brazil_cmap_regs)
52962306a36Sopenharmony_ci		iounmap(v8_brazil_cmap_regs);
53062306a36Sopenharmony_ci	if (rbv_cmap_regs)
53162306a36Sopenharmony_ci		iounmap(rbv_cmap_regs);
53262306a36Sopenharmony_ci	if (civic_cmap_regs)
53362306a36Sopenharmony_ci		iounmap(civic_cmap_regs);
53462306a36Sopenharmony_ci	if (csc_cmap_regs)
53562306a36Sopenharmony_ci		iounmap(csc_cmap_regs);
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic int __init macfb_init(void)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	int video_cmap_len, video_is_nubus = 0;
54162306a36Sopenharmony_ci	struct nubus_rsrc *ndev = NULL;
54262306a36Sopenharmony_ci	char *option = NULL;
54362306a36Sopenharmony_ci	int err;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (fb_get_options("macfb", &option))
54662306a36Sopenharmony_ci		return -ENODEV;
54762306a36Sopenharmony_ci	macfb_setup(option);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (!MACH_IS_MAC)
55062306a36Sopenharmony_ci		return -ENODEV;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (mac_bi_data.id == MAC_MODEL_Q630 ||
55362306a36Sopenharmony_ci	    mac_bi_data.id == MAC_MODEL_P588)
55462306a36Sopenharmony_ci		return -ENODEV; /* See valkyriefb.c */
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
55762306a36Sopenharmony_ci	macfb_defined.yres = mac_bi_data.dimensions >> 16;
55862306a36Sopenharmony_ci	macfb_defined.bits_per_pixel = mac_bi_data.videodepth;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	macfb_fix.line_length = mac_bi_data.videorow;
56162306a36Sopenharmony_ci	macfb_fix.smem_len    = macfb_fix.line_length * macfb_defined.yres;
56262306a36Sopenharmony_ci	/* Note: physical address (since 2.1.127) */
56362306a36Sopenharmony_ci	macfb_fix.smem_start  = mac_bi_data.videoaddr;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/*
56662306a36Sopenharmony_ci	 * This is actually redundant with the initial mappings.
56762306a36Sopenharmony_ci	 * However, there are some non-obvious aspects to the way
56862306a36Sopenharmony_ci	 * those mappings are set up, so this is in fact the safest
56962306a36Sopenharmony_ci	 * way to ensure that this driver will work on every possible Mac
57062306a36Sopenharmony_ci	 */
57162306a36Sopenharmony_ci	fb_info.screen_base = ioremap(mac_bi_data.videoaddr,
57262306a36Sopenharmony_ci				      macfb_fix.smem_len);
57362306a36Sopenharmony_ci	if (!fb_info.screen_base)
57462306a36Sopenharmony_ci		return -ENODEV;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	pr_info("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
57762306a36Sopenharmony_ci	        macfb_fix.smem_start, fb_info.screen_base,
57862306a36Sopenharmony_ci	        macfb_fix.smem_len / 1024);
57962306a36Sopenharmony_ci	pr_info("macfb: mode is %dx%dx%d, linelength=%d\n",
58062306a36Sopenharmony_ci	        macfb_defined.xres, macfb_defined.yres,
58162306a36Sopenharmony_ci	        macfb_defined.bits_per_pixel, macfb_fix.line_length);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/* Fill in the available video resolution */
58462306a36Sopenharmony_ci	macfb_defined.xres_virtual = macfb_defined.xres;
58562306a36Sopenharmony_ci	macfb_defined.yres_virtual = macfb_defined.yres;
58662306a36Sopenharmony_ci	macfb_defined.height       = PIXEL_TO_MM(macfb_defined.yres);
58762306a36Sopenharmony_ci	macfb_defined.width        = PIXEL_TO_MM(macfb_defined.xres);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/* Some dummy values for timing to make fbset happy */
59062306a36Sopenharmony_ci	macfb_defined.pixclock     = 10000000 / macfb_defined.xres *
59162306a36Sopenharmony_ci				     1000 / macfb_defined.yres;
59262306a36Sopenharmony_ci	macfb_defined.left_margin  = (macfb_defined.xres / 8) & 0xf8;
59362306a36Sopenharmony_ci	macfb_defined.hsync_len    = (macfb_defined.xres / 8) & 0xf8;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	switch (macfb_defined.bits_per_pixel) {
59662306a36Sopenharmony_ci	case 1:
59762306a36Sopenharmony_ci		macfb_defined.red.length = macfb_defined.bits_per_pixel;
59862306a36Sopenharmony_ci		macfb_defined.green.length = macfb_defined.bits_per_pixel;
59962306a36Sopenharmony_ci		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
60062306a36Sopenharmony_ci		video_cmap_len = 2;
60162306a36Sopenharmony_ci		macfb_fix.visual = FB_VISUAL_MONO01;
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci	case 2:
60462306a36Sopenharmony_ci	case 4:
60562306a36Sopenharmony_ci	case 8:
60662306a36Sopenharmony_ci		macfb_defined.red.length = macfb_defined.bits_per_pixel;
60762306a36Sopenharmony_ci		macfb_defined.green.length = macfb_defined.bits_per_pixel;
60862306a36Sopenharmony_ci		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
60962306a36Sopenharmony_ci		video_cmap_len = 1 << macfb_defined.bits_per_pixel;
61062306a36Sopenharmony_ci		macfb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	case 16:
61362306a36Sopenharmony_ci		macfb_defined.transp.offset = 15;
61462306a36Sopenharmony_ci		macfb_defined.transp.length = 1;
61562306a36Sopenharmony_ci		macfb_defined.red.offset = 10;
61662306a36Sopenharmony_ci		macfb_defined.red.length = 5;
61762306a36Sopenharmony_ci		macfb_defined.green.offset = 5;
61862306a36Sopenharmony_ci		macfb_defined.green.length = 5;
61962306a36Sopenharmony_ci		macfb_defined.blue.offset = 0;
62062306a36Sopenharmony_ci		macfb_defined.blue.length = 5;
62162306a36Sopenharmony_ci		video_cmap_len = 16;
62262306a36Sopenharmony_ci		/*
62362306a36Sopenharmony_ci		 * Should actually be FB_VISUAL_DIRECTCOLOR, but this
62462306a36Sopenharmony_ci		 * works too
62562306a36Sopenharmony_ci		 */
62662306a36Sopenharmony_ci		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
62762306a36Sopenharmony_ci		break;
62862306a36Sopenharmony_ci	case 24:
62962306a36Sopenharmony_ci	case 32:
63062306a36Sopenharmony_ci		macfb_defined.red.offset = 16;
63162306a36Sopenharmony_ci		macfb_defined.red.length = 8;
63262306a36Sopenharmony_ci		macfb_defined.green.offset = 8;
63362306a36Sopenharmony_ci		macfb_defined.green.length = 8;
63462306a36Sopenharmony_ci		macfb_defined.blue.offset = 0;
63562306a36Sopenharmony_ci		macfb_defined.blue.length = 8;
63662306a36Sopenharmony_ci		video_cmap_len = 16;
63762306a36Sopenharmony_ci		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
63862306a36Sopenharmony_ci		break;
63962306a36Sopenharmony_ci	default:
64062306a36Sopenharmony_ci		pr_err("macfb: unknown or unsupported bit depth: %d\n",
64162306a36Sopenharmony_ci		       macfb_defined.bits_per_pixel);
64262306a36Sopenharmony_ci		err = -EINVAL;
64362306a36Sopenharmony_ci		goto fail_unmap;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/*
64762306a36Sopenharmony_ci	 * We take a wild guess that if the video physical address is
64862306a36Sopenharmony_ci	 * in nubus slot space, that the nubus card is driving video.
64962306a36Sopenharmony_ci	 * Penguin really ought to tell us whether we are using internal
65062306a36Sopenharmony_ci	 * video or not.
65162306a36Sopenharmony_ci	 * Hopefully we only find one of them.  Otherwise our NuBus
65262306a36Sopenharmony_ci	 * code is really broken :-)
65362306a36Sopenharmony_ci	 */
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	for_each_func_rsrc(ndev) {
65662306a36Sopenharmony_ci		unsigned long base = ndev->board->slot_addr;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		if (mac_bi_data.videoaddr < base ||
65962306a36Sopenharmony_ci		    mac_bi_data.videoaddr - base > 0xFFFFFF)
66062306a36Sopenharmony_ci			continue;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		if (ndev->category != NUBUS_CAT_DISPLAY ||
66362306a36Sopenharmony_ci		    ndev->type != NUBUS_TYPE_VIDEO)
66462306a36Sopenharmony_ci			continue;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		video_is_nubus = 1;
66762306a36Sopenharmony_ci		slot_addr = (unsigned char *)base;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		switch(ndev->dr_hw) {
67062306a36Sopenharmony_ci		case NUBUS_DRHW_APPLE_MDC:
67162306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Mac Disp. Card");
67262306a36Sopenharmony_ci			macfb_setpalette = mdc_setpalette;
67362306a36Sopenharmony_ci			break;
67462306a36Sopenharmony_ci		case NUBUS_DRHW_APPLE_TFB:
67562306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Toby");
67662306a36Sopenharmony_ci			macfb_setpalette = toby_setpalette;
67762306a36Sopenharmony_ci			break;
67862306a36Sopenharmony_ci		case NUBUS_DRHW_APPLE_JET:
67962306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Jet");
68062306a36Sopenharmony_ci			macfb_setpalette = jet_setpalette;
68162306a36Sopenharmony_ci			break;
68262306a36Sopenharmony_ci		default:
68362306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Generic NuBus");
68462306a36Sopenharmony_ci			break;
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/* If it's not a NuBus card, it must be internal video */
68962306a36Sopenharmony_ci	if (!video_is_nubus)
69062306a36Sopenharmony_ci		switch (mac_bi_data.id) {
69162306a36Sopenharmony_ci		/*
69262306a36Sopenharmony_ci		 * DAFB Quadras
69362306a36Sopenharmony_ci		 * Note: these first four have the v7 DAFB, which is
69462306a36Sopenharmony_ci		 * known to be rather unlike the ones used in the
69562306a36Sopenharmony_ci		 * other models
69662306a36Sopenharmony_ci		 */
69762306a36Sopenharmony_ci		case MAC_MODEL_P475:
69862306a36Sopenharmony_ci		case MAC_MODEL_P475F:
69962306a36Sopenharmony_ci		case MAC_MODEL_P575:
70062306a36Sopenharmony_ci		case MAC_MODEL_Q605:
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		case MAC_MODEL_Q800:
70362306a36Sopenharmony_ci		case MAC_MODEL_Q650:
70462306a36Sopenharmony_ci		case MAC_MODEL_Q610:
70562306a36Sopenharmony_ci		case MAC_MODEL_C650:
70662306a36Sopenharmony_ci		case MAC_MODEL_C610:
70762306a36Sopenharmony_ci		case MAC_MODEL_Q700:
70862306a36Sopenharmony_ci		case MAC_MODEL_Q900:
70962306a36Sopenharmony_ci		case MAC_MODEL_Q950:
71062306a36Sopenharmony_ci			strcpy(macfb_fix.id, "DAFB");
71162306a36Sopenharmony_ci			macfb_setpalette = dafb_setpalette;
71262306a36Sopenharmony_ci			dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
71362306a36Sopenharmony_ci			break;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		/*
71662306a36Sopenharmony_ci		 * LC II uses the V8 framebuffer
71762306a36Sopenharmony_ci		 */
71862306a36Sopenharmony_ci		case MAC_MODEL_LCII:
71962306a36Sopenharmony_ci			strcpy(macfb_fix.id, "V8");
72062306a36Sopenharmony_ci			macfb_setpalette = v8_brazil_setpalette;
72162306a36Sopenharmony_ci			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
72262306a36Sopenharmony_ci			break;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		/*
72562306a36Sopenharmony_ci		 * IIvi, IIvx use the "Brazil" framebuffer (which is
72662306a36Sopenharmony_ci		 * very much like the V8, it seems, and probably uses
72762306a36Sopenharmony_ci		 * the same DAC)
72862306a36Sopenharmony_ci		 */
72962306a36Sopenharmony_ci		case MAC_MODEL_IIVI:
73062306a36Sopenharmony_ci		case MAC_MODEL_IIVX:
73162306a36Sopenharmony_ci		case MAC_MODEL_P600:
73262306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Brazil");
73362306a36Sopenharmony_ci			macfb_setpalette = v8_brazil_setpalette;
73462306a36Sopenharmony_ci			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
73562306a36Sopenharmony_ci			break;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		/*
73862306a36Sopenharmony_ci		 * LC III (and friends) use the Sonora framebuffer
73962306a36Sopenharmony_ci		 * Incidentally this is also used in the non-AV models
74062306a36Sopenharmony_ci		 * of the x100 PowerMacs
74162306a36Sopenharmony_ci		 * These do in fact seem to use the same DAC interface
74262306a36Sopenharmony_ci		 * as the LC II.
74362306a36Sopenharmony_ci		 */
74462306a36Sopenharmony_ci		case MAC_MODEL_LCIII:
74562306a36Sopenharmony_ci		case MAC_MODEL_P520:
74662306a36Sopenharmony_ci		case MAC_MODEL_P550:
74762306a36Sopenharmony_ci		case MAC_MODEL_P460:
74862306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Sonora");
74962306a36Sopenharmony_ci			macfb_setpalette = v8_brazil_setpalette;
75062306a36Sopenharmony_ci			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
75162306a36Sopenharmony_ci			break;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		/*
75462306a36Sopenharmony_ci		 * IIci and IIsi use the infamous RBV chip
75562306a36Sopenharmony_ci		 * (the IIsi is just a rebadged and crippled
75662306a36Sopenharmony_ci		 * IIci in a different case, BTW)
75762306a36Sopenharmony_ci		 */
75862306a36Sopenharmony_ci		case MAC_MODEL_IICI:
75962306a36Sopenharmony_ci		case MAC_MODEL_IISI:
76062306a36Sopenharmony_ci			strcpy(macfb_fix.id, "RBV");
76162306a36Sopenharmony_ci			macfb_setpalette = rbv_setpalette;
76262306a36Sopenharmony_ci			rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
76362306a36Sopenharmony_ci			break;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		/*
76662306a36Sopenharmony_ci		 * AVs use the Civic framebuffer
76762306a36Sopenharmony_ci		 */
76862306a36Sopenharmony_ci		case MAC_MODEL_Q840:
76962306a36Sopenharmony_ci		case MAC_MODEL_C660:
77062306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Civic");
77162306a36Sopenharmony_ci			macfb_setpalette = civic_setpalette;
77262306a36Sopenharmony_ci			civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
77362306a36Sopenharmony_ci			break;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		/*
77762306a36Sopenharmony_ci		 * Assorted weirdos
77862306a36Sopenharmony_ci		 * We think this may be like the LC II
77962306a36Sopenharmony_ci		 */
78062306a36Sopenharmony_ci		case MAC_MODEL_LC:
78162306a36Sopenharmony_ci			strcpy(macfb_fix.id, "LC");
78262306a36Sopenharmony_ci			if (vidtest) {
78362306a36Sopenharmony_ci				macfb_setpalette = v8_brazil_setpalette;
78462306a36Sopenharmony_ci				v8_brazil_cmap_regs =
78562306a36Sopenharmony_ci					ioremap(DAC_BASE, 0x1000);
78662306a36Sopenharmony_ci			}
78762306a36Sopenharmony_ci			break;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		/*
79062306a36Sopenharmony_ci		 * We think this may be like the LC II
79162306a36Sopenharmony_ci		 */
79262306a36Sopenharmony_ci		case MAC_MODEL_CCL:
79362306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Color Classic");
79462306a36Sopenharmony_ci			if (vidtest) {
79562306a36Sopenharmony_ci				macfb_setpalette = v8_brazil_setpalette;
79662306a36Sopenharmony_ci				v8_brazil_cmap_regs =
79762306a36Sopenharmony_ci					ioremap(DAC_BASE, 0x1000);
79862306a36Sopenharmony_ci			}
79962306a36Sopenharmony_ci			break;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		/*
80262306a36Sopenharmony_ci		 * And we *do* mean "weirdos"
80362306a36Sopenharmony_ci		 */
80462306a36Sopenharmony_ci		case MAC_MODEL_TV:
80562306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Mac TV");
80662306a36Sopenharmony_ci			break;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		/*
80962306a36Sopenharmony_ci		 * These don't have colour, so no need to worry
81062306a36Sopenharmony_ci		 */
81162306a36Sopenharmony_ci		case MAC_MODEL_SE30:
81262306a36Sopenharmony_ci		case MAC_MODEL_CLII:
81362306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Monochrome");
81462306a36Sopenharmony_ci			break;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		/*
81762306a36Sopenharmony_ci		 * Powerbooks are particularly difficult.  Many of
81862306a36Sopenharmony_ci		 * them have separate framebuffers for external and
81962306a36Sopenharmony_ci		 * internal video, which is admittedly pretty cool,
82062306a36Sopenharmony_ci		 * but will be a bit of a headache to support here.
82162306a36Sopenharmony_ci		 * Also, many of them are grayscale, and we don't
82262306a36Sopenharmony_ci		 * really support that.
82362306a36Sopenharmony_ci		 */
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		/*
82662306a36Sopenharmony_ci		 * Slot 0 ROM says TIM. No external video. B&W.
82762306a36Sopenharmony_ci		 */
82862306a36Sopenharmony_ci		case MAC_MODEL_PB140:
82962306a36Sopenharmony_ci		case MAC_MODEL_PB145:
83062306a36Sopenharmony_ci		case MAC_MODEL_PB170:
83162306a36Sopenharmony_ci			strcpy(macfb_fix.id, "DDC");
83262306a36Sopenharmony_ci			break;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		/*
83562306a36Sopenharmony_ci		 * Internal is GSC, External (if present) is ViSC
83662306a36Sopenharmony_ci		 */
83762306a36Sopenharmony_ci		case MAC_MODEL_PB150:	/* no external video */
83862306a36Sopenharmony_ci		case MAC_MODEL_PB160:
83962306a36Sopenharmony_ci		case MAC_MODEL_PB165:
84062306a36Sopenharmony_ci		case MAC_MODEL_PB180:
84162306a36Sopenharmony_ci		case MAC_MODEL_PB210:
84262306a36Sopenharmony_ci		case MAC_MODEL_PB230:
84362306a36Sopenharmony_ci			strcpy(macfb_fix.id, "GSC");
84462306a36Sopenharmony_ci			break;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		/*
84762306a36Sopenharmony_ci		 * Internal is TIM, External is ViSC
84862306a36Sopenharmony_ci		 */
84962306a36Sopenharmony_ci		case MAC_MODEL_PB165C:
85062306a36Sopenharmony_ci		case MAC_MODEL_PB180C:
85162306a36Sopenharmony_ci			strcpy(macfb_fix.id, "TIM");
85262306a36Sopenharmony_ci			break;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		/*
85562306a36Sopenharmony_ci		 * Internal is CSC, External is Keystone+Ariel.
85662306a36Sopenharmony_ci		 */
85762306a36Sopenharmony_ci		case MAC_MODEL_PB190:	/* external video is optional */
85862306a36Sopenharmony_ci		case MAC_MODEL_PB520:
85962306a36Sopenharmony_ci		case MAC_MODEL_PB250:
86062306a36Sopenharmony_ci		case MAC_MODEL_PB270C:
86162306a36Sopenharmony_ci		case MAC_MODEL_PB280:
86262306a36Sopenharmony_ci		case MAC_MODEL_PB280C:
86362306a36Sopenharmony_ci			strcpy(macfb_fix.id, "CSC");
86462306a36Sopenharmony_ci			macfb_setpalette = csc_setpalette;
86562306a36Sopenharmony_ci			csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
86662306a36Sopenharmony_ci			break;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		default:
86962306a36Sopenharmony_ci			strcpy(macfb_fix.id, "Unknown");
87062306a36Sopenharmony_ci			break;
87162306a36Sopenharmony_ci		}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	fb_info.fbops		= &macfb_ops;
87462306a36Sopenharmony_ci	fb_info.var		= macfb_defined;
87562306a36Sopenharmony_ci	fb_info.fix		= macfb_fix;
87662306a36Sopenharmony_ci	fb_info.pseudo_palette	= pseudo_palette;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
87962306a36Sopenharmony_ci	if (err)
88062306a36Sopenharmony_ci		goto fail_unmap;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	err = register_framebuffer(&fb_info);
88362306a36Sopenharmony_ci	if (err)
88462306a36Sopenharmony_ci		goto fail_dealloc;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	return 0;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cifail_dealloc:
89162306a36Sopenharmony_ci	fb_dealloc_cmap(&fb_info.cmap);
89262306a36Sopenharmony_cifail_unmap:
89362306a36Sopenharmony_ci	iounmap(fb_info.screen_base);
89462306a36Sopenharmony_ci	iounmap_macfb();
89562306a36Sopenharmony_ci	return err;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cimodule_init(macfb_init);
89962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
900