brintos

brintos / linux-shallow public Read only

0
0
Text · 11.4 KiB · 97db325 Raw
515 lines · c
1/*2 * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device3 *4 * (C) 1999 Mihai Spatar5 * (C) 2000 YAEGASHI Takeshi6 * (C) 2003, 2004 Paul Mundt7 * (C) 2003, 2004, 2006 Andriy Skulysh8 *9 *  This file is subject to the terms and conditions of the GNU General Public10 *  License. See the file COPYING in the main directory of this archive for11 *  more details.12 */13 14#include <linux/module.h>15#include <linux/kernel.h>16#include <linux/errno.h>17#include <linux/string.h>18#include <linux/mm.h>19#include <linux/delay.h>20#include <linux/init.h>21#include <linux/platform_device.h>22#include <linux/fb.h>23 24#include <asm/machvec.h>25#include <linux/uaccess.h>26#include <asm/io.h>27#include <asm/hd64461.h>28#include <cpu/dac.h>29 30#define	WIDTH 64031 32static struct fb_var_screeninfo hitfb_var = {33	.activate	= FB_ACTIVATE_NOW,34	.height		= -1,35	.width		= -1,36	.vmode		= FB_VMODE_NONINTERLACED,37};38 39static struct fb_fix_screeninfo hitfb_fix = {40	.id		= "Hitachi HD64461",41	.type		= FB_TYPE_PACKED_PIXELS,42	.accel		= FB_ACCEL_NONE,43};44 45static volatile void __iomem *hitfb_offset_to_addr(unsigned int offset)46{47	return (__force volatile void __iomem *)(uintptr_t)offset;48}49 50static u16 hitfb_readw(unsigned int offset)51{52	return fb_readw(hitfb_offset_to_addr(offset));53}54 55static void hitfb_writew(u16 value, unsigned int offset)56{57	fb_writew(value, hitfb_offset_to_addr(offset));58}59 60static inline void hitfb_accel_wait(void)61{62	while (hitfb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS)63		;64}65 66static inline void hitfb_accel_start(int truecolor)67{68	if (truecolor) {69		hitfb_writew(6, HD64461_GRCFGR);70	} else {71		hitfb_writew(7, HD64461_GRCFGR);72	}73}74 75static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy,76					u16 width, u16 height)77{78	u32 saddr = WIDTH * dy + dx;79	if (truecolor)80		saddr <<= 1;81 82	hitfb_writew(width-1, HD64461_BBTDWR);83	hitfb_writew(height-1, HD64461_BBTDHR);84 85	hitfb_writew(saddr & 0xffff, HD64461_BBTDSARL);86	hitfb_writew(saddr >> 16, HD64461_BBTDSARH);87 88}89 90static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,91				      u16 dy, u16 width, u16 height, u16 rop,92				      u32 mask_addr)93{94	u32 saddr, daddr;95	u32 maddr = 0;96 97	height--;98	width--;99	hitfb_writew(rop, HD64461_BBTROPR);100	if ((sy < dy) || ((sy == dy) && (sx <= dx))) {101		saddr = WIDTH * (sy + height) + sx + width;102		daddr = WIDTH * (dy + height) + dx + width;103		if (mask_addr) {104			if (truecolor)105				maddr = ((width >> 3) + 1) * (height + 1) - 1;106			else107				maddr =108				    (((width >> 4) + 1) * (height + 1) - 1) * 2;109 110			hitfb_writew((1 << 5) | 1, HD64461_BBTMDR);111		} else112			hitfb_writew(1, HD64461_BBTMDR);113	} else {114		saddr = WIDTH * sy + sx;115		daddr = WIDTH * dy + dx;116		if (mask_addr) {117			hitfb_writew((1 << 5), HD64461_BBTMDR);118		} else {119			hitfb_writew(0, HD64461_BBTMDR);120		}121	}122	if (truecolor) {123		saddr <<= 1;124		daddr <<= 1;125	}126	hitfb_writew(width, HD64461_BBTDWR);127	hitfb_writew(height, HD64461_BBTDHR);128	hitfb_writew(saddr & 0xffff, HD64461_BBTSSARL);129	hitfb_writew(saddr >> 16, HD64461_BBTSSARH);130	hitfb_writew(daddr & 0xffff, HD64461_BBTDSARL);131	hitfb_writew(daddr >> 16, HD64461_BBTDSARH);132	if (mask_addr) {133		maddr += mask_addr;134		hitfb_writew(maddr & 0xffff, HD64461_BBTMARL);135		hitfb_writew(maddr >> 16, HD64461_BBTMARH);136	}137	hitfb_accel_start(truecolor);138}139 140static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)141{142	if (rect->rop != ROP_COPY)143		cfb_fillrect(p, rect);144	else {145		hitfb_accel_wait();146		hitfb_writew(0x00f0, HD64461_BBTROPR);147		hitfb_writew(16, HD64461_BBTMDR);148 149		if (p->var.bits_per_pixel == 16) {150			hitfb_writew(((u32 *) (p->pseudo_palette))[rect->color],151				  HD64461_GRSCR);152			hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width,153					     rect->height);154			hitfb_accel_start(1);155		} else {156			hitfb_writew(rect->color, HD64461_GRSCR);157			hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width,158					     rect->height);159			hitfb_accel_start(0);160		}161	}162}163 164static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)165{166	hitfb_accel_wait();167	hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy,168			   area->dx, area->dy, area->width, area->height,169			   0x00cc, 0);170}171 172static int hitfb_pan_display(struct fb_var_screeninfo *var,173			     struct fb_info *info)174{175	int xoffset = var->xoffset;176	int yoffset = var->yoffset;177 178	if (xoffset != 0)179		return -EINVAL;180 181	hitfb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR);182 183	return 0;184}185 186static int hitfb_blank(int blank_mode, struct fb_info *info)187{188	unsigned short v;189 190	if (blank_mode) {191		v = hitfb_readw(HD64461_LDR1);192		v &= ~HD64461_LDR1_DON;193		hitfb_writew(v, HD64461_LDR1);194 195		v = hitfb_readw(HD64461_LCDCCR);196		v |= HD64461_LCDCCR_MOFF;197		hitfb_writew(v, HD64461_LCDCCR);198 199		v = hitfb_readw(HD64461_STBCR);200		v |= HD64461_STBCR_SLCDST;201		hitfb_writew(v, HD64461_STBCR);202	} else {203		v = hitfb_readw(HD64461_STBCR);204		v &= ~HD64461_STBCR_SLCDST;205		hitfb_writew(v, HD64461_STBCR);206 207		v = hitfb_readw(HD64461_LCDCCR);208		v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ);209		hitfb_writew(v, HD64461_LCDCCR);210 211		do {212		    v = hitfb_readw(HD64461_LCDCCR);213		} while(v&HD64461_LCDCCR_STBACK);214 215		v = hitfb_readw(HD64461_LDR1);216		v |= HD64461_LDR1_DON;217		hitfb_writew(v, HD64461_LDR1);218	}219	return 0;220}221 222static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,223			   unsigned blue, unsigned transp, struct fb_info *info)224{225	if (regno >= 256)226		return 1;227 228	switch (info->var.bits_per_pixel) {229	case 8:230		hitfb_writew(regno << 8, HD64461_CPTWAR);231		hitfb_writew(red >> 10, HD64461_CPTWDR);232		hitfb_writew(green >> 10, HD64461_CPTWDR);233		hitfb_writew(blue >> 10, HD64461_CPTWDR);234		break;235	case 16:236		if (regno >= 16)237			return 1;238		((u32 *) (info->pseudo_palette))[regno] =239		    ((red & 0xf800)) |240		    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);241		break;242	}243	return 0;244}245 246static int hitfb_sync(struct fb_info *info)247{248	hitfb_accel_wait();249 250	return 0;251}252 253static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)254{255	int maxy;256 257	var->xres = info->var.xres;258	var->xres_virtual = info->var.xres;259	var->yres = info->var.yres;260 261	if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16))262		var->bits_per_pixel = info->var.bits_per_pixel;263 264	if (var->yres_virtual < var->yres)265		var->yres_virtual = var->yres;266 267	maxy = info->fix.smem_len / var->xres;268 269	if (var->bits_per_pixel == 16)270		maxy /= 2;271 272	if (var->yres_virtual > maxy)273		var->yres_virtual = maxy;274 275	var->xoffset = 0;276	var->yoffset = 0;277 278	switch (var->bits_per_pixel) {279	case 8:280		var->red.offset = 0;281		var->red.length = 8;282		var->green.offset = 0;283		var->green.length = 8;284		var->blue.offset = 0;285		var->blue.length = 8;286		var->transp.offset = 0;287		var->transp.length = 0;288		break;289	case 16:		/* RGB 565 */290		var->red.offset = 11;291		var->red.length = 5;292		var->green.offset = 5;293		var->green.length = 6;294		var->blue.offset = 0;295		var->blue.length = 5;296		var->transp.offset = 0;297		var->transp.length = 0;298		break;299	}300 301	return 0;302}303 304static int hitfb_set_par(struct fb_info *info)305{306	unsigned short ldr3;307 308	switch (info->var.bits_per_pixel) {309	case 8:310		info->fix.line_length = info->var.xres;311		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;312		info->fix.ypanstep = 16;313		break;314	case 16:315		info->fix.line_length = info->var.xres*2;316		info->fix.visual = FB_VISUAL_TRUECOLOR;317		info->fix.ypanstep = 8;318		break;319	}320 321	hitfb_writew(info->fix.line_length, HD64461_LCDCLOR);322	ldr3 = hitfb_readw(HD64461_LDR3);323	ldr3 &= ~15;324	ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8;325	hitfb_writew(ldr3, HD64461_LDR3);326	return 0;327}328 329static const struct fb_ops hitfb_ops = {330	.owner		= THIS_MODULE,331	__FB_DEFAULT_IOMEM_OPS_RDWR,332	.fb_check_var	= hitfb_check_var,333	.fb_set_par	= hitfb_set_par,334	.fb_setcolreg	= hitfb_setcolreg,335	.fb_blank	= hitfb_blank,336	.fb_sync	= hitfb_sync,337	.fb_pan_display = hitfb_pan_display,338	.fb_fillrect	= hitfb_fillrect,339	.fb_copyarea	= hitfb_copyarea,340	.fb_imageblit	= cfb_imageblit,341	__FB_DEFAULT_IOMEM_OPS_MMAP,342};343 344static int hitfb_probe(struct platform_device *dev)345{346	unsigned short lcdclor, ldr3, ldvndr;347	struct fb_info *info;348	int ret;349 350	if (fb_get_options("hitfb", NULL))351		return -ENODEV;352 353	hitfb_fix.mmio_start = HD64461_IO_OFFSET(0x1000);354	hitfb_fix.mmio_len = 0x1000;355	hitfb_fix.smem_start = HD64461_IO_OFFSET(0x02000000);356	hitfb_fix.smem_len = 512 * 1024;357 358	lcdclor = hitfb_readw(HD64461_LCDCLOR);359	ldvndr = hitfb_readw(HD64461_LDVNDR);360	ldr3 = hitfb_readw(HD64461_LDR3);361 362	switch (ldr3 & 15) {363	default:364	case 4:365		hitfb_var.bits_per_pixel = 8;366		hitfb_var.xres = lcdclor;367		break;368	case 8:369		hitfb_var.bits_per_pixel = 16;370		hitfb_var.xres = lcdclor / 2;371		break;372	}373	hitfb_fix.line_length = lcdclor;374	hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ?375	    FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;376	hitfb_var.yres = ldvndr + 1;377	hitfb_var.xres_virtual = hitfb_var.xres;378	hitfb_var.yres_virtual = hitfb_fix.smem_len / lcdclor;379	switch (hitfb_var.bits_per_pixel) {380	case 8:381		hitfb_var.red.offset = 0;382		hitfb_var.red.length = 8;383		hitfb_var.green.offset = 0;384		hitfb_var.green.length = 8;385		hitfb_var.blue.offset = 0;386		hitfb_var.blue.length = 8;387		hitfb_var.transp.offset = 0;388		hitfb_var.transp.length = 0;389		break;390	case 16:		/* RGB 565 */391		hitfb_var.red.offset = 11;392		hitfb_var.red.length = 5;393		hitfb_var.green.offset = 5;394		hitfb_var.green.length = 6;395		hitfb_var.blue.offset = 0;396		hitfb_var.blue.length = 5;397		hitfb_var.transp.offset = 0;398		hitfb_var.transp.length = 0;399		break;400	}401 402	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);403	if (unlikely(!info))404		return -ENOMEM;405 406	info->fbops = &hitfb_ops;407	info->var = hitfb_var;408	info->fix = hitfb_fix;409	info->pseudo_palette = info->par;410	info->flags = FBINFO_HWACCEL_YPAN |411		FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;412 413	info->screen_base = (char __iomem *)(uintptr_t)hitfb_fix.smem_start;414 415	ret = fb_alloc_cmap(&info->cmap, 256, 0);416	if (unlikely(ret < 0))417		goto err_fb;418 419	ret = register_framebuffer(info);420	if (unlikely(ret < 0))421		goto err;422 423	platform_set_drvdata(dev, info);424 425	fb_info(info, "%s frame buffer device\n", info->fix.id);426 427	return 0;428 429err:430	fb_dealloc_cmap(&info->cmap);431err_fb:432	framebuffer_release(info);433	return ret;434}435 436static void hitfb_remove(struct platform_device *dev)437{438	struct fb_info *info = platform_get_drvdata(dev);439 440	unregister_framebuffer(info);441	fb_dealloc_cmap(&info->cmap);442	framebuffer_release(info);443}444 445static int hitfb_suspend(struct device *dev)446{447	u16 v;448 449	hitfb_blank(1, NULL);450	v = hitfb_readw(HD64461_STBCR);451	v |= HD64461_STBCR_SLCKE_IST;452	hitfb_writew(v, HD64461_STBCR);453 454	return 0;455}456 457static int hitfb_resume(struct device *dev)458{459	u16 v;460 461	v = hitfb_readw(HD64461_STBCR);462	v &= ~HD64461_STBCR_SLCKE_OST;463	msleep(100);464	v = hitfb_readw(HD64461_STBCR);465	v &= ~HD64461_STBCR_SLCKE_IST;466	hitfb_writew(v, HD64461_STBCR);467	hitfb_blank(0, NULL);468 469	return 0;470}471 472static const struct dev_pm_ops hitfb_dev_pm_ops = {473	.suspend	= hitfb_suspend,474	.resume		= hitfb_resume,475};476 477static struct platform_driver hitfb_driver = {478	.probe		= hitfb_probe,479	.remove		= hitfb_remove,480	.driver		= {481		.name	= "hitfb",482		.pm	= &hitfb_dev_pm_ops,483	},484};485 486static struct platform_device hitfb_device = {487	.name	= "hitfb",488	.id	= -1,489};490 491static int __init hitfb_init(void)492{493	int ret;494 495	ret = platform_driver_register(&hitfb_driver);496	if (!ret) {497		ret = platform_device_register(&hitfb_device);498		if (ret)499			platform_driver_unregister(&hitfb_driver);500	}501	return ret;502}503 504 505static void __exit hitfb_exit(void)506{507	platform_device_unregister(&hitfb_device);508	platform_driver_unregister(&hitfb_driver);509}510 511module_init(hitfb_init);512module_exit(hitfb_exit);513 514MODULE_LICENSE("GPL");515