162306a36Sopenharmony_ci/* $Id: g364fb.c,v 1.3 1998/08/28 22:43:00 tsbogend Exp $ 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * linux/drivers/video/g364fb.c -- Mips Magnum frame buffer device 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) 1998 Thomas Bogendoerfer 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This driver is based on tgafb.c 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 1997 Geert Uytterhoeven 1062306a36Sopenharmony_ci * Copyright (C) 1995 Jay Estabrook 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 1362306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 1462306a36Sopenharmony_ci * more details. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/console.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/errno.h> 2162306a36Sopenharmony_ci#include <linux/string.h> 2262306a36Sopenharmony_ci#include <linux/mm.h> 2362306a36Sopenharmony_ci#include <linux/vmalloc.h> 2462306a36Sopenharmony_ci#include <linux/delay.h> 2562306a36Sopenharmony_ci#include <linux/interrupt.h> 2662306a36Sopenharmony_ci#include <linux/fb.h> 2762306a36Sopenharmony_ci#include <linux/init.h> 2862306a36Sopenharmony_ci#include <asm/io.h> 2962306a36Sopenharmony_ci#include <asm/jazz.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Various defines for the G364 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci#define G364_MEM_BASE 0xe4400000 3562306a36Sopenharmony_ci#define G364_PORT_BASE 0xe4000000 3662306a36Sopenharmony_ci#define ID_REG 0xe4000000 /* Read only */ 3762306a36Sopenharmony_ci#define BOOT_REG 0xe4080000 3862306a36Sopenharmony_ci#define TIMING_REG 0xe4080108 /* to 0x080170 - DON'T TOUCH! */ 3962306a36Sopenharmony_ci#define DISPLAY_REG 0xe4080118 4062306a36Sopenharmony_ci#define VDISPLAY_REG 0xe4080150 4162306a36Sopenharmony_ci#define MASK_REG 0xe4080200 4262306a36Sopenharmony_ci#define CTLA_REG 0xe4080300 4362306a36Sopenharmony_ci#define CURS_TOGGLE 0x800000 4462306a36Sopenharmony_ci#define BIT_PER_PIX 0x700000 /* bits 22 to 20 of Control A */ 4562306a36Sopenharmony_ci#define DELAY_SAMPLE 0x080000 4662306a36Sopenharmony_ci#define PORT_INTER 0x040000 4762306a36Sopenharmony_ci#define PIX_PIPE_DEL 0x030000 /* bits 17 and 16 of Control A */ 4862306a36Sopenharmony_ci#define PIX_PIPE_DEL2 0x008000 /* same as above - don't ask me why */ 4962306a36Sopenharmony_ci#define TR_CYCLE_TOG 0x004000 5062306a36Sopenharmony_ci#define VRAM_ADR_INC 0x003000 /* bits 13 and 12 of Control A */ 5162306a36Sopenharmony_ci#define BLANK_OFF 0x000800 5262306a36Sopenharmony_ci#define FORCE_BLANK 0x000400 5362306a36Sopenharmony_ci#define BLK_FUN_SWTCH 0x000200 5462306a36Sopenharmony_ci#define BLANK_IO 0x000100 5562306a36Sopenharmony_ci#define BLANK_LEVEL 0x000080 5662306a36Sopenharmony_ci#define A_VID_FORM 0x000040 5762306a36Sopenharmony_ci#define D_SYNC_FORM 0x000020 5862306a36Sopenharmony_ci#define FRAME_FLY_PAT 0x000010 5962306a36Sopenharmony_ci#define OP_MODE 0x000008 6062306a36Sopenharmony_ci#define INTL_STAND 0x000004 6162306a36Sopenharmony_ci#define SCRN_FORM 0x000002 6262306a36Sopenharmony_ci#define ENABLE_VTG 0x000001 6362306a36Sopenharmony_ci#define TOP_REG 0xe4080400 6462306a36Sopenharmony_ci#define CURS_PAL_REG 0xe4080508 /* to 0x080518 */ 6562306a36Sopenharmony_ci#define CHKSUM_REG 0xe4080600 /* to 0x080610 - unused */ 6662306a36Sopenharmony_ci#define CURS_POS_REG 0xe4080638 6762306a36Sopenharmony_ci#define CLR_PAL_REG 0xe4080800 /* to 0x080ff8 */ 6862306a36Sopenharmony_ci#define CURS_PAT_REG 0xe4081000 /* to 0x081ff8 */ 6962306a36Sopenharmony_ci#define MON_ID_REG 0xe4100000 /* unused */ 7062306a36Sopenharmony_ci#define RESET_REG 0xe4180000 /* Write only */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic struct fb_info fb_info; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct fb_fix_screeninfo fb_fix __initdata = { 7562306a36Sopenharmony_ci .id = "G364 8plane", 7662306a36Sopenharmony_ci .smem_start = 0x40000000, /* physical address */ 7762306a36Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 7862306a36Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 7962306a36Sopenharmony_ci .ypanstep = 1, 8062306a36Sopenharmony_ci .accel = FB_ACCEL_NONE, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct fb_var_screeninfo fb_var __initdata = { 8462306a36Sopenharmony_ci .bits_per_pixel = 8, 8562306a36Sopenharmony_ci .red = { 0, 8, 0 }, 8662306a36Sopenharmony_ci .green = { 0, 8, 0 }, 8762306a36Sopenharmony_ci .blue = { 0, 8, 0 }, 8862306a36Sopenharmony_ci .activate = FB_ACTIVATE_NOW, 8962306a36Sopenharmony_ci .height = -1, 9062306a36Sopenharmony_ci .width = -1, 9162306a36Sopenharmony_ci .pixclock = 39722, 9262306a36Sopenharmony_ci .left_margin = 40, 9362306a36Sopenharmony_ci .right_margin = 24, 9462306a36Sopenharmony_ci .upper_margin = 32, 9562306a36Sopenharmony_ci .lower_margin = 11, 9662306a36Sopenharmony_ci .hsync_len = 96, 9762306a36Sopenharmony_ci .vsync_len = 2, 9862306a36Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * Interface used by the world 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ciint g364fb_init(void); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int g364fb_pan_display(struct fb_var_screeninfo *var, 10762306a36Sopenharmony_ci struct fb_info *info); 10862306a36Sopenharmony_cistatic int g364fb_setcolreg(u_int regno, u_int red, u_int green, 10962306a36Sopenharmony_ci u_int blue, u_int transp, 11062306a36Sopenharmony_ci struct fb_info *info); 11162306a36Sopenharmony_cistatic int g364fb_blank(int blank, struct fb_info *info); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic const struct fb_ops g364fb_ops = { 11462306a36Sopenharmony_ci .owner = THIS_MODULE, 11562306a36Sopenharmony_ci FB_DEFAULT_IOMEM_OPS, 11662306a36Sopenharmony_ci .fb_setcolreg = g364fb_setcolreg, 11762306a36Sopenharmony_ci .fb_pan_display = g364fb_pan_display, 11862306a36Sopenharmony_ci .fb_blank = g364fb_blank, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Pan or Wrap the Display 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic int g364fb_pan_display(struct fb_var_screeninfo *var, 12762306a36Sopenharmony_ci struct fb_info *info) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci if (var->xoffset || 13062306a36Sopenharmony_ci var->yoffset + info->var.yres > info->var.yres_virtual) 13162306a36Sopenharmony_ci return -EINVAL; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci *(unsigned int *) TOP_REG = var->yoffset * info->var.xres; 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci * Blank the display. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_cistatic int g364fb_blank(int blank, struct fb_info *info) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci if (blank) 14362306a36Sopenharmony_ci *(unsigned int *) CTLA_REG |= FORCE_BLANK; 14462306a36Sopenharmony_ci else 14562306a36Sopenharmony_ci *(unsigned int *) CTLA_REG &= ~FORCE_BLANK; 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* 15062306a36Sopenharmony_ci * Set a single color register. Return != 0 for invalid regno. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic int g364fb_setcolreg(u_int regno, u_int red, u_int green, 15362306a36Sopenharmony_ci u_int blue, u_int transp, struct fb_info *info) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci volatile unsigned int *ptr = (volatile unsigned int *) CLR_PAL_REG; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (regno > 255) 15862306a36Sopenharmony_ci return 1; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci red >>= 8; 16162306a36Sopenharmony_ci green >>= 8; 16262306a36Sopenharmony_ci blue >>= 8; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ptr[regno << 1] = (red << 16) | (green << 8) | blue; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* 17062306a36Sopenharmony_ci * Initialisation 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ciint __init g364fb_init(void) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci volatile unsigned int *curs_pal_ptr = 17562306a36Sopenharmony_ci (volatile unsigned int *) CURS_PAL_REG; 17662306a36Sopenharmony_ci int mem, i; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (fb_get_options("g364fb", NULL)) 17962306a36Sopenharmony_ci return -ENODEV; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* TBD: G364 detection */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* get the resolution set by ARC console */ 18462306a36Sopenharmony_ci *(volatile unsigned int *) CTLA_REG &= ~ENABLE_VTG; 18562306a36Sopenharmony_ci fb_var.xres = 18662306a36Sopenharmony_ci (*((volatile unsigned int *) DISPLAY_REG) & 0x00ffffff) * 4; 18762306a36Sopenharmony_ci fb_var.yres = 18862306a36Sopenharmony_ci (*((volatile unsigned int *) VDISPLAY_REG) & 0x00ffffff) / 2; 18962306a36Sopenharmony_ci *(volatile unsigned int *) CTLA_REG |= ENABLE_VTG; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* setup cursor */ 19262306a36Sopenharmony_ci curs_pal_ptr[0] |= 0x00ffffff; 19362306a36Sopenharmony_ci curs_pal_ptr[2] |= 0x00ffffff; 19462306a36Sopenharmony_ci curs_pal_ptr[4] |= 0x00ffffff; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * first set the whole cursor to transparent 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci for (i = 0; i < 512; i++) 20062306a36Sopenharmony_ci *(unsigned short *) (CURS_PAT_REG + i * 8) = 0; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * switch the last two lines to cursor palette 3 20462306a36Sopenharmony_ci * we assume here, that FONTSIZE_X is 8 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci *(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff; 20762306a36Sopenharmony_ci *(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff; 20862306a36Sopenharmony_ci fb_var.xres_virtual = fb_var.xres; 20962306a36Sopenharmony_ci fb_fix.line_length = fb_var.xres_virtual * fb_var.bits_per_pixel / 8; 21062306a36Sopenharmony_ci fb_fix.smem_start = 0x40000000; /* physical address */ 21162306a36Sopenharmony_ci /* get size of video memory; this is special for the JAZZ hardware */ 21262306a36Sopenharmony_ci mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3; 21362306a36Sopenharmony_ci fb_fix.smem_len = (1 << (mem * 2)) * 512 * 1024; 21462306a36Sopenharmony_ci fb_var.yres_virtual = fb_fix.smem_len / fb_var.xres; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci fb_info.fbops = &g364fb_ops; 21762306a36Sopenharmony_ci fb_info.screen_base = (char *) G364_MEM_BASE; /* virtual kernel address */ 21862306a36Sopenharmony_ci fb_info.var = fb_var; 21962306a36Sopenharmony_ci fb_info.fix = fb_fix; 22062306a36Sopenharmony_ci fb_info.flags = FBINFO_HWACCEL_YPAN; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci fb_alloc_cmap(&fb_info.cmap, 255, 0); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (register_framebuffer(&fb_info) < 0) 22562306a36Sopenharmony_ci return -EINVAL; 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cimodule_init(g364fb_init); 23062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 231