18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/68328fb.c -- Low level implementation of the 38c2ecf20Sopenharmony_ci * mc68x328 LCD frame buffer device 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003 Georges Menie 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This driver assumes an already configured controller (e.g. from config.c) 88c2ecf20Sopenharmony_ci * Keep the code clean of board specific initialization. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This code has not been tested with colors, colormap management functions 118c2ecf20Sopenharmony_ci * are minimal (no colormap data written to the 68328 registers...) 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * initial version of this driver: 148c2ecf20Sopenharmony_ci * Copyright (C) 1998,1999 Kenneth Albanowski <kjahds@kjahds.com>, 158c2ecf20Sopenharmony_ci * The Silver Hammer Group, Ltd. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * this version is based on : 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * linux/drivers/video/vfb.c -- Virtual frame buffer device 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Copyright (C) 2002 James Simmons 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Copyright (C) 1997 Geert Uytterhoeven 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 268c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 278c2ecf20Sopenharmony_ci * more details. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/kernel.h> 328c2ecf20Sopenharmony_ci#include <linux/errno.h> 338c2ecf20Sopenharmony_ci#include <linux/string.h> 348c2ecf20Sopenharmony_ci#include <linux/mm.h> 358c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 388c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 398c2ecf20Sopenharmony_ci#include <linux/fb.h> 408c2ecf20Sopenharmony_ci#include <linux/init.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#if defined(CONFIG_M68VZ328) 438c2ecf20Sopenharmony_ci#include <asm/MC68VZ328.h> 448c2ecf20Sopenharmony_ci#elif defined(CONFIG_M68EZ328) 458c2ecf20Sopenharmony_ci#include <asm/MC68EZ328.h> 468c2ecf20Sopenharmony_ci#elif defined(CONFIG_M68328) 478c2ecf20Sopenharmony_ci#include <asm/MC68328.h> 488c2ecf20Sopenharmony_ci#else 498c2ecf20Sopenharmony_ci#error wrong architecture for the MC68x328 frame buffer device 508c2ecf20Sopenharmony_ci#endif 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic u_long videomemory; 538c2ecf20Sopenharmony_cistatic u_long videomemorysize; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic struct fb_info fb_info; 568c2ecf20Sopenharmony_cistatic u32 mc68x328fb_pseudo_palette[16]; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo mc68x328fb_default __initdata = { 598c2ecf20Sopenharmony_ci .red = { 0, 8, 0 }, 608c2ecf20Sopenharmony_ci .green = { 0, 8, 0 }, 618c2ecf20Sopenharmony_ci .blue = { 0, 8, 0 }, 628c2ecf20Sopenharmony_ci .activate = FB_ACTIVATE_TEST, 638c2ecf20Sopenharmony_ci .height = -1, 648c2ecf20Sopenharmony_ci .width = -1, 658c2ecf20Sopenharmony_ci .pixclock = 20000, 668c2ecf20Sopenharmony_ci .left_margin = 64, 678c2ecf20Sopenharmony_ci .right_margin = 64, 688c2ecf20Sopenharmony_ci .upper_margin = 32, 698c2ecf20Sopenharmony_ci .lower_margin = 32, 708c2ecf20Sopenharmony_ci .hsync_len = 64, 718c2ecf20Sopenharmony_ci .vsync_len = 2, 728c2ecf20Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct fb_fix_screeninfo mc68x328fb_fix __initconst = { 768c2ecf20Sopenharmony_ci .id = "68328fb", 778c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 788c2ecf20Sopenharmony_ci .xpanstep = 1, 798c2ecf20Sopenharmony_ci .ypanstep = 1, 808c2ecf20Sopenharmony_ci .ywrapstep = 1, 818c2ecf20Sopenharmony_ci .accel = FB_ACCEL_NONE, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* 858c2ecf20Sopenharmony_ci * Interface used by the world 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ciint mc68x328fb_init(void); 888c2ecf20Sopenharmony_ciint mc68x328fb_setup(char *); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int mc68x328fb_check_var(struct fb_var_screeninfo *var, 918c2ecf20Sopenharmony_ci struct fb_info *info); 928c2ecf20Sopenharmony_cistatic int mc68x328fb_set_par(struct fb_info *info); 938c2ecf20Sopenharmony_cistatic int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 948c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info); 958c2ecf20Sopenharmony_cistatic int mc68x328fb_pan_display(struct fb_var_screeninfo *var, 968c2ecf20Sopenharmony_ci struct fb_info *info); 978c2ecf20Sopenharmony_cistatic int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic const struct fb_ops mc68x328fb_ops = { 1008c2ecf20Sopenharmony_ci .fb_check_var = mc68x328fb_check_var, 1018c2ecf20Sopenharmony_ci .fb_set_par = mc68x328fb_set_par, 1028c2ecf20Sopenharmony_ci .fb_setcolreg = mc68x328fb_setcolreg, 1038c2ecf20Sopenharmony_ci .fb_pan_display = mc68x328fb_pan_display, 1048c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 1058c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 1068c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 1078c2ecf20Sopenharmony_ci .fb_mmap = mc68x328fb_mmap, 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* 1118c2ecf20Sopenharmony_ci * Internal routines 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic u_long get_line_length(int xres_virtual, int bpp) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci u_long length; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci length = xres_virtual * bpp; 1198c2ecf20Sopenharmony_ci length = (length + 31) & ~31; 1208c2ecf20Sopenharmony_ci length >>= 3; 1218c2ecf20Sopenharmony_ci return (length); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Setting the video mode has been split into two parts. 1268c2ecf20Sopenharmony_ci * First part, xxxfb_check_var, must not write anything 1278c2ecf20Sopenharmony_ci * to hardware, it should only verify and adjust var. 1288c2ecf20Sopenharmony_ci * This means it doesn't alter par but it does use hardware 1298c2ecf20Sopenharmony_ci * data from it to check this var. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int mc68x328fb_check_var(struct fb_var_screeninfo *var, 1338c2ecf20Sopenharmony_ci struct fb_info *info) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci u_long line_length; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 1398c2ecf20Sopenharmony_ci * as FB_VMODE_SMOOTH_XPAN is only used internally 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_CONUPDATE) { 1438c2ecf20Sopenharmony_ci var->vmode |= FB_VMODE_YWRAP; 1448c2ecf20Sopenharmony_ci var->xoffset = info->var.xoffset; 1458c2ecf20Sopenharmony_ci var->yoffset = info->var.yoffset; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Some very basic checks 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci if (!var->xres) 1528c2ecf20Sopenharmony_ci var->xres = 1; 1538c2ecf20Sopenharmony_ci if (!var->yres) 1548c2ecf20Sopenharmony_ci var->yres = 1; 1558c2ecf20Sopenharmony_ci if (var->xres > var->xres_virtual) 1568c2ecf20Sopenharmony_ci var->xres_virtual = var->xres; 1578c2ecf20Sopenharmony_ci if (var->yres > var->yres_virtual) 1588c2ecf20Sopenharmony_ci var->yres_virtual = var->yres; 1598c2ecf20Sopenharmony_ci if (var->bits_per_pixel <= 1) 1608c2ecf20Sopenharmony_ci var->bits_per_pixel = 1; 1618c2ecf20Sopenharmony_ci else if (var->bits_per_pixel <= 8) 1628c2ecf20Sopenharmony_ci var->bits_per_pixel = 8; 1638c2ecf20Sopenharmony_ci else if (var->bits_per_pixel <= 16) 1648c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 1658c2ecf20Sopenharmony_ci else if (var->bits_per_pixel <= 24) 1668c2ecf20Sopenharmony_ci var->bits_per_pixel = 24; 1678c2ecf20Sopenharmony_ci else if (var->bits_per_pixel <= 32) 1688c2ecf20Sopenharmony_ci var->bits_per_pixel = 32; 1698c2ecf20Sopenharmony_ci else 1708c2ecf20Sopenharmony_ci return -EINVAL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (var->xres_virtual < var->xoffset + var->xres) 1738c2ecf20Sopenharmony_ci var->xres_virtual = var->xoffset + var->xres; 1748c2ecf20Sopenharmony_ci if (var->yres_virtual < var->yoffset + var->yres) 1758c2ecf20Sopenharmony_ci var->yres_virtual = var->yoffset + var->yres; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * Memory limit 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci line_length = 1818c2ecf20Sopenharmony_ci get_line_length(var->xres_virtual, var->bits_per_pixel); 1828c2ecf20Sopenharmony_ci if (line_length * var->yres_virtual > videomemorysize) 1838c2ecf20Sopenharmony_ci return -ENOMEM; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * Now that we checked it we alter var. The reason being is that the video 1878c2ecf20Sopenharmony_ci * mode passed in might not work but slight changes to it might make it 1888c2ecf20Sopenharmony_ci * work. This way we let the user know what is acceptable. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 1918c2ecf20Sopenharmony_ci case 1: 1928c2ecf20Sopenharmony_ci var->red.offset = 0; 1938c2ecf20Sopenharmony_ci var->red.length = 1; 1948c2ecf20Sopenharmony_ci var->green.offset = 0; 1958c2ecf20Sopenharmony_ci var->green.length = 1; 1968c2ecf20Sopenharmony_ci var->blue.offset = 0; 1978c2ecf20Sopenharmony_ci var->blue.length = 1; 1988c2ecf20Sopenharmony_ci var->transp.offset = 0; 1998c2ecf20Sopenharmony_ci var->transp.length = 0; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci case 8: 2028c2ecf20Sopenharmony_ci var->red.offset = 0; 2038c2ecf20Sopenharmony_ci var->red.length = 8; 2048c2ecf20Sopenharmony_ci var->green.offset = 0; 2058c2ecf20Sopenharmony_ci var->green.length = 8; 2068c2ecf20Sopenharmony_ci var->blue.offset = 0; 2078c2ecf20Sopenharmony_ci var->blue.length = 8; 2088c2ecf20Sopenharmony_ci var->transp.offset = 0; 2098c2ecf20Sopenharmony_ci var->transp.length = 0; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci case 16: /* RGBA 5551 */ 2128c2ecf20Sopenharmony_ci if (var->transp.length) { 2138c2ecf20Sopenharmony_ci var->red.offset = 0; 2148c2ecf20Sopenharmony_ci var->red.length = 5; 2158c2ecf20Sopenharmony_ci var->green.offset = 5; 2168c2ecf20Sopenharmony_ci var->green.length = 5; 2178c2ecf20Sopenharmony_ci var->blue.offset = 10; 2188c2ecf20Sopenharmony_ci var->blue.length = 5; 2198c2ecf20Sopenharmony_ci var->transp.offset = 15; 2208c2ecf20Sopenharmony_ci var->transp.length = 1; 2218c2ecf20Sopenharmony_ci } else { /* RGB 565 */ 2228c2ecf20Sopenharmony_ci var->red.offset = 0; 2238c2ecf20Sopenharmony_ci var->red.length = 5; 2248c2ecf20Sopenharmony_ci var->green.offset = 5; 2258c2ecf20Sopenharmony_ci var->green.length = 6; 2268c2ecf20Sopenharmony_ci var->blue.offset = 11; 2278c2ecf20Sopenharmony_ci var->blue.length = 5; 2288c2ecf20Sopenharmony_ci var->transp.offset = 0; 2298c2ecf20Sopenharmony_ci var->transp.length = 0; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case 24: /* RGB 888 */ 2338c2ecf20Sopenharmony_ci var->red.offset = 0; 2348c2ecf20Sopenharmony_ci var->red.length = 8; 2358c2ecf20Sopenharmony_ci var->green.offset = 8; 2368c2ecf20Sopenharmony_ci var->green.length = 8; 2378c2ecf20Sopenharmony_ci var->blue.offset = 16; 2388c2ecf20Sopenharmony_ci var->blue.length = 8; 2398c2ecf20Sopenharmony_ci var->transp.offset = 0; 2408c2ecf20Sopenharmony_ci var->transp.length = 0; 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci case 32: /* RGBA 8888 */ 2438c2ecf20Sopenharmony_ci var->red.offset = 0; 2448c2ecf20Sopenharmony_ci var->red.length = 8; 2458c2ecf20Sopenharmony_ci var->green.offset = 8; 2468c2ecf20Sopenharmony_ci var->green.length = 8; 2478c2ecf20Sopenharmony_ci var->blue.offset = 16; 2488c2ecf20Sopenharmony_ci var->blue.length = 8; 2498c2ecf20Sopenharmony_ci var->transp.offset = 24; 2508c2ecf20Sopenharmony_ci var->transp.length = 8; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci var->red.msb_right = 0; 2548c2ecf20Sopenharmony_ci var->green.msb_right = 0; 2558c2ecf20Sopenharmony_ci var->blue.msb_right = 0; 2568c2ecf20Sopenharmony_ci var->transp.msb_right = 0; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* This routine actually sets the video mode. It's in here where we 2628c2ecf20Sopenharmony_ci * the hardware state info->par and fix which can be affected by the 2638c2ecf20Sopenharmony_ci * change in par. For this driver it doesn't do much. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic int mc68x328fb_set_par(struct fb_info *info) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci info->fix.line_length = get_line_length(info->var.xres_virtual, 2688c2ecf20Sopenharmony_ci info->var.bits_per_pixel); 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* 2738c2ecf20Sopenharmony_ci * Set a single color register. The values supplied are already 2748c2ecf20Sopenharmony_ci * rounded down to the hardware's capabilities (according to the 2758c2ecf20Sopenharmony_ci * entries in the var structure). Return != 0 for invalid regno. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 2798c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci if (regno >= 256) /* no. of hw registers */ 2828c2ecf20Sopenharmony_ci return 1; 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * Program hardware... do anything you want with transp 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* grayscale works only partially under directcolor */ 2888c2ecf20Sopenharmony_ci if (info->var.grayscale) { 2898c2ecf20Sopenharmony_ci /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 2908c2ecf20Sopenharmony_ci red = green = blue = 2918c2ecf20Sopenharmony_ci (red * 77 + green * 151 + blue * 28) >> 8; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Directcolor: 2958c2ecf20Sopenharmony_ci * var->{color}.offset contains start of bitfield 2968c2ecf20Sopenharmony_ci * var->{color}.length contains length of bitfield 2978c2ecf20Sopenharmony_ci * {hardwarespecific} contains width of RAMDAC 2988c2ecf20Sopenharmony_ci * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) 2998c2ecf20Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * Pseudocolor: 3028c2ecf20Sopenharmony_ci * uses offset = 0 && length = RAMDAC register width. 3038c2ecf20Sopenharmony_ci * var->{color}.offset is 0 3048c2ecf20Sopenharmony_ci * var->{color}.length contains width of DAC 3058c2ecf20Sopenharmony_ci * cmap is not used 3068c2ecf20Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 3078c2ecf20Sopenharmony_ci * Truecolor: 3088c2ecf20Sopenharmony_ci * does not use DAC. Usually 3 are present. 3098c2ecf20Sopenharmony_ci * var->{color}.offset contains start of bitfield 3108c2ecf20Sopenharmony_ci * var->{color}.length contains length of bitfield 3118c2ecf20Sopenharmony_ci * cmap is programmed to (red << red.offset) | (green << green.offset) | 3128c2ecf20Sopenharmony_ci * (blue << blue.offset) | (transp << transp.offset) 3138c2ecf20Sopenharmony_ci * RAMDAC does not exist 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) 3168c2ecf20Sopenharmony_ci switch (info->fix.visual) { 3178c2ecf20Sopenharmony_ci case FB_VISUAL_TRUECOLOR: 3188c2ecf20Sopenharmony_ci case FB_VISUAL_PSEUDOCOLOR: 3198c2ecf20Sopenharmony_ci red = CNVT_TOHW(red, info->var.red.length); 3208c2ecf20Sopenharmony_ci green = CNVT_TOHW(green, info->var.green.length); 3218c2ecf20Sopenharmony_ci blue = CNVT_TOHW(blue, info->var.blue.length); 3228c2ecf20Sopenharmony_ci transp = CNVT_TOHW(transp, info->var.transp.length); 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci case FB_VISUAL_DIRECTCOLOR: 3258c2ecf20Sopenharmony_ci red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ 3268c2ecf20Sopenharmony_ci green = CNVT_TOHW(green, 8); 3278c2ecf20Sopenharmony_ci blue = CNVT_TOHW(blue, 8); 3288c2ecf20Sopenharmony_ci /* hey, there is bug in transp handling... */ 3298c2ecf20Sopenharmony_ci transp = CNVT_TOHW(transp, 8); 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci#undef CNVT_TOHW 3338c2ecf20Sopenharmony_ci /* Truecolor has hardware independent palette */ 3348c2ecf20Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 3358c2ecf20Sopenharmony_ci u32 v; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (regno >= 16) 3388c2ecf20Sopenharmony_ci return 1; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci v = (red << info->var.red.offset) | 3418c2ecf20Sopenharmony_ci (green << info->var.green.offset) | 3428c2ecf20Sopenharmony_ci (blue << info->var.blue.offset) | 3438c2ecf20Sopenharmony_ci (transp << info->var.transp.offset); 3448c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 3458c2ecf20Sopenharmony_ci case 8: 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci case 16: 3488c2ecf20Sopenharmony_ci ((u32 *) (info->pseudo_palette))[regno] = v; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case 24: 3518c2ecf20Sopenharmony_ci case 32: 3528c2ecf20Sopenharmony_ci ((u32 *) (info->pseudo_palette))[regno] = v; 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * Pan or Wrap the Display 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int mc68x328fb_pan_display(struct fb_var_screeninfo *var, 3678c2ecf20Sopenharmony_ci struct fb_info *info) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_YWRAP) { 3708c2ecf20Sopenharmony_ci if (var->yoffset < 0 3718c2ecf20Sopenharmony_ci || var->yoffset >= info->var.yres_virtual 3728c2ecf20Sopenharmony_ci || var->xoffset) 3738c2ecf20Sopenharmony_ci return -EINVAL; 3748c2ecf20Sopenharmony_ci } else { 3758c2ecf20Sopenharmony_ci if (var->xoffset + info->var.xres > info->var.xres_virtual || 3768c2ecf20Sopenharmony_ci var->yoffset + info->var.yres > info->var.yres_virtual) 3778c2ecf20Sopenharmony_ci return -EINVAL; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci info->var.xoffset = var->xoffset; 3808c2ecf20Sopenharmony_ci info->var.yoffset = var->yoffset; 3818c2ecf20Sopenharmony_ci if (var->vmode & FB_VMODE_YWRAP) 3828c2ecf20Sopenharmony_ci info->var.vmode |= FB_VMODE_YWRAP; 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci info->var.vmode &= ~FB_VMODE_YWRAP; 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * Most drivers don't need their own mmap function 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci#ifndef MMU 3958c2ecf20Sopenharmony_ci /* this is uClinux (no MMU) specific code */ 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; 3988c2ecf20Sopenharmony_ci vma->vm_start = videomemory; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci#else 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci#endif 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ciint __init mc68x328fb_setup(char *options) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci if (!options || !*options) 4098c2ecf20Sopenharmony_ci return 1; 4108c2ecf20Sopenharmony_ci return 1; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * Initialisation 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciint __init mc68x328fb_init(void) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci#ifndef MODULE 4208c2ecf20Sopenharmony_ci char *option = NULL; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (fb_get_options("68328fb", &option)) 4238c2ecf20Sopenharmony_ci return -ENODEV; 4248c2ecf20Sopenharmony_ci mc68x328fb_setup(option); 4258c2ecf20Sopenharmony_ci#endif 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * initialize the default mode from the LCD controller registers 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci mc68x328fb_default.xres = LXMAX; 4308c2ecf20Sopenharmony_ci mc68x328fb_default.yres = LYMAX+1; 4318c2ecf20Sopenharmony_ci mc68x328fb_default.xres_virtual = mc68x328fb_default.xres; 4328c2ecf20Sopenharmony_ci mc68x328fb_default.yres_virtual = mc68x328fb_default.yres; 4338c2ecf20Sopenharmony_ci mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01); 4348c2ecf20Sopenharmony_ci videomemory = LSSA; 4358c2ecf20Sopenharmony_ci videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 * 4368c2ecf20Sopenharmony_ci mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci fb_info.screen_base = (void *)videomemory; 4398c2ecf20Sopenharmony_ci fb_info.fbops = &mc68x328fb_ops; 4408c2ecf20Sopenharmony_ci fb_info.var = mc68x328fb_default; 4418c2ecf20Sopenharmony_ci fb_info.fix = mc68x328fb_fix; 4428c2ecf20Sopenharmony_ci fb_info.fix.smem_start = videomemory; 4438c2ecf20Sopenharmony_ci fb_info.fix.smem_len = videomemorysize; 4448c2ecf20Sopenharmony_ci fb_info.fix.line_length = 4458c2ecf20Sopenharmony_ci get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); 4468c2ecf20Sopenharmony_ci fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? 4478c2ecf20Sopenharmony_ci FB_VISUAL_MONO10 : FB_VISUAL_PSEUDOCOLOR; 4488c2ecf20Sopenharmony_ci if (fb_info.var.bits_per_pixel == 1) { 4498c2ecf20Sopenharmony_ci fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; 4508c2ecf20Sopenharmony_ci fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; 4538c2ecf20Sopenharmony_ci fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&fb_info.cmap, 256, 0)) 4568c2ecf20Sopenharmony_ci return -ENOMEM; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (register_framebuffer(&fb_info) < 0) { 4598c2ecf20Sopenharmony_ci fb_dealloc_cmap(&fb_info.cmap); 4608c2ecf20Sopenharmony_ci return -EINVAL; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id); 4648c2ecf20Sopenharmony_ci fb_info(&fb_info, "%dx%dx%d at 0x%08lx\n", 4658c2ecf20Sopenharmony_ci mc68x328fb_default.xres_virtual, 4668c2ecf20Sopenharmony_ci mc68x328fb_default.yres_virtual, 4678c2ecf20Sopenharmony_ci 1 << mc68x328fb_default.bits_per_pixel, videomemory); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cimodule_init(mc68x328fb_init); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci#ifdef MODULE 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void __exit mc68x328fb_cleanup(void) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci unregister_framebuffer(&fb_info); 4798c2ecf20Sopenharmony_ci fb_dealloc_cmap(&fb_info.cmap); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cimodule_exit(mc68x328fb_cleanup); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4858c2ecf20Sopenharmony_ci#endif /* MODULE */ 486