cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

arcfb.c (16889B)


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