^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * platinumfb.c -- frame buffer device for the PowerMac 'platinum' display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1998 Franz Sirl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Frame buffer structure from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * drivers/video/controlfb.c -- frame buffer device for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Apple 'control' display chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 1998 Dan Jacobowitz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Hardware information from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * platinum.c: Console support for PowerMac "platinum" display adaptor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 1996 Paul Mackerras and Mark Abene
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/nvram.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include "macmodes.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include "platinumfb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int default_vmode = VMODE_NVRAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int default_cmode = CMODE_NVRAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct fb_info_platinum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int vmode, cmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int xres, yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int vxres, vyres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int xoffset, yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) __u8 red, green, blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) } palette[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) volatile struct cmap_regs __iomem *cmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned long cmap_regs_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) volatile struct platinum_regs __iomem *platinum_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned long platinum_regs_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) __u8 __iomem *frame_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) volatile __u8 __iomem *base_frame_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned long frame_buffer_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned long total_vram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int clktype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int dactype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct resource rsrc_fb, rsrc_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * Frame buffer device API
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u_int transp, struct fb_info *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int platinumfb_blank(int blank_mode, struct fb_info *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int platinumfb_set_par (struct fb_info *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * internal functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static inline int platinum_vram_reqd(int video_mode, int color_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int read_platinum_sense(struct fb_info_platinum *pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static void set_platinum_clock(struct fb_info_platinum *pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static void platinum_set_hardware(struct fb_info_platinum *pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int platinum_var_to_par(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct fb_info_platinum *pinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int check_only);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * Interface used by the world
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static const struct fb_ops platinumfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .fb_check_var = platinumfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .fb_set_par = platinumfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .fb_setcolreg = platinumfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .fb_blank = platinumfb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Checks a var structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static int platinumfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return platinum_var_to_par(var, info->par, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * Applies current var to display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static int platinumfb_set_par (struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct fb_info_platinum *pinfo = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct platinum_regvals *init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int err, offset = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if((err = platinum_var_to_par(&info->var, pinfo, 0))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) printk (KERN_ERR "platinumfb_set_par: error calling"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) " platinum_var_to_par: %d.\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) platinum_set_hardware(pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) init = platinum_reg_init[pinfo->vmode-1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) offset = 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) mutex_lock(&info->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) mutex_unlock(&info->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) info->fix.visual = (pinfo->cmode == CMODE_8) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) printk("line_length: %x\n", info->fix.line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static int platinumfb_blank(int blank, struct fb_info *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * then the caller blanks by setting the CLUT (Color Look Up Table) to all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * to e.g. a video mode which doesn't support it. Implements VESA suspend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * and powerdown modes on hardware that supports disabling hsync/vsync:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * blank_mode == 2: suspend vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * blank_mode == 3: suspend hsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * blank_mode == 4: powerdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* [danj] I think there's something fishy about those constants... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ctrl = le32_to_cpup(&info->platinum_regs->ctrl.r) | 0x33;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) --blank_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (blank & VESA_VSYNC_SUSPEND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ctrl &= ~3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (blank & VESA_HSYNC_SUSPEND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) ctrl &= ~0x30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) out_le32(&info->platinum_regs->ctrl.r, ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* TODO: Figure out how the heck to powerdown this thing! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) u_int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct fb_info_platinum *pinfo = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (regno > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) pinfo->palette[regno].red = red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) pinfo->palette[regno].green = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) pinfo->palette[regno].blue = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) out_8(&cmap_regs->addr, regno); /* tell clut what addr to fill */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) out_8(&cmap_regs->lut, red); /* send one color channel at */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) out_8(&cmap_regs->lut, green); /* a time... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) out_8(&cmap_regs->lut, blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) u32 *pal = info->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) switch (pinfo->cmode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) case CMODE_16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pal[regno] = (regno << 10) | (regno << 5) | regno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) case CMODE_32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) i = (regno << 8) | regno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) pal[regno] = (i << 16) | i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static inline int platinum_vram_reqd(int video_mode, int color_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) int baseval = vmode_attrs[video_mode-1].hres * (1<<color_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if ((video_mode == VMODE_832_624_75) && (color_mode > CMODE_8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) baseval += 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) baseval += 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return vmode_attrs[video_mode-1].vres * baseval + 0x1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #define STORE_D2(a, d) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) out_8(&cmap_regs->addr, (a+32)); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) out_8(&cmap_regs->d2, (d)); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static void set_platinum_clock(struct fb_info_platinum *pinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct platinum_regvals *init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) init = platinum_reg_init[pinfo->vmode-1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) STORE_D2(6, 0xc6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) out_8(&cmap_regs->addr,3+32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (in_8(&cmap_regs->d2) == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) STORE_D2(7, init->clock_params[pinfo->clktype][0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) STORE_D2(8, init->clock_params[pinfo->clktype][1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) STORE_D2(3, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) STORE_D2(4, init->clock_params[pinfo->clktype][0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) STORE_D2(5, init->clock_params[pinfo->clktype][1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) STORE_D2(3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) __delay(5000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) STORE_D2(9, 0xa6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) /* Now how about actually saying, Make it so! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* Some things in here probably don't need to be done each time. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static void platinum_set_hardware(struct fb_info_platinum *pinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) volatile struct platinum_regs __iomem *platinum_regs = pinfo->platinum_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) volatile struct cmap_regs __iomem *cmap_regs = pinfo->cmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct platinum_regvals *init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int vmode, cmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) vmode = pinfo->vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) cmode = pinfo->cmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) init = platinum_reg_init[vmode - 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /* Initialize display timing registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) out_be32(&platinum_regs->reg[24].r, 7); /* turn display off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) for (i = 0; i < 26; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) out_be32(&platinum_regs->reg[i+32].r, init->regs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) out_be32(&platinum_regs->reg[26+32].r, (pinfo->total_vram == 0x100000 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) init->offset[cmode] + 4 - cmode :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) init->offset[cmode]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) out_be32(&platinum_regs->reg[16].r, (unsigned) pinfo->frame_buffer_phys+init->fb_offset+0x10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) out_be32(&platinum_regs->reg[19].r, (pinfo->total_vram == 0x100000 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) init->mode[cmode+1] :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) init->mode[cmode]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) out_be32(&platinum_regs->reg[20].r, (pinfo->total_vram == 0x100000 ? 0x11 : 0x1011));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) out_be32(&platinum_regs->reg[21].r, 0x100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) out_be32(&platinum_regs->reg[22].r, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) out_be32(&platinum_regs->reg[23].r, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) out_be32(&platinum_regs->reg[26].r, 0xc00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) out_be32(&platinum_regs->reg[27].r, 0x235);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /* out_be32(&platinum_regs->reg[27].r, 0x2aa); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) STORE_D2(0, (pinfo->total_vram == 0x100000 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) init->dacula_ctrl[cmode] & 0xf :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) init->dacula_ctrl[cmode]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) STORE_D2(1, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) STORE_D2(2, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) set_platinum_clock(pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) out_be32(&platinum_regs->reg[24].r, 0); /* turn display on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * Set misc info vars for this driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static void platinum_init_info(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) struct fb_info_platinum *pinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /* Fill fb_info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) info->fbops = &platinumfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) info->pseudo_palette = pinfo->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) info->flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) info->screen_base = pinfo->frame_buffer + 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /* Fill fix common fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) strcpy(info->fix.id, "platinum");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) info->fix.mmio_start = pinfo->platinum_regs_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) info->fix.mmio_len = 0x1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) info->fix.smem_start = pinfo->frame_buffer_phys + 0x20; /* will be updated later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) info->fix.smem_len = pinfo->total_vram - 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) info->fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) info->fix.xpanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) info->fix.ypanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) info->fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) info->fix.accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static int platinum_init_fb(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct fb_info_platinum *pinfo = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct fb_var_screeninfo var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) int sense, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) sense = read_platinum_sense(pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (IS_REACHABLE(CONFIG_NVRAM) && default_vmode == VMODE_NVRAM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) default_vmode = nvram_read_byte(NV_VMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) !platinum_reg_init[default_vmode - 1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) default_vmode = mac_map_monitor_sense(sense);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (!platinum_reg_init[default_vmode - 1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) default_vmode = VMODE_640_480_60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) default_cmode = nvram_read_byte(NV_CMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) default_cmode = CMODE_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) * Reduce the pixel size if we don't have enough VRAM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) while(default_cmode > CMODE_8 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) platinum_vram_reqd(default_vmode, default_cmode) > pinfo->total_vram)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) default_cmode--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) printk("platinumfb: Using video mode %d and color mode %d.\n", default_vmode, default_cmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) /* Setup default var */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* This shouldn't happen! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) printk("mac_vmode_to_var(%d, %d,) failed\n", default_vmode, default_cmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) try_again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) default_vmode = VMODE_640_480_60;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) default_cmode = CMODE_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) printk(KERN_ERR "platinumfb: mac_vmode_to_var() failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /* Initialize info structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) platinum_init_info(info, pinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /* Apply default var */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) info->var = var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) rc = fb_set_var(info, &var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (rc && (default_vmode != VMODE_640_480_60 || default_cmode != CMODE_8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) goto try_again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /* Register with fbdev layer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) rc = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) fb_info(info, "Apple Platinum frame buffer device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * Get the monitor sense value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * Note that this can be called before calibrate_delay,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * so we can't use udelay.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) static int read_platinum_sense(struct fb_info_platinum *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) volatile struct platinum_regs __iomem *platinum_regs = info->platinum_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) int sense;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) __delay(2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* drive each sense line low in turn and collect the other 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) out_be32(&platinum_regs->reg[23].r, 3); /* drive A low */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) __delay(2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) out_be32(&platinum_regs->reg[23].r, 5); /* drive B low */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) __delay(2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) out_be32(&platinum_regs->reg[23].r, 6); /* drive C low */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) __delay(2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return sense;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * This routine takes a user-supplied var, and picks the best vmode/cmode from it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * It also updates the var structure to the actual mode data obtained
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static int platinum_var_to_par(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) struct fb_info_platinum *pinfo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) int check_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) int vmode, cmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (mac_var_to_vmode(var, &vmode, &cmode) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (!platinum_reg_init[vmode-1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (platinum_vram_reqd(vmode, cmode) > pinfo->total_vram) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", vmode, cmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (mac_vmode_to_var(vmode, cmode, var))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (check_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pinfo->vmode = vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) pinfo->cmode = cmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) pinfo->xres = vmode_attrs[vmode-1].hres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) pinfo->yres = vmode_attrs[vmode-1].vres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) pinfo->xoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) pinfo->yoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) pinfo->vxres = pinfo->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) pinfo->vyres = pinfo->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * Parse user specified options (`video=platinumfb:')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) static int __init platinumfb_setup(char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) char *this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) while ((this_opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (!strncmp(this_opt, "vmode:", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) int vmode = simple_strtoul(this_opt+6, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (vmode > 0 && vmode <= VMODE_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) default_vmode = vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) } else if (!strncmp(this_opt, "cmode:", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) int depth = simple_strtoul(this_opt+6, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) switch (depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) default_cmode = CMODE_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) case 15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) default_cmode = CMODE_16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) default_cmode = CMODE_32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) #ifdef __powerpc__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) #define invalidate_cache(addr) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) asm volatile("eieio; dcbf 0,%1" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) : "=m" (*(addr)) : "r" (addr) : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) #define invalidate_cache(addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) static int platinumfb_probe(struct platform_device* odev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) struct device_node *dp = odev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) struct fb_info_platinum *pinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) volatile __u8 *fbuffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) int bank0, bank1, bank2, bank3, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) dev_info(&odev->dev, "Found Apple Platinum video hardware\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) pinfo = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) dev_err(&odev->dev, "Can't get resources\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) (unsigned long long)pinfo->rsrc_reg.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) (unsigned long long)pinfo->rsrc_reg.end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) (unsigned long long)pinfo->rsrc_fb.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) (unsigned long long)pinfo->rsrc_fb.end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* Do not try to request register space, they overlap with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * northbridge and that can fail. Only request framebuffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (!request_mem_region(pinfo->rsrc_fb.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) resource_size(&pinfo->rsrc_fb),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) "platinumfb framebuffer")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) printk(KERN_ERR "platinumfb: Can't request framebuffer !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) /* frame buffer - map only 4MB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) pinfo->frame_buffer_phys = pinfo->rsrc_fb.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) pinfo->frame_buffer = ioremap_wt(pinfo->rsrc_fb.start, 0x400000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) pinfo->base_frame_buffer = pinfo->frame_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /* registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) pinfo->platinum_regs_phys = pinfo->rsrc_reg.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) pinfo->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) pinfo->cmap_regs = ioremap(pinfo->cmap_regs_phys, 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) /* Grok total video ram */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) out_be32(&pinfo->platinum_regs->reg[16].r, (unsigned)pinfo->frame_buffer_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) out_be32(&pinfo->platinum_regs->reg[20].r, 0x1011); /* select max vram */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) out_be32(&pinfo->platinum_regs->reg[24].r, 0); /* switch in vram */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) fbuffer = pinfo->base_frame_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) fbuffer[0x100000] = 0x34;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) fbuffer[0x100008] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) invalidate_cache(&fbuffer[0x100000]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) fbuffer[0x200000] = 0x56;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) fbuffer[0x200008] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) invalidate_cache(&fbuffer[0x200000]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) fbuffer[0x300000] = 0x78;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) fbuffer[0x300008] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) invalidate_cache(&fbuffer[0x300000]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) bank0 = 1; /* builtin 1MB vram, always there */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) bank1 = fbuffer[0x100000] == 0x34;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) bank2 = fbuffer[0x200000] == 0x56;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) bank3 = fbuffer[0x300000] == 0x78;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) (unsigned int) (pinfo->total_vram / 1024 / 1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) bank3, bank2, bank1, bank0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) * Try to determine whether we have an old or a new DACula.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) out_8(&pinfo->cmap_regs->addr, 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) pinfo->dactype = in_8(&pinfo->cmap_regs->d2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) switch (pinfo->dactype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) case 0x3c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) pinfo->clktype = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) printk(KERN_INFO "platinumfb: DACula type 0x3c\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) case 0x84:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) pinfo->clktype = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) printk(KERN_INFO "platinumfb: DACula type 0x84\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) pinfo->clktype = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) printk(KERN_INFO "platinumfb: Unknown DACula type: %x\n", pinfo->dactype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) dev_set_drvdata(&odev->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) rc = platinum_init_fb(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (rc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) iounmap(pinfo->frame_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) iounmap(pinfo->platinum_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) iounmap(pinfo->cmap_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) static int platinumfb_remove(struct platform_device* odev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) struct fb_info *info = dev_get_drvdata(&odev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) struct fb_info_platinum *pinfo = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) unregister_framebuffer (info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) /* Unmap frame buffer and registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) iounmap(pinfo->frame_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) iounmap(pinfo->platinum_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) iounmap(pinfo->cmap_regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) release_mem_region(pinfo->rsrc_fb.start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) resource_size(&pinfo->rsrc_fb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) release_mem_region(pinfo->cmap_regs_phys, 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static struct of_device_id platinumfb_match[] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) .name = "platinum",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) static struct platform_driver platinum_driver =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) .name = "platinumfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) .of_match_table = platinumfb_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) .probe = platinumfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) .remove = platinumfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) static int __init platinumfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) char *option = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (fb_get_options("platinumfb", &option))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) platinumfb_setup(option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) platform_driver_register(&platinum_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) static void __exit platinumfb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) platform_driver_unregister(&platinum_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) MODULE_DESCRIPTION("framebuffer driver for Apple Platinum video");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) module_init(platinumfb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) module_exit(platinumfb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) #endif