^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/drivers/video/q40fb.c -- Q40 frame buffer device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Richard Zidlicky <rz@linux-m68k.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/q40_master.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define Q40_PHYS_SCREEN_ADDR 0xFE800000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static struct fb_fix_screeninfo q40fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .id = "Q40",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .smem_len = 1024*1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .visual = FB_VISUAL_TRUECOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .line_length = 1024*2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .accel = FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static const struct fb_var_screeninfo q40fb_var = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) .xres = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .yres = 512,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .xres_virtual = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .yres_virtual = 512,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .bits_per_pixel = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .red = {6, 5, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .green = {11, 5, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) .blue = {0, 6, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .activate = FB_ACTIVATE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .height = 230,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .width = 300,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int q40fb_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned blue, unsigned transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Set a single color register. The values supplied have a 16 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * magnitude.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Return != 0 for invalid regno.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (regno > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) red>>=11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) green>>=11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) blue>>=10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ((u32 *)info->pseudo_palette)[regno] = ((red & 31) <<6) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ((green & 31) << 11) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) (blue & 63);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static const struct fb_ops q40fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .fb_setcolreg = q40fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int q40fb_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (!MACH_IS_Q40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* mapped in q40/config.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) info->var = q40fb_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) info->fix = q40fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) info->fbops = &q40fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) info->flags = FBINFO_DEFAULT; /* not as module for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) info->pseudo_palette = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) info->par = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) info->screen_base = (char *) q40fb_fix.smem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) master_outb(3, DISPLAY_CONTROL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (register_framebuffer(info) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) printk(KERN_ERR "Unable to register Q40 frame buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) fb_info(info, "Q40 frame buffer alive and kicking !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static struct platform_driver q40fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .probe = q40fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .name = "q40fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static struct platform_device q40fb_device = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .name = "q40fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int __init q40fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (fb_get_options("q40fb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ret = platform_driver_register(&q40fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ret = platform_device_register(&q40fb_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) platform_driver_unregister(&q40fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return ret;
^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) module_init(q40fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) MODULE_LICENSE("GPL");