18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/q40fb.c -- Q40 frame buffer device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2001 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Richard Zidlicky <rz@linux-m68k.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 98c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 108c2ecf20Sopenharmony_ci * more details. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 228c2ecf20Sopenharmony_ci#include <asm/setup.h> 238c2ecf20Sopenharmony_ci#include <asm/q40_master.h> 248c2ecf20Sopenharmony_ci#include <linux/fb.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define Q40_PHYS_SCREEN_ADDR 0xFE800000 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo q40fb_fix = { 308c2ecf20Sopenharmony_ci .id = "Q40", 318c2ecf20Sopenharmony_ci .smem_len = 1024*1024, 328c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 338c2ecf20Sopenharmony_ci .visual = FB_VISUAL_TRUECOLOR, 348c2ecf20Sopenharmony_ci .line_length = 1024*2, 358c2ecf20Sopenharmony_ci .accel = FB_ACCEL_NONE, 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const struct fb_var_screeninfo q40fb_var = { 398c2ecf20Sopenharmony_ci .xres = 1024, 408c2ecf20Sopenharmony_ci .yres = 512, 418c2ecf20Sopenharmony_ci .xres_virtual = 1024, 428c2ecf20Sopenharmony_ci .yres_virtual = 512, 438c2ecf20Sopenharmony_ci .bits_per_pixel = 16, 448c2ecf20Sopenharmony_ci .red = {6, 5, 0}, 458c2ecf20Sopenharmony_ci .green = {11, 5, 0}, 468c2ecf20Sopenharmony_ci .blue = {0, 6, 0}, 478c2ecf20Sopenharmony_ci .activate = FB_ACTIVATE_NOW, 488c2ecf20Sopenharmony_ci .height = 230, 498c2ecf20Sopenharmony_ci .width = 300, 508c2ecf20Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED, 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green, 548c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 558c2ecf20Sopenharmony_ci struct fb_info *info) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci /* 588c2ecf20Sopenharmony_ci * Set a single color register. The values supplied have a 16 bit 598c2ecf20Sopenharmony_ci * magnitude. 608c2ecf20Sopenharmony_ci * Return != 0 for invalid regno. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (regno > 255) 648c2ecf20Sopenharmony_ci return 1; 658c2ecf20Sopenharmony_ci red>>=11; 668c2ecf20Sopenharmony_ci green>>=11; 678c2ecf20Sopenharmony_ci blue>>=10; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (regno < 16) { 708c2ecf20Sopenharmony_ci ((u32 *)info->pseudo_palette)[regno] = ((red & 31) <<6) | 718c2ecf20Sopenharmony_ci ((green & 31) << 11) | 728c2ecf20Sopenharmony_ci (blue & 63); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct fb_ops q40fb_ops = { 788c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 798c2ecf20Sopenharmony_ci .fb_setcolreg = q40fb_setcolreg, 808c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 818c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 828c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int q40fb_probe(struct platform_device *dev) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct fb_info *info; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (!MACH_IS_Q40) 908c2ecf20Sopenharmony_ci return -ENXIO; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* mapped in q40/config.c */ 938c2ecf20Sopenharmony_ci q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); 968c2ecf20Sopenharmony_ci if (!info) 978c2ecf20Sopenharmony_ci return -ENOMEM; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci info->var = q40fb_var; 1008c2ecf20Sopenharmony_ci info->fix = q40fb_fix; 1018c2ecf20Sopenharmony_ci info->fbops = &q40fb_ops; 1028c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT; /* not as module for now */ 1038c2ecf20Sopenharmony_ci info->pseudo_palette = info->par; 1048c2ecf20Sopenharmony_ci info->par = NULL; 1058c2ecf20Sopenharmony_ci info->screen_base = (char *) q40fb_fix.smem_start; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 1088c2ecf20Sopenharmony_ci framebuffer_release(info); 1098c2ecf20Sopenharmony_ci return -ENOMEM; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci master_outb(3, DISPLAY_CONTROL_REG); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (register_framebuffer(info) < 0) { 1158c2ecf20Sopenharmony_ci printk(KERN_ERR "Unable to register Q40 frame buffer\n"); 1168c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 1178c2ecf20Sopenharmony_ci framebuffer_release(info); 1188c2ecf20Sopenharmony_ci return -EINVAL; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci fb_info(info, "Q40 frame buffer alive and kicking !\n"); 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct platform_driver q40fb_driver = { 1268c2ecf20Sopenharmony_ci .probe = q40fb_probe, 1278c2ecf20Sopenharmony_ci .driver = { 1288c2ecf20Sopenharmony_ci .name = "q40fb", 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic struct platform_device q40fb_device = { 1338c2ecf20Sopenharmony_ci .name = "q40fb", 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciint __init q40fb_init(void) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int ret = 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (fb_get_options("q40fb", NULL)) 1418c2ecf20Sopenharmony_ci return -ENODEV; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = platform_driver_register(&q40fb_driver); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!ret) { 1468c2ecf20Sopenharmony_ci ret = platform_device_register(&q40fb_device); 1478c2ecf20Sopenharmony_ci if (ret) 1488c2ecf20Sopenharmony_ci platform_driver_unregister(&q40fb_driver); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cimodule_init(q40fb_init); 1548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 155