162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * valkyriefb.c -- frame buffer device for the PowerMac 'valkyrie' display 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Created 8 August 1998 by 562306a36Sopenharmony_ci * Martin Costabel <costabel@wanadoo.fr> and Kevin Schoedel 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Vmode-switching changes and vmode 15/17 modifications created 29 August 862306a36Sopenharmony_ci * 1998 by Barry K. Nathan <barryn@pobox.com>. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Ported to m68k Macintosh by David Huggins-Daines <dhd@debian.org> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Derived directly from: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * controlfb.c -- frame buffer device for the PowerMac 'control' display 1562306a36Sopenharmony_ci * Copyright (C) 1998 Dan Jacobowitz <dan@debian.org> 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * pmc-valkyrie.c -- Console support for PowerMac "valkyrie" display adaptor. 1862306a36Sopenharmony_ci * Copyright (C) 1997 Paul Mackerras. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * and indirectly: 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Frame buffer structure from: 2362306a36Sopenharmony_ci * drivers/video/chipsfb.c -- frame buffer device for 2462306a36Sopenharmony_ci * Chips & Technologies 65550 chip. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Copyright (C) 1998 Paul Mackerras 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * This file is derived from the Powermac "chips" driver: 2962306a36Sopenharmony_ci * Copyright (C) 1997 Fabio Riccardi. 3062306a36Sopenharmony_ci * And from the frame buffer device for Open Firmware-initialized devices: 3162306a36Sopenharmony_ci * Copyright (C) 1997 Geert Uytterhoeven. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Hardware information from: 3462306a36Sopenharmony_ci * control.c: Console support for PowerMac "control" display adaptor. 3562306a36Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 3862306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 3962306a36Sopenharmony_ci * more details. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include <linux/module.h> 4362306a36Sopenharmony_ci#include <linux/kernel.h> 4462306a36Sopenharmony_ci#include <linux/errno.h> 4562306a36Sopenharmony_ci#include <linux/string.h> 4662306a36Sopenharmony_ci#include <linux/mm.h> 4762306a36Sopenharmony_ci#include <linux/slab.h> 4862306a36Sopenharmony_ci#include <linux/vmalloc.h> 4962306a36Sopenharmony_ci#include <linux/delay.h> 5062306a36Sopenharmony_ci#include <linux/interrupt.h> 5162306a36Sopenharmony_ci#include <linux/fb.h> 5262306a36Sopenharmony_ci#include <linux/selection.h> 5362306a36Sopenharmony_ci#include <linux/init.h> 5462306a36Sopenharmony_ci#include <linux/nvram.h> 5562306a36Sopenharmony_ci#include <linux/adb.h> 5662306a36Sopenharmony_ci#include <linux/cuda.h> 5762306a36Sopenharmony_ci#include <linux/of_address.h> 5862306a36Sopenharmony_ci#ifdef CONFIG_MAC 5962306a36Sopenharmony_ci#include <asm/macintosh.h> 6062306a36Sopenharmony_ci#endif 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#include "macmodes.h" 6362306a36Sopenharmony_ci#include "valkyriefb.h" 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int default_vmode = VMODE_NVRAM; 6662306a36Sopenharmony_cistatic int default_cmode = CMODE_NVRAM; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct fb_par_valkyrie { 6962306a36Sopenharmony_ci int vmode, cmode; 7062306a36Sopenharmony_ci int xres, yres; 7162306a36Sopenharmony_ci int vxres, vyres; 7262306a36Sopenharmony_ci struct valkyrie_regvals *init; 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistruct fb_info_valkyrie { 7662306a36Sopenharmony_ci struct fb_info info; 7762306a36Sopenharmony_ci struct fb_par_valkyrie par; 7862306a36Sopenharmony_ci struct cmap_regs __iomem *cmap_regs; 7962306a36Sopenharmony_ci unsigned long cmap_regs_phys; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci struct valkyrie_regs __iomem *valkyrie_regs; 8262306a36Sopenharmony_ci unsigned long valkyrie_regs_phys; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci __u8 __iomem *frame_buffer; 8562306a36Sopenharmony_ci unsigned long frame_buffer_phys; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci int sense; 8862306a36Sopenharmony_ci unsigned long total_vram; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci u32 pseudo_palette[16]; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int valkyriefb_setup(char*); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int valkyriefb_check_var(struct fb_var_screeninfo *var, 9662306a36Sopenharmony_ci struct fb_info *info); 9762306a36Sopenharmony_cistatic int valkyriefb_set_par(struct fb_info *info); 9862306a36Sopenharmony_cistatic int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 9962306a36Sopenharmony_ci u_int transp, struct fb_info *info); 10062306a36Sopenharmony_cistatic int valkyriefb_blank(int blank_mode, struct fb_info *info); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int read_valkyrie_sense(struct fb_info_valkyrie *p); 10362306a36Sopenharmony_cistatic void set_valkyrie_clock(unsigned char *params); 10462306a36Sopenharmony_cistatic int valkyrie_var_to_par(struct fb_var_screeninfo *var, 10562306a36Sopenharmony_ci struct fb_par_valkyrie *par, const struct fb_info *fb_info); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p); 10862306a36Sopenharmony_cistatic void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix); 10962306a36Sopenharmony_cistatic void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic const struct fb_ops valkyriefb_ops = { 11262306a36Sopenharmony_ci .owner = THIS_MODULE, 11362306a36Sopenharmony_ci FB_DEFAULT_IOMEM_OPS, 11462306a36Sopenharmony_ci .fb_check_var = valkyriefb_check_var, 11562306a36Sopenharmony_ci .fb_set_par = valkyriefb_set_par, 11662306a36Sopenharmony_ci .fb_setcolreg = valkyriefb_setcolreg, 11762306a36Sopenharmony_ci .fb_blank = valkyriefb_blank, 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* Sets the video mode according to info->var */ 12162306a36Sopenharmony_cistatic int valkyriefb_set_par(struct fb_info *info) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct fb_info_valkyrie *p = 12462306a36Sopenharmony_ci container_of(info, struct fb_info_valkyrie, info); 12562306a36Sopenharmony_ci volatile struct valkyrie_regs __iomem *valkyrie_regs = p->valkyrie_regs; 12662306a36Sopenharmony_ci struct fb_par_valkyrie *par = info->par; 12762306a36Sopenharmony_ci struct valkyrie_regvals *init; 12862306a36Sopenharmony_ci int err; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if ((err = valkyrie_var_to_par(&info->var, par, info))) 13162306a36Sopenharmony_ci return err; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci valkyrie_par_to_fix(par, &info->fix); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Reset the valkyrie */ 13662306a36Sopenharmony_ci out_8(&valkyrie_regs->status.r, 0); 13762306a36Sopenharmony_ci udelay(100); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Initialize display timing registers */ 14062306a36Sopenharmony_ci init = par->init; 14162306a36Sopenharmony_ci out_8(&valkyrie_regs->mode.r, init->mode | 0x80); 14262306a36Sopenharmony_ci out_8(&valkyrie_regs->depth.r, par->cmode + 3); 14362306a36Sopenharmony_ci set_valkyrie_clock(init->clock_params); 14462306a36Sopenharmony_ci udelay(100); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* Turn on display */ 14762306a36Sopenharmony_ci out_8(&valkyrie_regs->mode.r, init->mode); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic inline int valkyrie_par_to_var(struct fb_par_valkyrie *par, 15362306a36Sopenharmony_ci struct fb_var_screeninfo *var) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return mac_vmode_to_var(par->vmode, par->cmode, var); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int 15962306a36Sopenharmony_civalkyriefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci int err; 16262306a36Sopenharmony_ci struct fb_par_valkyrie par; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if ((err = valkyrie_var_to_par(var, &par, info))) 16562306a36Sopenharmony_ci return err; 16662306a36Sopenharmony_ci valkyrie_par_to_var(&par, var); 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * Blank the screen if blank_mode != 0, else unblank. If blank_mode == NULL 17262306a36Sopenharmony_ci * then the caller blanks by setting the CLUT (Color Look Up Table) to all 17362306a36Sopenharmony_ci * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due 17462306a36Sopenharmony_ci * to e.g. a video mode which doesn't support it. Implements VESA suspend 17562306a36Sopenharmony_ci * and powerdown modes on hardware that supports disabling hsync/vsync: 17662306a36Sopenharmony_ci * blank_mode == 2: suspend vsync 17762306a36Sopenharmony_ci * blank_mode == 3: suspend hsync 17862306a36Sopenharmony_ci * blank_mode == 4: powerdown 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cistatic int valkyriefb_blank(int blank_mode, struct fb_info *info) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct fb_info_valkyrie *p = 18362306a36Sopenharmony_ci container_of(info, struct fb_info_valkyrie, info); 18462306a36Sopenharmony_ci struct fb_par_valkyrie *par = info->par; 18562306a36Sopenharmony_ci struct valkyrie_regvals *init = par->init; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (init == NULL) 18862306a36Sopenharmony_ci return 1; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci switch (blank_mode) { 19162306a36Sopenharmony_ci case FB_BLANK_UNBLANK: /* unblank */ 19262306a36Sopenharmony_ci out_8(&p->valkyrie_regs->mode.r, init->mode); 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci case FB_BLANK_NORMAL: 19562306a36Sopenharmony_ci return 1; /* get caller to set CLUT to all black */ 19662306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 19762306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * [kps] Value extracted from MacOS. I don't know 20062306a36Sopenharmony_ci * whether this bit disables hsync or vsync, or 20162306a36Sopenharmony_ci * whether the hardware can do the other as well. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci out_8(&p->valkyrie_regs->mode.r, init->mode | 0x40); 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 20662306a36Sopenharmony_ci out_8(&p->valkyrie_regs->mode.r, 0x66); 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 21362306a36Sopenharmony_ci u_int transp, struct fb_info *info) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct fb_info_valkyrie *p = 21662306a36Sopenharmony_ci container_of(info, struct fb_info_valkyrie, info); 21762306a36Sopenharmony_ci volatile struct cmap_regs __iomem *cmap_regs = p->cmap_regs; 21862306a36Sopenharmony_ci struct fb_par_valkyrie *par = info->par; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (regno > 255) 22162306a36Sopenharmony_ci return 1; 22262306a36Sopenharmony_ci red >>= 8; 22362306a36Sopenharmony_ci green >>= 8; 22462306a36Sopenharmony_ci blue >>= 8; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* tell clut which address to fill */ 22762306a36Sopenharmony_ci out_8(&p->cmap_regs->addr, regno); 22862306a36Sopenharmony_ci udelay(1); 22962306a36Sopenharmony_ci /* send one color channel at a time */ 23062306a36Sopenharmony_ci out_8(&cmap_regs->lut, red); 23162306a36Sopenharmony_ci out_8(&cmap_regs->lut, green); 23262306a36Sopenharmony_ci out_8(&cmap_regs->lut, blue); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (regno < 16 && par->cmode == CMODE_16) 23562306a36Sopenharmony_ci ((u32 *)info->pseudo_palette)[regno] = 23662306a36Sopenharmony_ci (regno << 10) | (regno << 5) | regno; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic inline int valkyrie_vram_reqd(int video_mode, int color_mode) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci int pitch; 24462306a36Sopenharmony_ci struct valkyrie_regvals *init = valkyrie_reg_init[video_mode-1]; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if ((pitch = init->pitch[color_mode]) == 0) 24762306a36Sopenharmony_ci pitch = 2 * init->pitch[0]; 24862306a36Sopenharmony_ci return init->vres * pitch; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void set_valkyrie_clock(unsigned char *params) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci#ifdef CONFIG_ADB_CUDA 25462306a36Sopenharmony_ci struct adb_request req; 25562306a36Sopenharmony_ci int i; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < 3; ++i) { 25862306a36Sopenharmony_ci cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 25962306a36Sopenharmony_ci 0x50, i + 1, params[i]); 26062306a36Sopenharmony_ci while (!req.complete) 26162306a36Sopenharmony_ci cuda_poll(); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci#endif 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void __init valkyrie_choose_mode(struct fb_info_valkyrie *p) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci p->sense = read_valkyrie_sense(p); 26962306a36Sopenharmony_ci printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Try to pick a video mode out of NVRAM if we have one. */ 27262306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 27362306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_NVRAM) && default_vmode == VMODE_NVRAM) 27462306a36Sopenharmony_ci default_vmode = nvram_read_byte(NV_VMODE); 27562306a36Sopenharmony_ci#endif 27662306a36Sopenharmony_ci if (default_vmode <= 0 || default_vmode > VMODE_MAX || 27762306a36Sopenharmony_ci !valkyrie_reg_init[default_vmode - 1]) { 27862306a36Sopenharmony_ci default_vmode = mac_map_monitor_sense(p->sense); 27962306a36Sopenharmony_ci if (!valkyrie_reg_init[default_vmode - 1]) 28062306a36Sopenharmony_ci default_vmode = VMODE_640_480_67; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 28462306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM) 28562306a36Sopenharmony_ci default_cmode = nvram_read_byte(NV_CMODE); 28662306a36Sopenharmony_ci#endif 28762306a36Sopenharmony_ci /* 28862306a36Sopenharmony_ci * Reduce the pixel size if we don't have enough VRAM or bandwidth. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci if (default_cmode < CMODE_8 || default_cmode > CMODE_16 29162306a36Sopenharmony_ci || valkyrie_reg_init[default_vmode-1]->pitch[default_cmode] == 0 29262306a36Sopenharmony_ci || valkyrie_vram_reqd(default_vmode, default_cmode) > p->total_vram) 29362306a36Sopenharmony_ci default_cmode = CMODE_8; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci printk(KERN_INFO "using video mode %d and color mode %d.\n", 29662306a36Sopenharmony_ci default_vmode, default_cmode); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int __init valkyriefb_init(void) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct fb_info_valkyrie *p; 30262306a36Sopenharmony_ci unsigned long frame_buffer_phys, cmap_regs_phys; 30362306a36Sopenharmony_ci int err; 30462306a36Sopenharmony_ci char *option = NULL; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (fb_get_options("valkyriefb", &option)) 30762306a36Sopenharmony_ci return -ENODEV; 30862306a36Sopenharmony_ci valkyriefb_setup(option); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci#ifdef CONFIG_MAC 31162306a36Sopenharmony_ci if (!MACH_IS_MAC) 31262306a36Sopenharmony_ci return -ENODEV; 31362306a36Sopenharmony_ci if (!(mac_bi_data.id == MAC_MODEL_Q630 31462306a36Sopenharmony_ci /* I'm not sure about this one */ 31562306a36Sopenharmony_ci || mac_bi_data.id == MAC_MODEL_P588)) 31662306a36Sopenharmony_ci return -ENODEV; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Hardcoded addresses... welcome to 68k Macintosh country :-) */ 31962306a36Sopenharmony_ci frame_buffer_phys = 0xf9000000; 32062306a36Sopenharmony_ci cmap_regs_phys = 0x50f24000; 32162306a36Sopenharmony_ci#else /* ppc (!CONFIG_MAC) */ 32262306a36Sopenharmony_ci { 32362306a36Sopenharmony_ci struct device_node *dp; 32462306a36Sopenharmony_ci struct resource r; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci dp = of_find_node_by_name(NULL, "valkyrie"); 32762306a36Sopenharmony_ci if (!dp) 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (of_address_to_resource(dp, 0, &r)) { 33162306a36Sopenharmony_ci printk(KERN_ERR "can't find address for valkyrie\n"); 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci frame_buffer_phys = r.start; 33662306a36Sopenharmony_ci cmap_regs_phys = r.start + 0x304000; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci#endif /* ppc (!CONFIG_MAC) */ 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci p = kzalloc(sizeof(*p), GFP_ATOMIC); 34162306a36Sopenharmony_ci if (!p) 34262306a36Sopenharmony_ci return -ENOMEM; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Map in frame buffer and registers */ 34562306a36Sopenharmony_ci if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { 34662306a36Sopenharmony_ci kfree(p); 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci p->total_vram = 0x100000; 35062306a36Sopenharmony_ci p->frame_buffer_phys = frame_buffer_phys; 35162306a36Sopenharmony_ci#ifdef CONFIG_MAC 35262306a36Sopenharmony_ci p->frame_buffer = ioremap(frame_buffer_phys, p->total_vram); 35362306a36Sopenharmony_ci#else 35462306a36Sopenharmony_ci p->frame_buffer = ioremap_wt(frame_buffer_phys, p->total_vram); 35562306a36Sopenharmony_ci#endif 35662306a36Sopenharmony_ci p->cmap_regs_phys = cmap_regs_phys; 35762306a36Sopenharmony_ci p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); 35862306a36Sopenharmony_ci p->valkyrie_regs_phys = cmap_regs_phys+0x6000; 35962306a36Sopenharmony_ci p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, 0x1000); 36062306a36Sopenharmony_ci err = -ENOMEM; 36162306a36Sopenharmony_ci if (p->frame_buffer == NULL || p->cmap_regs == NULL 36262306a36Sopenharmony_ci || p->valkyrie_regs == NULL) { 36362306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: couldn't map resources\n"); 36462306a36Sopenharmony_ci goto out_free; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci valkyrie_choose_mode(p); 36862306a36Sopenharmony_ci mac_vmode_to_var(default_vmode, default_cmode, &p->info.var); 36962306a36Sopenharmony_ci err = valkyrie_init_info(&p->info, p); 37062306a36Sopenharmony_ci if (err < 0) 37162306a36Sopenharmony_ci goto out_free; 37262306a36Sopenharmony_ci valkyrie_init_fix(&p->info.fix, p); 37362306a36Sopenharmony_ci if (valkyriefb_set_par(&p->info)) 37462306a36Sopenharmony_ci /* "can't happen" */ 37562306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: can't set default video mode\n"); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if ((err = register_framebuffer(&p->info)) != 0) 37862306a36Sopenharmony_ci goto out_cmap_free; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci fb_info(&p->info, "valkyrie frame buffer device\n"); 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci out_cmap_free: 38462306a36Sopenharmony_ci fb_dealloc_cmap(&p->info.cmap); 38562306a36Sopenharmony_ci out_free: 38662306a36Sopenharmony_ci if (p->frame_buffer) 38762306a36Sopenharmony_ci iounmap(p->frame_buffer); 38862306a36Sopenharmony_ci if (p->cmap_regs) 38962306a36Sopenharmony_ci iounmap(p->cmap_regs); 39062306a36Sopenharmony_ci if (p->valkyrie_regs) 39162306a36Sopenharmony_ci iounmap(p->valkyrie_regs); 39262306a36Sopenharmony_ci kfree(p); 39362306a36Sopenharmony_ci return err; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* 39762306a36Sopenharmony_ci * Get the monitor sense value. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_cistatic int read_valkyrie_sense(struct fb_info_valkyrie *p) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci int sense, in; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci out_8(&p->valkyrie_regs->msense.r, 0); /* release all lines */ 40462306a36Sopenharmony_ci __delay(20000); 40562306a36Sopenharmony_ci sense = ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x70) << 4; 40662306a36Sopenharmony_ci /* drive each sense line low in turn and collect the other 2 */ 40762306a36Sopenharmony_ci out_8(&p->valkyrie_regs->msense.r, 4); /* drive A low */ 40862306a36Sopenharmony_ci __delay(20000); 40962306a36Sopenharmony_ci sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x30); 41062306a36Sopenharmony_ci out_8(&p->valkyrie_regs->msense.r, 2); /* drive B low */ 41162306a36Sopenharmony_ci __delay(20000); 41262306a36Sopenharmony_ci sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x40) >> 3; 41362306a36Sopenharmony_ci sense |= (in & 0x10) >> 2; 41462306a36Sopenharmony_ci out_8(&p->valkyrie_regs->msense.r, 1); /* drive C low */ 41562306a36Sopenharmony_ci __delay(20000); 41662306a36Sopenharmony_ci sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x60) >> 5; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci out_8(&p->valkyrie_regs->msense.r, 7); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return sense; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* 42462306a36Sopenharmony_ci * This routine takes a user-supplied var, 42562306a36Sopenharmony_ci * and picks the best vmode/cmode from it. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* [bkn] I did a major overhaul of this function. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * Much of the old code was "swiped by jonh from atyfb.c". Because 43162306a36Sopenharmony_ci * macmodes has mac_var_to_vmode, I felt that it would be better to 43262306a36Sopenharmony_ci * rework this function to use that, instead of reinventing the wheel to 43362306a36Sopenharmony_ci * add support for vmode 17. This was reinforced by the fact that 43462306a36Sopenharmony_ci * the previously swiped atyfb.c code is no longer there. 43562306a36Sopenharmony_ci * 43662306a36Sopenharmony_ci * So, I swiped and adapted platinum_var_to_par (from platinumfb.c), replacing 43762306a36Sopenharmony_ci * most, but not all, of the old code in the process. One side benefit of 43862306a36Sopenharmony_ci * swiping the platinumfb code is that we now have more comprehensible error 43962306a36Sopenharmony_ci * messages when a vmode/cmode switch fails. (Most of the error messages are 44062306a36Sopenharmony_ci * platinumfb.c, but I added two of my own, and I also changed some commas 44162306a36Sopenharmony_ci * into colons to make the messages more consistent with other Linux error 44262306a36Sopenharmony_ci * messages.) In addition, I think the new code *might* fix some vmode- 44362306a36Sopenharmony_ci * switching oddities, but I'm not sure. 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * There may be some more opportunities for cleanup in here, but this is a 44662306a36Sopenharmony_ci * good start... 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int valkyrie_var_to_par(struct fb_var_screeninfo *var, 45062306a36Sopenharmony_ci struct fb_par_valkyrie *par, const struct fb_info *fb_info) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci int vmode, cmode; 45362306a36Sopenharmony_ci struct valkyrie_regvals *init; 45462306a36Sopenharmony_ci struct fb_info_valkyrie *p = 45562306a36Sopenharmony_ci container_of(fb_info, struct fb_info_valkyrie, info); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (mac_var_to_vmode(var, &vmode, &cmode) != 0) { 45862306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: can't do %dx%dx%d.\n", 45962306a36Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel); 46062306a36Sopenharmony_ci return -EINVAL; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Check if we know about the wanted video mode */ 46462306a36Sopenharmony_ci if (vmode < 1 || vmode > VMODE_MAX || !valkyrie_reg_init[vmode-1]) { 46562306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: vmode %d not valid.\n", vmode); 46662306a36Sopenharmony_ci return -EINVAL; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (cmode != CMODE_8 && cmode != CMODE_16) { 47062306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: cmode %d not valid.\n", cmode); 47162306a36Sopenharmony_ci return -EINVAL; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (var->xres_virtual > var->xres || var->yres_virtual > var->yres 47562306a36Sopenharmony_ci || var->xoffset != 0 || var->yoffset != 0) { 47662306a36Sopenharmony_ci return -EINVAL; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci init = valkyrie_reg_init[vmode-1]; 48062306a36Sopenharmony_ci if (init->pitch[cmode] == 0) { 48162306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: vmode %d does not support " 48262306a36Sopenharmony_ci "cmode %d.\n", vmode, cmode); 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (valkyrie_vram_reqd(vmode, cmode) > p->total_vram) { 48762306a36Sopenharmony_ci printk(KERN_ERR "valkyriefb: not enough ram for vmode %d, " 48862306a36Sopenharmony_ci "cmode %d.\n", vmode, cmode); 48962306a36Sopenharmony_ci return -EINVAL; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci par->vmode = vmode; 49362306a36Sopenharmony_ci par->cmode = cmode; 49462306a36Sopenharmony_ci par->init = init; 49562306a36Sopenharmony_ci par->xres = var->xres; 49662306a36Sopenharmony_ci par->yres = var->yres; 49762306a36Sopenharmony_ci par->vxres = par->xres; 49862306a36Sopenharmony_ci par->vyres = par->yres; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci memset(fix, 0, sizeof(*fix)); 50662306a36Sopenharmony_ci strcpy(fix->id, "valkyrie"); 50762306a36Sopenharmony_ci fix->mmio_start = p->valkyrie_regs_phys; 50862306a36Sopenharmony_ci fix->mmio_len = sizeof(struct valkyrie_regs); 50962306a36Sopenharmony_ci fix->type = FB_TYPE_PACKED_PIXELS; 51062306a36Sopenharmony_ci fix->smem_start = p->frame_buffer_phys + 0x1000; 51162306a36Sopenharmony_ci fix->smem_len = p->total_vram; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci fix->type_aux = 0; 51462306a36Sopenharmony_ci fix->ywrapstep = 0; 51562306a36Sopenharmony_ci fix->ypanstep = 0; 51662306a36Sopenharmony_ci fix->xpanstep = 0; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* Fix must already be inited above */ 52162306a36Sopenharmony_cistatic void valkyrie_par_to_fix(struct fb_par_valkyrie *par, 52262306a36Sopenharmony_ci struct fb_fix_screeninfo *fix) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci fix->smem_len = valkyrie_vram_reqd(par->vmode, par->cmode); 52562306a36Sopenharmony_ci fix->visual = (par->cmode == CMODE_8) ? 52662306a36Sopenharmony_ci FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; 52762306a36Sopenharmony_ci fix->line_length = par->vxres << par->cmode; 52862306a36Sopenharmony_ci /* ywrapstep, xpanstep, ypanstep */ 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic int __init valkyrie_init_info(struct fb_info *info, 53262306a36Sopenharmony_ci struct fb_info_valkyrie *p) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci info->fbops = &valkyriefb_ops; 53562306a36Sopenharmony_ci info->screen_base = p->frame_buffer + 0x1000; 53662306a36Sopenharmony_ci info->pseudo_palette = p->pseudo_palette; 53762306a36Sopenharmony_ci info->par = &p->par; 53862306a36Sopenharmony_ci return fb_alloc_cmap(&info->cmap, 256, 0); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * Parse user specified options (`video=valkyriefb:') 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistatic int __init valkyriefb_setup(char *options) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci char *this_opt; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (!options || !*options) 55062306a36Sopenharmony_ci return 0; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 55362306a36Sopenharmony_ci if (!strncmp(this_opt, "vmode:", 6)) { 55462306a36Sopenharmony_ci int vmode = simple_strtoul(this_opt+6, NULL, 0); 55562306a36Sopenharmony_ci if (vmode > 0 && vmode <= VMODE_MAX) 55662306a36Sopenharmony_ci default_vmode = vmode; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci else if (!strncmp(this_opt, "cmode:", 6)) { 55962306a36Sopenharmony_ci int depth = simple_strtoul(this_opt+6, NULL, 0); 56062306a36Sopenharmony_ci switch (depth) { 56162306a36Sopenharmony_ci case 8: 56262306a36Sopenharmony_ci default_cmode = CMODE_8; 56362306a36Sopenharmony_ci break; 56462306a36Sopenharmony_ci case 15: 56562306a36Sopenharmony_ci case 16: 56662306a36Sopenharmony_ci default_cmode = CMODE_16; 56762306a36Sopenharmony_ci break; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cimodule_init(valkyriefb_init); 57562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 576