^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * This driver was written to be used with the Arc LCD board. Arc uses a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * set of KS108 chips that control individual 64x64 LCD matrices. The board
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * so on. The interface between the board and the host is TTL based GPIO. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * GPIO requirements are 8 writable data lines and 4+n lines for control. On a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * GPIO-less system, the board can be tested by connecting the respective sigs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * up to a parallel port connector. The driver requires the IO addresses for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * data and control GPIO at load time. It is unable to probe for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * existence of the LCD so it must be told at load time whether it should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * be enabled or not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Todo:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * - testing with 4x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * - testing with interrupt hw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * General notes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * - User must set tuhold. It's in microseconds. According to the 108 spec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * the hold time is supposed to be at least 1 microsecond.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * - User must set num_cols=x num_rows=y, eg: x=2 means 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * - User must set arcfb_enable=1 to enable it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/arcfb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define floor8(a) (a&(~0x07))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define floorXres(a,xres) (a&(~(xres - 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define iceil8(a) (((int)((a+7)/8))*8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define ceil64(a) (a|0x3F)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define ceilXres(a,xres) (a|(xres - 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* ks108 chipset specific defines and code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define KS_SET_DPY_START_LINE 0xC0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define KS_SET_PAGE_NUM 0xB8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define KS_SET_X 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define KS_CEHI 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define KS_CELO 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define KS_SEL_CMD 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define KS_SEL_DATA 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define KS_DPY_ON 0x3F
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define KS_DPY_OFF 0x3E
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define KS_INTACK 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define KS_CLRINT 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct arcfb_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) unsigned long dio_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) unsigned long cio_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned long c2io_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) atomic_t ref_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned char cslut[9];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static const struct fb_fix_screeninfo arcfb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .id = "arcfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .visual = FB_VISUAL_MONO01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .xpanstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .ypanstep = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .ywrapstep = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .accel = FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static const struct fb_var_screeninfo arcfb_var = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .xres = 128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .yres = 64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .xres_virtual = 128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .yres_virtual = 64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .bits_per_pixel = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .nonstd = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static unsigned long num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static unsigned long num_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static unsigned long dio_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static unsigned long cio_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static unsigned long c2io_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static unsigned long splashval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static unsigned long tuhold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static unsigned int nosplash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static unsigned int arcfb_enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static unsigned int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void ks108_writeb_ctl(struct arcfb_par *par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) unsigned int chipindex, unsigned char value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned char chipselval = par->cslut[chipindex];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) outb(value, par->dio_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) udelay(tuhold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr);
^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 void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) outb(value, par->cio_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) udelay(tuhold);
^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 unsigned char ks108_readb_ctl2(struct arcfb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return inb(par->c2io_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static void ks108_writeb_data(struct arcfb_par *par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) unsigned int chipindex, unsigned char value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) unsigned char chipselval = par->cslut[chipindex];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) outb(value, par->dio_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) udelay(tuhold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void ks108_set_start_line(struct arcfb_par *par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) unsigned int chipindex, unsigned char y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void ks108_set_yaddr(struct arcfb_par *par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) unsigned int chipindex, unsigned char y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static void ks108_set_xaddr(struct arcfb_par *par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) unsigned int chipindex, unsigned char x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) ks108_writeb_ctl(par, chipindex, KS_SET_X|x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) int i,j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) for (i = 0; i <= 8; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) ks108_set_yaddr(par, chipindex, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) ks108_set_xaddr(par, chipindex, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) for (j = 0; j < 64; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) ks108_writeb_data(par, chipindex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) (unsigned char) splashval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /* main arcfb functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static int arcfb_open(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) atomic_inc(&par->ref_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int arcfb_release(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) int count = atomic_read(&par->ref_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) atomic_dec(&par->ref_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int arcfb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) && (info->var.yres <= 64)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) for (i = 0; i < num_cols; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) ks108_set_start_line(par, i, var->yoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) info->var.yoffset = var->yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static irqreturn_t arcfb_interrupt(int vec, void *dev_instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct fb_info *info = dev_instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) unsigned char ctl2status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ctl2status = ks108_readb_ctl2(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) ks108_writeb_mainctl(par, KS_CLRINT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) spin_lock(&par->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (waitqueue_active(&arcfb_waitq)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) wake_up(&arcfb_waitq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) spin_unlock(&par->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * here we handle a specific page on the lcd. the complexity comes from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * the fact that the fb is laidout in 8xX vertical columns. we extract
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * each write of 8 vertical pixels. then we shift out as we move along
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * X. That's what rightshift does. bitmask selects the desired input bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) unsigned int left, unsigned int right, unsigned int distance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) unsigned char *src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) unsigned int xindex, yindex, chipindex, linesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) unsigned char bitmask, rightshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) xindex = left >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) yindex = upper >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) chipindex = (xindex + (yindex*num_cols));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) ks108_set_yaddr(par, chipindex, upper/8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) linesize = par->info->var.xres/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) src = (unsigned char __force *) par->info->screen_base + (left/8) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) (upper * linesize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ks108_set_xaddr(par, chipindex, left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) bitmask=1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) rightshift=0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) while (left <= right) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) for (i = 0; i < 8; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if ( i > rightshift) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) val |= (*(src + (i*linesize)) & bitmask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) << (i - rightshift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) val |= (*(src + (i*linesize)) & bitmask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) >> (rightshift - i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) ks108_writeb_data(par, chipindex, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) left++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (bitmask == 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) bitmask = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) src++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) rightshift=0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) bitmask <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) rightshift++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * here we handle the entire vertical page of the update. we write across
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * lcd chips. update_page uses the upper/left values to decide which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * chip to select for the right. upper is needed for setting the page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * desired for the write.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) unsigned int bottom, unsigned int left, unsigned int right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) unsigned int distance, upper, lower;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) distance = (bottom - top) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) upper = top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) lower = top + 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) while (distance > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) distance -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) arcfb_lcd_update_page(par, upper, left, right, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) upper = lower + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) lower = upper + 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * here we handle horizontal blocks for the update. update_vert will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * handle spaning multiple pages. we break out each horizontal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) * block in to individual blocks no taller than 64 pixels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) unsigned int right, unsigned int top, unsigned int h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) unsigned int distance, upper, lower;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) distance = h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) upper = floor8(top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) lower = min(upper + distance - 1, ceil64(upper));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) while (distance > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) distance -= ((lower - upper) + 1 );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) arcfb_lcd_update_vert(par, upper, lower, left, right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) upper = lower + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) lower = min(upper + distance - 1, ceil64(upper));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * here we start the process of splitting out the fb update into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * individual blocks of pixels. we end up splitting into 64x64 blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * and finally down to 64x8 pages.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) unsigned int dy, unsigned int w, unsigned int h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) unsigned int left, right, distance, y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /* align the request first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) y = floor8(dy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) h += dy - y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) h = iceil8(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) distance = w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) left = dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) right = min(left + w - 1, ceil64(left));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) while (distance > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) arcfb_lcd_update_horiz(par, left, right, y, h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) distance -= ((right - left) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) left = right + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) right = min(left + distance - 1, ceil64(left));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static void arcfb_fillrect(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) const struct fb_fillrect *rect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) sys_fillrect(info, rect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* update the physical lcd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) static void arcfb_copyarea(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) const struct fb_copyarea *area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) sys_copyarea(info, area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /* update the physical lcd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) sys_imageblit(info, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) /* update the physical lcd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) arcfb_lcd_update(par, image->dx, image->dy, image->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) image->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static int arcfb_ioctl(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) void __user *argp = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct arcfb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) case FBIO_WAITEVENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) DEFINE_WAIT(wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) /* illegal to wait on arc if no irq will occur */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!par->irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) /* wait until the Arc has generated an interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * which will wake us up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) spin_lock_irqsave(&par->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) prepare_to_wait(&arcfb_waitq, &wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) spin_unlock_irqrestore(&par->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) schedule();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) finish_wait(&arcfb_waitq, &wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) case FBIO_GETCONTROL2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) unsigned char ctl2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) ctl2 = ks108_readb_ctl2(info->par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (copy_to_user(argp, &ctl2, sizeof(ctl2)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * this is the access path from userspace. they can seek and write to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * the fb. it's inefficient for them to do anything less than 64*8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * writes since we update the lcd in each write() anyway.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) /* modded from epson 1355 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) unsigned long p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) int err=-EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct arcfb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) unsigned int xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) p = *ppos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) xres = info->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) fbmemlength = (xres * info->var.yres)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (p > fbmemlength)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if ((count + p) > fbmemlength) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) count = fbmemlength - p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) err = -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) char *base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) base_addr = (char __force *)info->screen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) count -= copy_from_user(base_addr + p, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) *ppos += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) err = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) bitppos = p*8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) startpos = floorXres(bitppos, xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) endpos = ceilXres((bitppos + (count*8)), xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) bitcount = endpos - startpos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) x = startpos % xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) y = startpos / xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) w = xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) h = bitcount / xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) arcfb_lcd_update(par, x, y, w, h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static const struct fb_ops arcfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) .fb_open = arcfb_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .fb_read = fb_sys_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .fb_write = arcfb_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .fb_release = arcfb_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .fb_pan_display = arcfb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) .fb_fillrect = arcfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) .fb_copyarea = arcfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) .fb_imageblit = arcfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) .fb_ioctl = arcfb_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static int arcfb_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) int retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) int videomemorysize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) unsigned char *videomemory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) struct arcfb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) videomemorysize = (((64*64)*num_cols)*num_rows)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* We need a flat backing store for the Arc's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) less-flat actual paged framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) videomemory = vzalloc(videomemorysize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (!videomemory)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) info->screen_base = (char __iomem *)videomemory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) info->fbops = &arcfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) info->var = arcfb_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) info->fix = arcfb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) par->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (!dio_addr || !cio_addr || !c2io_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) printk(KERN_WARNING "no IO addresses supplied\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) par->dio_addr = dio_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) par->cio_addr = cio_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) par->c2io_addr = c2io_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) par->cslut[0] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) par->cslut[1] = 0x06;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) info->flags = FBINFO_FLAG_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) spin_lock_init(&par->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) par->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (request_irq(par->irq, &arcfb_interrupt, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) "arcfb", info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) "arcfb: Failed req IRQ %d\n", par->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) retval = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) platform_set_drvdata(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) fb_info(info, "Arc frame buffer device, using %dK of video memory\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) videomemorysize >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) /* this inits the lcd but doesn't clear dirty pixels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) for (i = 0; i < num_cols * num_rows; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) ks108_writeb_ctl(par, i, KS_DPY_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) ks108_set_start_line(par, i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) ks108_set_yaddr(par, i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) ks108_set_xaddr(par, i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) ks108_writeb_ctl(par, i, KS_DPY_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) /* if we were told to splash the screen, we just clear it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (!nosplash) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) for (i = 0; i < num_cols * num_rows; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) fb_info(info, "splashing lcd %d\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) ks108_set_start_line(par, i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) ks108_clear_lcd(par, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) err1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) vfree(videomemory);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static int arcfb_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) struct fb_info *info = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) free_irq(((struct arcfb_par *)(info->par))->irq, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) vfree((void __force *)info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static struct platform_driver arcfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) .probe = arcfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) .remove = arcfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) .name = "arcfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) static struct platform_device *arcfb_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) static int __init arcfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (!arcfb_enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) ret = platform_driver_register(&arcfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) arcfb_device = platform_device_alloc("arcfb", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (arcfb_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) ret = platform_device_add(arcfb_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) platform_device_put(arcfb_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) platform_driver_unregister(&arcfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) static void __exit arcfb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) platform_device_unregister(arcfb_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) platform_driver_unregister(&arcfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) module_param(num_cols, ulong, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) module_param(num_rows, ulong, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) module_param(nosplash, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) module_param(arcfb_enable, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) module_param_hw(dio_addr, ulong, ioport, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) module_param_hw(cio_addr, ulong, ioport, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) module_param_hw(c2io_addr, ulong, ioport, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) module_param(splashval, ulong, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) module_param(tuhold, ulong, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) module_param_hw(irq, uint, irq, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) MODULE_PARM_DESC(irq, "IRQ for the Arc board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) module_init(arcfb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) module_exit(arcfb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) MODULE_AUTHOR("Jaya Kumar");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)