/* $Id: cgfourteen.c,v 1.25 1997/08/20 07:38:36 davem Exp $ * cgfourteen.c: Sun SparcStation console support. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * TODO: * * Add the ioctls for CLUT manipulation. * Map only the amount requested, not a constant amount. * XBGR mapping. * Add the interrupt handler. */ #include #include #include #include #include #include #include #include #include /* These must be included after asm/fbio.h */ #include #include #include #include "fb.h" #define CG14_MCR_INTENABLE_SHIFT 7 #define CG14_MCR_INTENABLE_MASK 0x80 #define CG14_MCR_VIDENABLE_SHIFT 6 #define CG14_MCR_VIDENABLE_MASK 0x40 #define CG14_MCR_PIXMODE_SHIFT 4 #define CG14_MCR_PIXMODE_MASK 0x30 #define CG14_MCR_TMR_SHIFT 2 #define CG14_MCR_TMR_MASK 0x0c #define CG14_MCR_TMENABLE_SHIFT 1 #define CG14_MCR_TMENABLE_MASK 0x02 #define CG14_MCR_RESET_SHIFT 0 #define CG14_MCR_RESET_MASK 0x01 #define CG14_REV_REVISION_SHIFT 4 #define CG14_REV_REVISION_MASK 0xf0 #define CG14_REV_IMPL_SHIFT 0 #define CG14_REV_IMPL_MASK 0x0f #define CG14_VBR_FRAMEBASE_SHIFT 12 #define CG14_VBR_FRAMEBASE_MASK 0x00fff000 #define CG14_VMCR1_SETUP_SHIFT 0 #define CG14_VMCR1_SETUP_MASK 0x000001ff #define CG14_VMCR1_VCONFIG_SHIFT 9 #define CG14_VMCR1_VCONFIG_MASK 0x00000e00 #define CG14_VMCR2_REFRESH_SHIFT 0 #define CG14_VMCR2_REFRESH_MASK 0x00000001 #define CG14_VMCR2_TESTROWCNT_SHIFT 1 #define CG14_VMCR2_TESTROWCNT_MASK 0x00000002 #define CG14_VMCR2_FBCONFIG_SHIFT 2 #define CG14_VMCR2_FBCONFIG_MASK 0x0000000c #define CG14_VCR_REFRESHREQ_SHIFT 0 #define CG14_VCR_REFRESHREQ_MASK 0x000003ff #define CG14_VCR1_REFRESHENA_SHIFT 10 #define CG14_VCR1_REFRESHENA_MASK 0x00000400 #define CG14_VCA_CAD_SHIFT 0 #define CG14_VCA_CAD_MASK 0x000003ff #define CG14_VCA_VERS_SHIFT 10 #define CG14_VCA_VERS_MASK 0x00000c00 #define CG14_VCA_RAMSPEED_SHIFT 12 #define CG14_VCA_RAMSPEED_MASK 0x00001000 #define CG14_VCA_8MB_SHIFT 13 #define CG14_VCA_8MB_MASK 0x00002000 #define CG14_MCR_PIXMODE_8 0 #define CG14_MCR_PIXMODE_16 2 #define CG14_MCR_PIXMODE_32 3 struct cg14_regs{ volatile u8 mcr; /* Master Control Reg */ volatile u8 ppr; /* Packed Pixel Reg */ volatile u8 tms[2]; /* Test Mode Status Regs */ volatile u8 msr; /* Master Status Reg */ volatile u8 fsr; /* Fault Status Reg */ volatile u8 rev; /* Revision & Impl */ volatile u8 ccr; /* Clock Control Reg */ volatile u32 tmr; /* Test Mode Read Back */ volatile u8 mod; /* Monitor Operation Data Reg */ volatile u8 acr; /* Aux Control */ u8 xxx0[6]; volatile u16 hct; /* Hor Counter */ volatile u16 vct; /* Vert Counter */ volatile u16 hbs; /* Hor Blank Start */ volatile u16 hbc; /* Hor Blank Clear */ volatile u16 hss; /* Hor Sync Start */ volatile u16 hsc; /* Hor Sync Clear */ volatile u16 csc; /* Composite Sync Clear */ volatile u16 vbs; /* Vert Blank Start */ volatile u16 vbc; /* Vert Blank Clear */ volatile u16 vss; /* Vert Sync Start */ volatile u16 vsc; /* Vert Sync Clear */ volatile u16 xcs; volatile u16 xcc; volatile u16 fsa; /* Fault Status Address */ volatile u16 adr; /* Address Registers */ u8 xxx1[0xce]; volatile u8 pcg[0x100]; /* Pixel Clock Generator */ volatile u32 vbr; /* Frame Base Row */ volatile u32 vmcr; /* VBC Master Control */ volatile u32 vcr; /* VBC refresh */ volatile u32 vca; /* VBC Config */ }; #define CG14_CCR_ENABLE 0x04 #define CG14_CCR_SELECT 0x02 /* HW/Full screen */ struct cg14_cursor { volatile u32 cpl0[32]; /* Enable plane 0 */ volatile u32 cpl1[32]; /* Color selection plane */ volatile u8 ccr; /* Cursor Control Reg */ u8 xxx0[3]; volatile u16 cursx; /* Cursor x,y position */ volatile u16 cursy; /* Cursor x,y position */ volatile u32 color0; volatile u32 color1; u32 xxx1[0x1bc]; volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */ volatile u32 cpl1i[32]; /* Color selection autoinc */ }; struct cg14_dac { volatile u8 addr; /* Address Register */ u8 xxx0[255]; volatile u8 glut; /* Gamma table */ u8 xxx1[255]; volatile u8 select; /* Register Select */ u8 xxx2[255]; volatile u8 mode; /* Mode Register */ }; struct cg14_xlut{ volatile u8 x_xlut [256]; volatile u8 x_xlutd [256]; u8 xxx0[0x600]; volatile u8 x_xlut_inc [256]; volatile u8 x_xlutd_inc [256]; }; /* Color look up table (clut) */ /* Each one of these arrays hold the color lookup table (for 256 * colors) for each MDI page (I assume then there should be 4 MDI * pages, I still wonder what they are. I have seen NeXTStep split * the screen in four parts, while operating in 24 bits mode. Each * integer holds 4 values: alpha value (transparency channel, thanks * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue * * I currently use the clut instead of the Xlut */ struct cg14_clut { unsigned int c_clut [256]; unsigned int c_clutd [256]; /* i wonder what the 'd' is for */ unsigned int c_clut_inc [256]; unsigned int c_clutd_inc [256]; }; static int cg14_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, fbinfo_t *fb) { uint size, page, r, map_size; unsigned long map_offset = 0; uint ram_size = fb->info.cg14.ramsize; printk ("RAMSIZE=%d\n", ram_size); size = vma->vm_end - vma->vm_start; if (vma->vm_offset & ~PAGE_MASK) return -ENXIO; /* To stop the swapper from even considering these pages */ vma->vm_flags |= FB_MMAP_VM_FLAGS; /* Each page, see which map applies */ for (page = 0; page < size; ){ switch (vma->vm_offset+page){ case CG3_MMAP_OFFSET-0x7000: printk ("Wee! They are mapping the register, report this to miguel@gnu.ai.mit.edu\n"); printk ("Mapping fb->info.regs!\n"); map_size = 0x7000; map_offset = get_phys ((unsigned long) fb->info.cg14.regs); break; case CG3_MMAP_OFFSET: map_size = size-page; map_offset = get_phys ((unsigned long) fb->base); break; case MDI_PLANAR_X16_MAP: map_size = ram_size/2; map_offset = get_phys ((unsigned long) fb->base) | 0x2000000; break; case MDI_PLANAR_C16_MAP: map_size = ram_size/2; map_offset = get_phys ((unsigned long) fb->base) | 0x2800000; break; case MDI_CHUNKY_XBGR_MAP: map_size = 0; printk ("Woo Woo: XBGR not there yet\n"); break; case MDI_CHUNKY_BGR_MAP: map_size = ram_size; map_offset = get_phys ((unsigned long) fb->base) | 0x1000000; break; case MDI_PLANAR_X32_MAP: map_size = ram_size/4; map_offset = get_phys ((unsigned long) fb->base) | 0x3000000; break; case MDI_PLANAR_B32_MAP: map_size = ram_size/4; map_offset = get_phys ((unsigned long) fb->base) | 0x3400000; break; case MDI_PLANAR_G32_MAP: map_size = ram_size/4; map_offset = get_phys ((unsigned long) fb->base) | 0x3800000; break; case MDI_PLANAR_R32_MAP: map_size = ram_size/4; map_offset = get_phys ((unsigned long) fb->base) | 0x3c00000; break; case MDI_CURSOR_MAP: map_size = PAGE_SIZE; map_offset = get_phys ((unsigned long) fb->info.cg14.cursor_regs); break; case CG14_REGS: printk ("Wee! They are mapping the register, report this to miguel@gnu.ai.mit.edu\n"); map_size = PAGE_SIZE; map_offset = get_phys ((unsigned long) fb->info.cg14.regs); break; case CG14_XLUT: map_size = PAGE_SIZE; map_offset = get_phys ((unsigned long) fb->info.cg14.regs+0x3000); break; case CG14_CLUT1: map_size = PAGE_SIZE; map_offset = get_phys ((unsigned long) fb->info.cg14.regs+0x4000); break; case CG14_CLUT2: map_size = PAGE_SIZE; map_offset = get_phys ((unsigned long) fb->info.cg14.regs+0x5000); break; default: map_size = 0; break; } if (!map_size){ page += PAGE_SIZE; continue; } if (page + map_size > size) map_size = size - page; r = io_remap_page_range (vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->space); if (r) return -EAGAIN; page += map_size; } vma->vm_dentry = dget(file->f_dentry); return 0; } static void cg14_cmap (fbinfo_t *fb, int index, int count) { struct cg14_clut *clut = fb->info.cg14.clut; int i; for (i = index; count--; i++){ clut->c_clut [i] = (fb->color_map CM(i,2) << 16) | (fb->color_map CM(i,1) << 8) | (fb->color_map CM(i,0)); } } static void cg14_setcursormap (fbinfo_t *fb, unsigned char *red, unsigned char *green, unsigned char *blue) { struct cg14_cursor *cur = fb->info.cg14.cursor_regs; cur->color0 = ((red[0]) | (green[0] << 8) | (blue[0] << 16)); cur->color1 = ((red[1]) | (green[1] << 8) | (blue[1] << 16)); } /* Load cursor information */ static void cg14_setcursor (fbinfo_t *fb) { struct cg_cursor *c = &fb->cursor; struct cg14_cursor *cur = fb->info.cg14.cursor_regs; if (c->enable) cur->ccr |= CG14_CCR_ENABLE; cur->cursx = ((c->cpos.fbx - c->chot.fbx) & 0xfff); cur->cursy = ((c->cpos.fby - c->chot.fby) & 0xfff); } /* Set cursor shape */ static void cg14_setcurshape (fbinfo_t *fb) { struct cg14_cursor *cur = fb->info.cg14.cursor_regs; int i; for (i = 0; i < 32; i++){ cur->cpl0 [i] = fb->cursor.bits[0][i]; cur->cpl1 [i] = fb->cursor.bits[1][i]; } } /* These ones are for putting the video card on 16/32 bpp */ static int cg14_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb) { switch (cmd){ case MDI_RESET: { volatile unsigned char *control = &(fb->info.cg14.regs->mcr); *control = (*control & ~CG14_MCR_PIXMODE_MASK); } break; case MDI_GET_CFGINFO: { int error; struct mdi_cfginfo *mdii; error = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct mdi_cfginfo)); if (error) return error; mdii = (struct mdi_cfginfo *) arg; #if 0 __put_user_ret(2, &mdii->mdi_ncluts, -EFAULT); switch (fb->info.cg14.regs->rev & CG14_REV_IMPL_MASK){ case 0: case 2: break; case 1: case 3: __put_user_ret(3, &mdii->mdi_ncluts, -EFAULT); break; default: printk ("Unknown implementation number\n"); } #endif __put_user_ret(FBTYPE_MDICOLOR, &mdii->mdi_type, -EFAULT); __put_user_ret(fb->type.fb_height, &mdii->mdi_height, -EFAULT); __put_user_ret(fb->type.fb_width, &mdii->mdi_width, -EFAULT); __put_user_ret(fb->info.cg14.video_mode, &mdii->mdi_mode, -EFAULT); __put_user_ret(72, &mdii->mdi_pixfreq, -EFAULT); /* FIXME */ __put_user_ret(fb->info.cg14.ramsize, &mdii->mdi_size, -EFAULT); } break; case MDI_SET_PIXELMODE: { int newmode; volatile u8 *control; get_user_ret(newmode, (int *)arg, -EFAULT); control = &(fb->info.cg14.regs->mcr); switch (newmode){ case MDI_32_PIX: *control = (*control & ~CG14_MCR_PIXMODE_MASK) | (CG14_MCR_PIXMODE_32 << CG14_MCR_PIXMODE_SHIFT); break; case MDI_16_PIX: *control = (*control & ~CG14_MCR_PIXMODE_MASK) | 0x20; break; case MDI_8_PIX: *control = (*control & ~CG14_MCR_PIXMODE_MASK); break; default: return -ENOSYS; } fb->info.cg14.video_mode = newmode; } break; } /* switch */ return 0; } static void cg14_switch_from_graph (void) { fbinfo_t *fb = &(fbinfo [0]); struct cg14_info *cg14info = (struct cg14_info *) &fb->info.cg14; /* Set the 8-bpp mode */ if (fb->open && fb->mmaped){ volatile char *mcr = (char *)(&cg14info->regs->mcr); fb->info.cg14.video_mode = 8; *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK)); } } void cg14_reset (fbinfo_t *fb) { volatile char *mcr = &(fb->info.cg14.regs->mcr); *mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK)); } __initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, u32 cg14, int cg14_io)) { struct cg14_info *cg14info; uint bases [2]; unsigned long cg14regs = 0; struct cg14_regs *regs = 0; if (!cg14) { prom_getproperty (con_node, "address", (char *) &bases[0], 8); cg14 = bases[1]; cg14regs = bases[0]; fb->base = cg14; fb->info.cg14.regs = (struct cg14_regs *) cg14regs; regs = (struct cg14_regs *) cg14regs; } if (!cg14regs){ printk ("The PROM does not have mapped the frame buffer or the registers\n" "Mr. Penguin can't use that"); prom_halt (); } fb->type.fb_cmsize = 256; fb->mmap = cg14_mmap; fb->loadcmap = cg14_cmap; fb->setcursor = cg14_setcursor; fb->setcursormap = cg14_setcursormap; fb->setcurshape = cg14_setcurshape; fb->ioctl = cg14_ioctl; fb->switch_from_graph = cg14_switch_from_graph; fb->postsetup = cg_postsetup; fb->reset = cg14_reset; fb->blank = 0; fb->unblank = 0; fb->info.cg14.video_mode = 8; fb->emulations [1] = FBTYPE_SUN3COLOR; fb->type.fb_depth = 24; cg14info = (struct cg14_info *) &fb->info.cg14; cg14info->clut = (void *) (cg14regs + CG14_CLUT1); cg14info->cursor_regs = (void *) (cg14regs + CG14_CURSORREGS); /* If the bit is turned on, the card has 8 mb of ram, otherwise just 4 */ cg14info->ramsize = (regs->vca & CG14_VCA_8MB_MASK ? 8 : 4) * 1024 * 1024; printk ("cgfourteen%d at 0x%8.8x with %d megs of RAM rev=%d, impl=%d\n", slot, cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf); }