| /* |
| * linux/arch/m68knommu/console/68328fb.c -- Low level implementation of the |
| * mc68328 LCD frame buffer device |
| * |
| * Copyright (C) 1998,1999 Kenneth Albanowski <kjahds@kjahds.com>, |
| * The Silver Hammer Group, Ltd. |
| * |
| * |
| * This file is based on the Amiga CyberVision frame buffer device (Cyberfb.c): |
| * |
| * Copyright (C) 1996 Martin Apel |
| * Geert Uytterhoeven |
| * |
| * |
| * This file is based on the Amiga frame buffer device (amifb.c): |
| * |
| * Copyright (C) 1995 Geert Uytterhoeven |
| * |
| * |
| * History: |
| * - 17 Feb 98: Original version by Kenneth Albanowski <kjahds@kjahds.com> |
| * |
| * |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file COPYING in the main directory of this archive |
| * for more details. |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/errno.h> |
| #include <linux/string.h> |
| #include <linux/mm.h> |
| #include <linux/tty.h> |
| #include <linux/slab.h> |
| #include <linux/delay.h> |
| #include <linux/config.h> |
| #include <asm/segment.h> |
| #include <asm/system.h> |
| #include <asm/irq.h> |
| #include <asm/pgtable.h> |
| #include <linux/fb.h> |
| |
| #define arraysize(x) (sizeof(x)/sizeof(*(x))) |
| |
| static struct fb_info fb_info; |
| |
| /* |
| * mc68328vision Graphics Board |
| */ |
| |
| #define CYBER8_WIDTH 1152 |
| #define CYBER8_HEIGHT 886 |
| #define CYBER8_PIXCLOCK 12500 /* ++Geert: Just a guess */ |
| |
| #define CYBER16_WIDTH 800 |
| #define CYBER16_HEIGHT 600 |
| #define CYBER16_PIXCLOCK 25000 /* ++Geert: Just a guess */ |
| |
| #define PALM_WIDTH 160 |
| #define PALM_HEIGHT 160 |
| |
| /*static int mc68328Key = 0; |
| static u_char mc68328_colour_table [256][4];*/ |
| |
| /* |
| * Predefined Video Mode Names |
| */ |
| |
| static char *mc68328_fb_modenames[] = { |
| |
| /* |
| * Autodetect (Default) Video Mode |
| */ |
| |
| "default", |
| |
| /* |
| * Predefined Video Modes |
| */ |
| |
| "Palm", /* Palm Pilot devices, 1.0 and higher */ |
| "Palm Grey", /* Palm Pilot devices, 1.0 and higher */ |
| |
| /* |
| * Dummy Video Modes |
| */ |
| |
| "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", |
| "dummy", |
| "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", |
| "dummy", |
| "dummy", "dummy", "dummy", "dummy", |
| |
| /* |
| * User Defined Video Modes |
| * |
| * This doesn't work yet!! |
| */ |
| |
| "user0", "user1", "user2", "user3", "user4", "user5", "user6", |
| "user7" |
| }; |
| |
| |
| /* |
| * Predefined Video Mode Definitions |
| */ |
| |
| static struct fb_var_screeninfo mc68328_fb_predefined[] = { |
| |
| /* |
| * Autodetect (Default) Video Mode |
| */ |
| |
| {0,}, |
| |
| /* |
| * Predefined Video Modes |
| */ |
| |
| { |
| /* Palm */ |
| PALM_WIDTH, PALM_HEIGHT, PALM_WIDTH, PALM_HEIGHT, |
| 0, 0, |
| 1, -1, |
| {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, |
| 0, 0, |
| -1, -1, /* phys height, width */ |
| FB_ACCEL_NONE, |
| 0, 0, 0, 0, 0, 0, 0, /* timing */ |
| 0, /* sync */ |
| FB_VMODE_NONINTERLACED}, |
| { |
| /* Palm Grey */ |
| PALM_WIDTH, PALM_HEIGHT, PALM_WIDTH, PALM_HEIGHT, |
| 0, 0, |
| 2, -1, |
| {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, |
| 0, 0, |
| -1, -1, /* phys height, width */ |
| FB_ACCEL_NONE, |
| 0, 0, 0, 0, 0, 0, 0, /* timing */ |
| 0, /* sync */ |
| FB_VMODE_NONINTERLACED}, |
| |
| /* |
| * Dummy Video Modes |
| */ |
| |
| {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, |
| {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, |
| {0,}, {0,}, |
| |
| /* |
| * User Defined Video Modes |
| */ |
| |
| {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,}, {0,} |
| }; |
| |
| static struct fb_fix_screeninfo mc68328_fix __initdata = { |
| .id = "mc68328"; |
| .smem_len = 160 * 160 /8; |
| .type = FB_TYPE_PACKED_PIXELS; |
| .accel = FB_ACCEL_NONE; |
| }; |
| |
| #define NUM_TOTAL_MODES arraysize(mc68328_fb_predefined) |
| #define NUM_PREDEF_MODES (3) |
| |
| static int mc68328fb_inverse = 0; |
| static int mc68328fb_mode = 0; |
| static int mc68328fbCursorMode = 0; |
| |
| /* |
| * Some default modes |
| */ |
| |
| #define PALM_DEFMODE (1) |
| #define CYBER16_DEFMODE (2) |
| |
| /* |
| * Interface used by the world |
| */ |
| int mc68328_fb_init(void); |
| |
| static int mc68328fb_setcolreg(u_int regno, u_int red, u_int green, |
| u_int blue, u_int transp); |
| static void mc68328fb_blank(int blank, struct fb_info *info); |
| |
| /* |
| * Accelerated Functions used by the low level console driver |
| */ |
| |
| void mc68328_WaitQueue(u_short fifo); |
| void mc68328_WaitBlit(void); |
| void mc68328_BitBLT(u_short curx, u_short cury, u_short destx, |
| u_short desty, u_short width, u_short height, |
| u_short mode); |
| void mc68328_RectFill(u_short x, u_short y, u_short width, u_short height, |
| u_short mode, u_short color); |
| void mc68328_MoveCursor(u_short x, u_short y); |
| |
| /* |
| * Internal routines |
| */ |
| static int get_video_mode(const char *name); |
| |
| /* |
| * Set a single color register. The values supplied are already |
| * rounded down to the hardware's capabilities (according to the |
| * entries in the var structure). Return != 0 for invalid regno. |
| */ |
| |
| static int mc68328fb_setcolreg(u_int regno, u_int red, u_int green, |
| u_int blue, u_int transp) |
| { |
| return 1; |
| #if 0 |
| if (regno > 255) |
| return (1); |
| |
| *(mc68328Regs + 0x3c8) = (char) regno; |
| mc68328_colour_table[regno][0] = red & 0xff; |
| mc68328_colour_table[regno][1] = green & 0xff; |
| mc68328_colour_table[regno][2] = blue & 0xff; |
| mc68328_colour_table[regno][3] = transp; |
| |
| *(mc68328Regs + 0x3c9) = (red & 0xff) >> 2; |
| *(mc68328Regs + 0x3c9) = (green & 0xff) >> 2; |
| *(mc68328Regs + 0x3c9) = (blue & 0xff) >> 2; |
| |
| return (0); |
| #endif |
| } |
| |
| /* |
| * (Un)Blank the screen |
| */ |
| |
| static void mc68328fb_blank(int blank, struct fb_info *info) |
| { |
| #if 0 |
| if (blank) |
| (*(volatile unsigned char *) 0xFFFFFA27) &= ~128; |
| else |
| (*(volatile unsigned char *) 0xFFFFFA27) |= 128; |
| #endif |
| } |
| |
| |
| /************************************************************** |
| * We are waiting for "fifo" FIFO-slots empty |
| */ |
| void mc68328_WaitQueue(u_short fifo) |
| { |
| } |
| |
| /************************************************************** |
| * We are waiting for Hardware (Graphics Engine) not busy |
| */ |
| void mc68328_WaitBlit(void) |
| { |
| } |
| |
| /************************************************************** |
| * BitBLT - Through the Plane |
| */ |
| void mc68328_BitBLT(u_short curx, u_short cury, u_short destx, |
| u_short desty, u_short width, u_short height, |
| u_short mode) |
| { |
| #if 0 |
| u_short blitcmd = S3_BITBLT; |
| |
| /* Set drawing direction */ |
| /* -Y, X maj, -X (default) */ |
| if (curx > destx) |
| blitcmd |= 0x0020; /* Drawing direction +X */ |
| else { |
| curx += (width - 1); |
| destx += (width - 1); |
| } |
| |
| if (cury > desty) |
| blitcmd |= 0x0080; /* Drawing direction +Y */ |
| else { |
| cury += (height - 1); |
| desty += (height - 1); |
| } |
| |
| mc68328_WaitQueue(0x8000); |
| |
| *((u_short volatile *) (mc68328Regs + S3_PIXEL_CNTL)) = 0xa000; |
| *((u_short volatile *) (mc68328Regs + S3_FRGD_MIX)) = |
| (0x0060 | mode); |
| |
| *((u_short volatile *) (mc68328Regs + S3_CUR_X)) = curx; |
| *((u_short volatile *) (mc68328Regs + S3_CUR_Y)) = cury; |
| |
| *((u_short volatile *) (mc68328Regs + S3_DESTX_DIASTP)) = destx; |
| *((u_short volatile *) (mc68328Regs + S3_DESTY_AXSTP)) = desty; |
| |
| *((u_short volatile *) (mc68328Regs + S3_MIN_AXIS_PCNT)) = |
| height - 1; |
| *((u_short volatile *) (mc68328Regs + S3_MAJ_AXIS_PCNT)) = |
| width - 1; |
| |
| *((u_short volatile *) (mc68328Regs + S3_CMD)) = blitcmd; |
| #endif |
| } |
| |
| /************************************************************** |
| * Rectangle Fill Solid |
| */ |
| void mc68328_RectFill(u_short x, u_short y, u_short width, u_short height, |
| u_short mode, u_short color) |
| { |
| #if 0 |
| u_short blitcmd = S3_FILLEDRECT; |
| |
| mc68328_WaitQueue(0x8000); |
| |
| *((u_short volatile *) (mc68328Regs + S3_PIXEL_CNTL)) = 0xa000; |
| *((u_short volatile *) (mc68328Regs + S3_FRGD_MIX)) = |
| (0x0020 | mode); |
| |
| *((u_short volatile *) (mc68328Regs + S3_MULT_MISC)) = 0xe000; |
| *((u_short volatile *) (mc68328Regs + S3_FRGD_COLOR)) = color; |
| |
| *((u_short volatile *) (mc68328Regs + S3_CUR_X)) = x; |
| *((u_short volatile *) (mc68328Regs + S3_CUR_Y)) = y; |
| |
| *((u_short volatile *) (mc68328Regs + S3_MIN_AXIS_PCNT)) = |
| height - 1; |
| *((u_short volatile *) (mc68328Regs + S3_MAJ_AXIS_PCNT)) = |
| width - 1; |
| |
| *((u_short volatile *) (mc68328Regs + S3_CMD)) = blitcmd; |
| #endif |
| } |
| |
| |
| /************************************************************** |
| * Move cursor to x, y |
| */ |
| void mc68328_MoveCursor(u_short x, u_short y) |
| { |
| (*(volatile unsigned short *) 0xFFFFFA18) = |
| (mc68328fbCursorMode << 14) | x; |
| (*(volatile unsigned short *) 0xFFFFFA1A) = y; |
| #if 0 |
| *(mc68328Regs + S3_CRTC_ADR) = 0x39; |
| *(mc68328Regs + S3_CRTC_DATA) = 0xa0; |
| |
| *(mc68328Regs + S3_CRTC_ADR) = S3_HWGC_ORGX_H; |
| *(mc68328Regs + S3_CRTC_DATA) = (char) ((x & 0x0700) >> 8); |
| *(mc68328Regs + S3_CRTC_ADR) = S3_HWGC_ORGX_L; |
| *(mc68328Regs + S3_CRTC_DATA) = (char) (x & 0x00ff); |
| |
| *(mc68328Regs + S3_CRTC_ADR) = S3_HWGC_ORGY_H; |
| *(mc68328Regs + S3_CRTC_DATA) = (char) ((y & 0x0700) >> 8); |
| *(mc68328Regs + S3_CRTC_ADR) = S3_HWGC_ORGY_L; |
| *(mc68328Regs + S3_CRTC_DATA) = (char) (y & 0x00ff); |
| #endif |
| } |
| |
| /* -------------------- Generic routines ------------------------------------ */ |
| |
| /* |
| * Default Colormaps |
| */ |
| |
| static u_short red16[] = |
| { 0xc000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0x0000, |
| 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff |
| }; |
| static u_short green16[] = |
| { 0xc000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0x0000, |
| 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff |
| }; |
| static u_short blue16[] = |
| { 0xc000, 0x0000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0x0000, |
| 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff |
| }; |
| |
| |
| static struct fb_cmap default_16_colors = |
| { 0, 16, red16, green16, blue16, NULL }; |
| |
| |
| static struct fb_cmap *get_default_colormap(int bpp) |
| { |
| return (&default_16_colors); |
| } |
| |
| |
| #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) |
| #define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ |
| ((1<<(width))-1)) : 0)) |
| |
| static struct fb_ops mc68328_fb_ops = { |
| .owner: THIS_MODULE, |
| .fb_setcolreg: mc68328fb_setcolreg, |
| .fb_fillrect: cfbfillrect, |
| .fb_copyarea: cfbcopyarea, |
| .fb_imageblit: cfbimgblt, |
| .fb_cursor: softcursor, |
| }; |
| |
| |
| /* |
| * Initialization |
| */ |
| |
| int __init mc68328_fb_init(void) |
| { |
| if (mc68328fb_mode == -1) |
| mc68328fb_mode = PALM_DEFMODE; |
| mc68328_fix.smem_start = (*(volatile unsigned long *) 0xFFFFFA00); |
| /*kernel_map (board_addr + 0x01400000, 0x00400000, */ |
| |
| info->var = mc68328_fb_predefined[mc68328fb_mode]; |
| |
| if (info->var.bits_per_pixel == 1) |
| fix->visual = FB_VISUAL_MONO01; |
| else |
| fix->visual = FB_VISUAL_DIRECTCOLOR; |
| info->screen_base = (u_char *) mc68328_fix.smem_start; |
| |
| if (register_framebuffer(&fb_info) < 0) |
| panic("Cannot register frame buffer\n"); |
| return 0; |
| } |
| |
| /* |
| * Get a Video Mode |
| */ |
| |
| static int get_video_mode(const char *name) |
| { |
| int i; |
| |
| for (i = 1; i < NUM_PREDEF_MODES; i++) |
| if (!strcmp(name, mc68328_fb_modenames[i])) |
| return (i); |
| return (0); |
| } |