0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #include <linux/module.h>
0031 #include <linux/kernel.h>
0032 #include <linux/errno.h>
0033 #include <linux/string.h>
0034 #include <linux/mm.h>
0035 #include <linux/vmalloc.h>
0036 #include <linux/delay.h>
0037 #include <linux/interrupt.h>
0038 #include <linux/uaccess.h>
0039 #include <linux/fb.h>
0040 #include <linux/init.h>
0041
0042 #if defined(CONFIG_M68VZ328)
0043 #include <asm/MC68VZ328.h>
0044 #elif defined(CONFIG_M68EZ328)
0045 #include <asm/MC68EZ328.h>
0046 #elif defined(CONFIG_M68328)
0047 #include <asm/MC68328.h>
0048 #else
0049 #error wrong architecture for the MC68x328 frame buffer device
0050 #endif
0051
0052 static u_long videomemory;
0053 static u_long videomemorysize;
0054
0055 static struct fb_info fb_info;
0056 static u32 mc68x328fb_pseudo_palette[16];
0057
0058 static struct fb_var_screeninfo mc68x328fb_default __initdata = {
0059 .red = { 0, 8, 0 },
0060 .green = { 0, 8, 0 },
0061 .blue = { 0, 8, 0 },
0062 .activate = FB_ACTIVATE_TEST,
0063 .height = -1,
0064 .width = -1,
0065 .pixclock = 20000,
0066 .left_margin = 64,
0067 .right_margin = 64,
0068 .upper_margin = 32,
0069 .lower_margin = 32,
0070 .hsync_len = 64,
0071 .vsync_len = 2,
0072 .vmode = FB_VMODE_NONINTERLACED,
0073 };
0074
0075 static const struct fb_fix_screeninfo mc68x328fb_fix __initconst = {
0076 .id = "68328fb",
0077 .type = FB_TYPE_PACKED_PIXELS,
0078 .xpanstep = 1,
0079 .ypanstep = 1,
0080 .ywrapstep = 1,
0081 .accel = FB_ACCEL_NONE,
0082 };
0083
0084
0085
0086
0087 static int mc68x328fb_check_var(struct fb_var_screeninfo *var,
0088 struct fb_info *info);
0089 static int mc68x328fb_set_par(struct fb_info *info);
0090 static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0091 u_int transp, struct fb_info *info);
0092 static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
0093 struct fb_info *info);
0094 static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
0095
0096 static const struct fb_ops mc68x328fb_ops = {
0097 .fb_check_var = mc68x328fb_check_var,
0098 .fb_set_par = mc68x328fb_set_par,
0099 .fb_setcolreg = mc68x328fb_setcolreg,
0100 .fb_pan_display = mc68x328fb_pan_display,
0101 .fb_fillrect = cfb_fillrect,
0102 .fb_copyarea = cfb_copyarea,
0103 .fb_imageblit = cfb_imageblit,
0104 .fb_mmap = mc68x328fb_mmap,
0105 };
0106
0107
0108
0109
0110
0111 static u_long get_line_length(int xres_virtual, int bpp)
0112 {
0113 u_long length;
0114
0115 length = xres_virtual * bpp;
0116 length = (length + 31) & ~31;
0117 length >>= 3;
0118 return (length);
0119 }
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129 static int mc68x328fb_check_var(struct fb_var_screeninfo *var,
0130 struct fb_info *info)
0131 {
0132 u_long line_length;
0133
0134
0135
0136
0137
0138
0139 if (var->vmode & FB_VMODE_CONUPDATE) {
0140 var->vmode |= FB_VMODE_YWRAP;
0141 var->xoffset = info->var.xoffset;
0142 var->yoffset = info->var.yoffset;
0143 }
0144
0145
0146
0147
0148 if (!var->xres)
0149 var->xres = 1;
0150 if (!var->yres)
0151 var->yres = 1;
0152 if (var->xres > var->xres_virtual)
0153 var->xres_virtual = var->xres;
0154 if (var->yres > var->yres_virtual)
0155 var->yres_virtual = var->yres;
0156 if (var->bits_per_pixel <= 1)
0157 var->bits_per_pixel = 1;
0158 else if (var->bits_per_pixel <= 8)
0159 var->bits_per_pixel = 8;
0160 else if (var->bits_per_pixel <= 16)
0161 var->bits_per_pixel = 16;
0162 else if (var->bits_per_pixel <= 24)
0163 var->bits_per_pixel = 24;
0164 else if (var->bits_per_pixel <= 32)
0165 var->bits_per_pixel = 32;
0166 else
0167 return -EINVAL;
0168
0169 if (var->xres_virtual < var->xoffset + var->xres)
0170 var->xres_virtual = var->xoffset + var->xres;
0171 if (var->yres_virtual < var->yoffset + var->yres)
0172 var->yres_virtual = var->yoffset + var->yres;
0173
0174
0175
0176
0177 line_length =
0178 get_line_length(var->xres_virtual, var->bits_per_pixel);
0179 if (line_length * var->yres_virtual > videomemorysize)
0180 return -ENOMEM;
0181
0182
0183
0184
0185
0186
0187 switch (var->bits_per_pixel) {
0188 case 1:
0189 var->red.offset = 0;
0190 var->red.length = 1;
0191 var->green.offset = 0;
0192 var->green.length = 1;
0193 var->blue.offset = 0;
0194 var->blue.length = 1;
0195 var->transp.offset = 0;
0196 var->transp.length = 0;
0197 break;
0198 case 8:
0199 var->red.offset = 0;
0200 var->red.length = 8;
0201 var->green.offset = 0;
0202 var->green.length = 8;
0203 var->blue.offset = 0;
0204 var->blue.length = 8;
0205 var->transp.offset = 0;
0206 var->transp.length = 0;
0207 break;
0208 case 16:
0209 if (var->transp.length) {
0210 var->red.offset = 0;
0211 var->red.length = 5;
0212 var->green.offset = 5;
0213 var->green.length = 5;
0214 var->blue.offset = 10;
0215 var->blue.length = 5;
0216 var->transp.offset = 15;
0217 var->transp.length = 1;
0218 } else {
0219 var->red.offset = 0;
0220 var->red.length = 5;
0221 var->green.offset = 5;
0222 var->green.length = 6;
0223 var->blue.offset = 11;
0224 var->blue.length = 5;
0225 var->transp.offset = 0;
0226 var->transp.length = 0;
0227 }
0228 break;
0229 case 24:
0230 var->red.offset = 0;
0231 var->red.length = 8;
0232 var->green.offset = 8;
0233 var->green.length = 8;
0234 var->blue.offset = 16;
0235 var->blue.length = 8;
0236 var->transp.offset = 0;
0237 var->transp.length = 0;
0238 break;
0239 case 32:
0240 var->red.offset = 0;
0241 var->red.length = 8;
0242 var->green.offset = 8;
0243 var->green.length = 8;
0244 var->blue.offset = 16;
0245 var->blue.length = 8;
0246 var->transp.offset = 24;
0247 var->transp.length = 8;
0248 break;
0249 }
0250 var->red.msb_right = 0;
0251 var->green.msb_right = 0;
0252 var->blue.msb_right = 0;
0253 var->transp.msb_right = 0;
0254
0255 return 0;
0256 }
0257
0258
0259
0260
0261
0262 static int mc68x328fb_set_par(struct fb_info *info)
0263 {
0264 info->fix.line_length = get_line_length(info->var.xres_virtual,
0265 info->var.bits_per_pixel);
0266 return 0;
0267 }
0268
0269
0270
0271
0272
0273
0274
0275 static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0276 u_int transp, struct fb_info *info)
0277 {
0278 if (regno >= 256)
0279 return 1;
0280
0281
0282
0283
0284
0285 if (info->var.grayscale) {
0286
0287 red = green = blue =
0288 (red * 77 + green * 151 + blue * 28) >> 8;
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
0313 switch (info->fix.visual) {
0314 case FB_VISUAL_TRUECOLOR:
0315 case FB_VISUAL_PSEUDOCOLOR:
0316 red = CNVT_TOHW(red, info->var.red.length);
0317 green = CNVT_TOHW(green, info->var.green.length);
0318 blue = CNVT_TOHW(blue, info->var.blue.length);
0319 transp = CNVT_TOHW(transp, info->var.transp.length);
0320 break;
0321 case FB_VISUAL_DIRECTCOLOR:
0322 red = CNVT_TOHW(red, 8);
0323 green = CNVT_TOHW(green, 8);
0324 blue = CNVT_TOHW(blue, 8);
0325
0326 transp = CNVT_TOHW(transp, 8);
0327 break;
0328 }
0329 #undef CNVT_TOHW
0330
0331 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
0332 u32 v;
0333
0334 if (regno >= 16)
0335 return 1;
0336
0337 v = (red << info->var.red.offset) |
0338 (green << info->var.green.offset) |
0339 (blue << info->var.blue.offset) |
0340 (transp << info->var.transp.offset);
0341 switch (info->var.bits_per_pixel) {
0342 case 8:
0343 break;
0344 case 16:
0345 ((u32 *) (info->pseudo_palette))[regno] = v;
0346 break;
0347 case 24:
0348 case 32:
0349 ((u32 *) (info->pseudo_palette))[regno] = v;
0350 break;
0351 }
0352 return 0;
0353 }
0354 return 0;
0355 }
0356
0357
0358
0359
0360
0361
0362
0363 static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
0364 struct fb_info *info)
0365 {
0366 if (var->vmode & FB_VMODE_YWRAP) {
0367 if (var->yoffset < 0
0368 || var->yoffset >= info->var.yres_virtual
0369 || var->xoffset)
0370 return -EINVAL;
0371 } else {
0372 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
0373 var->yoffset + info->var.yres > info->var.yres_virtual)
0374 return -EINVAL;
0375 }
0376 info->var.xoffset = var->xoffset;
0377 info->var.yoffset = var->yoffset;
0378 if (var->vmode & FB_VMODE_YWRAP)
0379 info->var.vmode |= FB_VMODE_YWRAP;
0380 else
0381 info->var.vmode &= ~FB_VMODE_YWRAP;
0382 return 0;
0383 }
0384
0385
0386
0387
0388
0389 static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
0390 {
0391 #ifndef MMU
0392
0393
0394 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
0395 vma->vm_start = videomemory;
0396
0397 return 0;
0398 #else
0399 return -EINVAL;
0400 #endif
0401 }
0402
0403 static int __init mc68x328fb_setup(char *options)
0404 {
0405 if (!options || !*options)
0406 return 1;
0407 return 1;
0408 }
0409
0410
0411
0412
0413
0414 static int __init mc68x328fb_init(void)
0415 {
0416 #ifndef MODULE
0417 char *option = NULL;
0418
0419 if (fb_get_options("68328fb", &option))
0420 return -ENODEV;
0421 mc68x328fb_setup(option);
0422 #endif
0423
0424
0425
0426 mc68x328fb_default.xres = LXMAX;
0427 mc68x328fb_default.yres = LYMAX+1;
0428 mc68x328fb_default.xres_virtual = mc68x328fb_default.xres;
0429 mc68x328fb_default.yres_virtual = mc68x328fb_default.yres;
0430 mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01);
0431 videomemory = LSSA;
0432 videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 *
0433 mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel;
0434
0435 fb_info.screen_base = (void *)videomemory;
0436 fb_info.fbops = &mc68x328fb_ops;
0437 fb_info.var = mc68x328fb_default;
0438 fb_info.fix = mc68x328fb_fix;
0439 fb_info.fix.smem_start = videomemory;
0440 fb_info.fix.smem_len = videomemorysize;
0441 fb_info.fix.line_length =
0442 get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel);
0443 fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ?
0444 FB_VISUAL_MONO10 : FB_VISUAL_PSEUDOCOLOR;
0445 if (fb_info.var.bits_per_pixel == 1) {
0446 fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1;
0447 fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0;
0448 }
0449 fb_info.pseudo_palette = &mc68x328fb_pseudo_palette;
0450 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
0451
0452 if (fb_alloc_cmap(&fb_info.cmap, 256, 0))
0453 return -ENOMEM;
0454
0455 if (register_framebuffer(&fb_info) < 0) {
0456 fb_dealloc_cmap(&fb_info.cmap);
0457 return -EINVAL;
0458 }
0459
0460 fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id);
0461 fb_info(&fb_info, "%dx%dx%d at 0x%08lx\n",
0462 mc68x328fb_default.xres_virtual,
0463 mc68x328fb_default.yres_virtual,
0464 1 << mc68x328fb_default.bits_per_pixel, videomemory);
0465
0466 return 0;
0467 }
0468
0469 module_init(mc68x328fb_init);
0470
0471 #ifdef MODULE
0472
0473 static void __exit mc68x328fb_cleanup(void)
0474 {
0475 unregister_framebuffer(&fb_info);
0476 fb_dealloc_cmap(&fb_info.cmap);
0477 }
0478
0479 module_exit(mc68x328fb_cleanup);
0480
0481 MODULE_LICENSE("GPL");
0482 #endif