^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/drivers/video/maxinefb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * DECstation 5000/xx onboard framebuffer support ... derived from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * "HP300 Topcat framebuffer support (derived from macfb of all things)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Phil Blundell <philb@gnu.org> 1998", the original code can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * found in the file hpfb.c in the same directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * DECstation related code Copyright (C) 1999,2000,2001 by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Michael Engel <engel@unix-ag.org> and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Karsten Merker <merker@linuxtag.org>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * This file is subject to the terms and conditions of the GNU General
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Public License. See the file COPYING in the main directory of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * archive for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Changes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * 2001/01/27 removed debugging and testing code, fixed fb_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * initialization which had caused a crash before,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * general cleanup, first official release (KM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <video/maxinefb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* bootinfo.h defines the machine type values, needed when checking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* whether are really running on a maxine, KM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/bootinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static struct fb_info fb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static const struct fb_var_screeninfo maxinefb_defined = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .xres = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .yres = 768,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .xres_virtual = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) .yres_virtual = 768,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .bits_per_pixel =8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .activate = FB_ACTIVATE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .height = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .width = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static struct fb_fix_screeninfo maxinefb_fix __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .id = "Maxine",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .smem_len = (1024*768),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .visual = FB_VISUAL_PSEUDOCOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .line_length = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Handle the funny Inmos RamDAC/video controller ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void maxinefb_ims332_write_register(int regno, register unsigned int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) unsigned char *wptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) wptr = regs + 0xa0000 + (regno << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *((volatile unsigned int *) (regs)) = (val >> 8) & 0xff00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *((volatile unsigned short *) (wptr)) = val;
^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) unsigned int maxinefb_ims332_read_register(int regno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) register unsigned char *regs = (char *) MAXINEFB_IMS332_ADDRESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned char *rptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) register unsigned int j, k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) rptr = regs + 0x80000 + (regno << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) j = *((volatile unsigned short *) rptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) k = *((volatile unsigned short *) regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return (j & 0xffff) | ((k & 0xff00) << 8);
^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) /* Set the palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned blue, unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* value to be written into the palette reg. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long hw_colorvalue = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (regno > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) red >>= 8; /* The cmap fields are 16 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) green >>= 8; /* wide, but the harware colormap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) blue >>= 8; /* registers are only 8 bits wide */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) hw_colorvalue = (blue << 16) + (green << 8) + (red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE + regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) hw_colorvalue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static const struct fb_ops maxinefb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .fb_setcolreg = maxinefb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int __init maxinefb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned long fboff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned long fb_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (fb_get_options("maxinefb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* Validate we're on the proper machine type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (mips_machtype != MACH_DS5000_XX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) printk(KERN_INFO "Maxinefb: Personal DECstation detected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) printk(KERN_INFO "Maxinefb: initializing onboard framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* Framebuffer display memory base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) fb_start = DS5000_xx_ONBOARD_FBMEM_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* Clear screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) for (fboff = fb_start; fboff < fb_start + 0x1ffff; fboff++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) *(volatile unsigned char *)fboff = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) maxinefb_fix.smem_start = fb_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* erase hardware cursor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) for (i = 0; i < 512; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (i&0x8 == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0x0f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) maxinefb_ims332_write_register (IMS332_REG_CURSOR_RAM + i, 0xf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) fb_info.fbops = &maxinefb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) fb_info.screen_base = (char *)maxinefb_fix.smem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) fb_info.var = maxinefb_defined;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) fb_info.fix = maxinefb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) fb_info.flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) fb_alloc_cmap(&fb_info.cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (register_framebuffer(&fb_info) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static void __exit maxinefb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unregister_framebuffer(&fb_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) module_init(maxinefb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) module_exit(maxinefb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)