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