PageRenderTime 119ms CodeModel.GetById 12ms app.highlight 83ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/video/mbx/mbxfb.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 1071 lines | 802 code | 182 blank | 87 comment | 77 complexity | 70f1f1784b2a801022f30e81debc0315 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
   1/*
   2 *  linux/drivers/video/mbx/mbxfb.c
   3 *
   4 *  Copyright (C) 2006-2007 8D Technologies inc
   5 *  Raphael Assenat <raph@8d.com>
   6 *  	- Added video overlay support
   7 *  	- Various improvements
   8 *
   9 *  Copyright (C) 2006 Compulab, Ltd.
  10 *  Mike Rapoport <mike@compulab.co.il>
  11 *  	- Creation of driver
  12 *
  13 *   Based on pxafb.c
  14 *
  15 * This file is subject to the terms and conditions of the GNU General Public
  16 * License.  See the file COPYING in the main directory of this archive for
  17 * more details.
  18 *
  19 *   Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
  20 *
  21 */
  22
  23#include <linux/delay.h>
  24#include <linux/fb.h>
  25#include <linux/init.h>
  26#include <linux/module.h>
  27#include <linux/platform_device.h>
  28#include <linux/uaccess.h>
  29
  30#include <asm/io.h>
  31
  32#include <video/mbxfb.h>
  33
  34#include "regs.h"
  35#include "reg_bits.h"
  36
  37static unsigned long virt_base_2700;
  38
  39#define write_reg(val, reg) do { writel((val), (reg)); } while(0)
  40
  41/* Without this delay, the graphics appears somehow scaled and
  42 * there is a lot of jitter in scanlines. This delay is probably
  43 * needed only after setting some specific register(s) somewhere,
  44 * not all over the place... */
  45#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
  46
  47#define MIN_XRES	16
  48#define MIN_YRES	16
  49#define MAX_XRES	2048
  50#define MAX_YRES	2048
  51
  52#define MAX_PALETTES	16
  53
  54/* FIXME: take care of different chip revisions with different sizes
  55   of ODFB */
  56#define MEMORY_OFFSET	0x60000
  57
  58struct mbxfb_info {
  59	struct device *dev;
  60
  61	struct resource *fb_res;
  62	struct resource *fb_req;
  63
  64	struct resource *reg_res;
  65	struct resource *reg_req;
  66
  67	void __iomem *fb_virt_addr;
  68	unsigned long fb_phys_addr;
  69
  70	void __iomem *reg_virt_addr;
  71	unsigned long reg_phys_addr;
  72
  73	int (*platform_probe) (struct fb_info * fb);
  74	int (*platform_remove) (struct fb_info * fb);
  75
  76	u32 pseudo_palette[MAX_PALETTES];
  77#ifdef CONFIG_FB_MBX_DEBUG
  78	void *debugfs_data;
  79#endif
  80
  81};
  82
  83static struct fb_var_screeninfo mbxfb_default __devinitdata = {
  84	.xres = 640,
  85	.yres = 480,
  86	.xres_virtual = 640,
  87	.yres_virtual = 480,
  88	.bits_per_pixel = 16,
  89	.red = {11, 5, 0},
  90	.green = {5, 6, 0},
  91	.blue = {0, 5, 0},
  92	.activate = FB_ACTIVATE_TEST,
  93	.height = -1,
  94	.width = -1,
  95	.pixclock = 40000,
  96	.left_margin = 48,
  97	.right_margin = 16,
  98	.upper_margin = 33,
  99	.lower_margin = 10,
 100	.hsync_len = 96,
 101	.vsync_len = 2,
 102	.vmode = FB_VMODE_NONINTERLACED,
 103	.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 104};
 105
 106static struct fb_fix_screeninfo mbxfb_fix  __devinitdata = {
 107	.id = "MBX",
 108	.type = FB_TYPE_PACKED_PIXELS,
 109	.visual = FB_VISUAL_TRUECOLOR,
 110	.xpanstep = 0,
 111	.ypanstep = 0,
 112	.ywrapstep = 0,
 113	.accel = FB_ACCEL_NONE,
 114};
 115
 116struct pixclock_div {
 117	u8 m;
 118	u8 n;
 119	u8 p;
 120};
 121
 122static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
 123				       struct pixclock_div *div)
 124{
 125	u8 m, n, p;
 126	unsigned int err = 0;
 127	unsigned int min_err = ~0x0;
 128	unsigned int clk;
 129	unsigned int best_clk = 0;
 130	unsigned int ref_clk = 13000;	/* FIXME: take from platform data */
 131	unsigned int pixclock;
 132
 133	/* convert pixclock to KHz */
 134	pixclock = PICOS2KHZ(pixclock_ps);
 135
 136	/* PLL output freq = (ref_clk * M) / (N * 2^P)
 137	 *
 138	 * M: 1 to 63
 139	 * N: 1 to 7
 140	 * P: 0 to 7
 141	 */
 142
 143	/* RAPH: When N==1, the resulting pixel clock appears to
 144	 * get divided by 2. Preventing N=1 by starting the following
 145	 * loop at 2 prevents this. Is this a bug with my chip
 146	 * revision or something I dont understand? */
 147	for (m = 1; m < 64; m++) {
 148		for (n = 2; n < 8; n++) {
 149			for (p = 0; p < 8; p++) {
 150				clk = (ref_clk * m) / (n * (1 << p));
 151				err = (clk > pixclock) ? (clk - pixclock) :
 152					(pixclock - clk);
 153				if (err < min_err) {
 154					min_err = err;
 155					best_clk = clk;
 156					div->m = m;
 157					div->n = n;
 158					div->p = p;
 159				}
 160			}
 161		}
 162	}
 163	return KHZ2PICOS(best_clk);
 164}
 165
 166static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 167			   u_int trans, struct fb_info *info)
 168{
 169	u32 val, ret = 1;
 170
 171	if (regno < MAX_PALETTES) {
 172		u32 *pal = info->pseudo_palette;
 173
 174		val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
 175			((blue & 0xf800) >> 11);
 176		pal[regno] = val;
 177		ret = 0;
 178	}
 179
 180	return ret;
 181}
 182
 183static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 184{
 185	struct pixclock_div div;
 186
 187	var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
 188
 189	if (var->xres < MIN_XRES)
 190		var->xres = MIN_XRES;
 191	if (var->yres < MIN_YRES)
 192		var->yres = MIN_YRES;
 193	if (var->xres > MAX_XRES)
 194		return -EINVAL;
 195	if (var->yres > MAX_YRES)
 196		return -EINVAL;
 197	var->xres_virtual = max(var->xres_virtual, var->xres);
 198	var->yres_virtual = max(var->yres_virtual, var->yres);
 199
 200	switch (var->bits_per_pixel) {
 201		/* 8 bits-per-pixel is not supported yet */
 202	case 8:
 203		return -EINVAL;
 204	case 16:
 205		var->green.length = (var->green.length == 5) ? 5 : 6;
 206		var->red.length = 5;
 207		var->blue.length = 5;
 208		var->transp.length = 6 - var->green.length;
 209		var->blue.offset = 0;
 210		var->green.offset = 5;
 211		var->red.offset = 5 + var->green.length;
 212		var->transp.offset = (5 + var->red.offset) & 15;
 213		break;
 214	case 24:		/* RGB 888   */
 215	case 32:		/* RGBA 8888 */
 216		var->red.offset = 16;
 217		var->red.length = 8;
 218		var->green.offset = 8;
 219		var->green.length = 8;
 220		var->blue.offset = 0;
 221		var->blue.length = 8;
 222		var->transp.length = var->bits_per_pixel - 24;
 223		var->transp.offset = (var->transp.length) ? 24 : 0;
 224		break;
 225	}
 226	var->red.msb_right = 0;
 227	var->green.msb_right = 0;
 228	var->blue.msb_right = 0;
 229	var->transp.msb_right = 0;
 230
 231	return 0;
 232}
 233
 234static int mbxfb_set_par(struct fb_info *info)
 235{
 236	struct fb_var_screeninfo *var = &info->var;
 237	struct pixclock_div div;
 238	ushort hbps, ht, hfps, has;
 239	ushort vbps, vt, vfps, vas;
 240	u32 gsctrl = readl(GSCTRL);
 241	u32 gsadr = readl(GSADR);
 242
 243	info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
 244
 245	/* setup color mode */
 246	gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
 247	/* FIXME: add *WORKING* support for 8-bits per color */
 248	if (info->var.bits_per_pixel == 8) {
 249		return -EINVAL;
 250	} else {
 251		fb_dealloc_cmap(&info->cmap);
 252		gsctrl &= ~GSCTRL_LUT_EN;
 253
 254		info->fix.visual = FB_VISUAL_TRUECOLOR;
 255		switch (info->var.bits_per_pixel) {
 256		case 16:
 257			if (info->var.green.length == 5)
 258				gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
 259			else
 260				gsctrl |= GSCTRL_GPIXFMT_RGB565;
 261			break;
 262		case 24:
 263			gsctrl |= GSCTRL_GPIXFMT_RGB888;
 264			break;
 265		case 32:
 266			gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
 267			break;
 268		}
 269	}
 270
 271	/* setup resolution */
 272	gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
 273	gsctrl |= Gsctrl_Width(info->var.xres) |
 274		Gsctrl_Height(info->var.yres);
 275	write_reg_dly(gsctrl, GSCTRL);
 276
 277	gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
 278	gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
 279				 (8 * 16) - 1);
 280	write_reg_dly(gsadr, GSADR);
 281
 282	/* setup timings */
 283	var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
 284
 285	write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
 286		Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
 287
 288	hbps = var->hsync_len;
 289	has = hbps + var->left_margin;
 290	hfps = has + var->xres;
 291	ht = hfps + var->right_margin;
 292
 293	vbps = var->vsync_len;
 294	vas = vbps + var->upper_margin;
 295	vfps = vas + var->yres;
 296	vt = vfps + var->lower_margin;
 297
 298	write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
 299	write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
 300	write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
 301	write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
 302
 303	write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
 304	write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
 305	write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
 306	write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
 307	write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
 308
 309	write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 310
 311	write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
 312
 313	return 0;
 314}
 315
 316static int mbxfb_blank(int blank, struct fb_info *info)
 317{
 318	switch (blank) {
 319	case FB_BLANK_POWERDOWN:
 320	case FB_BLANK_VSYNC_SUSPEND:
 321	case FB_BLANK_HSYNC_SUSPEND:
 322	case FB_BLANK_NORMAL:
 323		write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
 324		write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
 325		write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
 326		break;
 327	case FB_BLANK_UNBLANK:
 328		write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 329		write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
 330		break;
 331	}
 332	return 0;
 333}
 334
 335static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
 336{
 337	u32 vsctrl, vscadr, vsadr;
 338	u32 sssize, spoctrl, shctrl;
 339	u32 vubase, vvbase;
 340	u32 vovrclk;
 341
 342	if (set->scaled_width==0 || set->scaled_height==0)
 343		return -EINVAL;
 344
 345	/* read registers which have reserved bits
 346	 * so we can write them back as-is. */
 347	vovrclk = readl(VOVRCLK);
 348	vsctrl = readl(VSCTRL);
 349	vscadr = readl(VSCADR);
 350	vubase = readl(VUBASE);
 351	vvbase = readl(VVBASE);
 352	shctrl = readl(SHCTRL);
 353
 354	spoctrl = readl(SPOCTRL);
 355	sssize = readl(SSSIZE);
 356
 357	vsctrl &= ~(	FMsk(VSCTRL_VSWIDTH) |
 358					FMsk(VSCTRL_VSHEIGHT) |
 359					FMsk(VSCTRL_VPIXFMT) |
 360					VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
 361					VSCTRL_COSITED );
 362	vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
 363				VSCTRL_CSC_EN;
 364
 365	vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) );
 366	vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
 367	vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
 368
 369	switch (set->fmt) {
 370	case MBXFB_FMT_YUV16:
 371		vsctrl |= VSCTRL_VPIXFMT_YUV12;
 372
 373		set->Y_stride = ((set->width) + 0xf ) & ~0xf;
 374		break;
 375	case MBXFB_FMT_YUV12:
 376		vsctrl |= VSCTRL_VPIXFMT_YUV12;
 377
 378		set->Y_stride = ((set->width) + 0xf ) & ~0xf;
 379		vubase |= VUBASE_UVHALFSTR;
 380
 381		break;
 382	case MBXFB_FMT_UY0VY1:
 383		vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
 384		set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 385		break;
 386	case MBXFB_FMT_VY0UY1:
 387		vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
 388		set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 389		break;
 390	case MBXFB_FMT_Y0UY1V:
 391		vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
 392		set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 393		break;
 394	case MBXFB_FMT_Y0VY1U:
 395		vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
 396		set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
 397			break;
 398	default:
 399		return -EINVAL;
 400	}
 401
 402	/* VSCTRL has the bits which sets the Video Pixel Format.
 403	 * When passing from a packed to planar format,
 404	 * if we write VSCTRL first, VVBASE and VUBASE would
 405	 * be zero if we would not set them here. (And then,
 406	 * the chips hangs and only a reset seems to fix it).
 407	 *
 408	 * If course, the values calculated here have no meaning
 409	 * for packed formats.
 410	 */
 411	set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
 412		set->U_offset = set->height * set->Y_stride;
 413		set->V_offset = set->U_offset +
 414						set->height * set->UV_stride;
 415	vubase |= Vubase_Ubase_Adr(
 416			(0x60000 + set->mem_offset + set->U_offset)>>3);
 417	vvbase |= Vvbase_Vbase_Adr(
 418			(0x60000 + set->mem_offset + set->V_offset)>>3);
 419
 420
 421	vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
 422
 423	if (set->enable)
 424		vscadr |= VSCADR_STR_EN;
 425
 426
 427	vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
 428		Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
 429
 430	sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
 431	sssize = Sssize_Sc_Width(set->scaled_width-1) |
 432			Sssize_Sc_Height(set->scaled_height-1);
 433
 434	spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
 435			SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
 436			FMsk(SPOCTRL_VPITCH));
 437	spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height);
 438
 439	/* Bypass horiz/vert scaler when same size */
 440	if (set->scaled_width == set->width)
 441		spoctrl |= SPOCTRL_H_SC_BP;
 442	if (set->scaled_height == set->height)
 443		spoctrl |= SPOCTRL_V_SC_BP;
 444
 445	shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM);
 446	shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width);
 447
 448	/* Video plane registers */
 449	write_reg(vsctrl, VSCTRL);
 450	write_reg(vscadr, VSCADR);
 451	write_reg(vubase, VUBASE);
 452	write_reg(vvbase, VVBASE);
 453	write_reg(vsadr, VSADR);
 454
 455	/* Video scaler registers */
 456	write_reg(sssize, SSSIZE);
 457	write_reg(spoctrl, SPOCTRL);
 458	write_reg(shctrl, SHCTRL);
 459
 460	/* Clock */
 461	if (set->enable)
 462		vovrclk |= 1;
 463	else
 464		vovrclk &= ~1;
 465
 466	write_reg(vovrclk, VOVRCLK);
 467
 468	return 0;
 469}
 470
 471static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder)
 472{
 473	unsigned long gscadr, vscadr;
 474
 475	if (porder->bottom == porder->top)
 476		return -EINVAL;
 477
 478	gscadr = readl(GSCADR);
 479	vscadr = readl(VSCADR);
 480
 481	gscadr &= ~(FMsk(GSCADR_BLEND_POS));
 482	vscadr &= ~(FMsk(VSCADR_BLEND_POS));
 483
 484	switch (porder->bottom) {
 485	case MBXFB_PLANE_GRAPHICS:
 486		gscadr |= GSCADR_BLEND_GFX;
 487		break;
 488	case MBXFB_PLANE_VIDEO:
 489		vscadr |= VSCADR_BLEND_GFX;
 490		break;
 491	default:
 492		return -EINVAL;
 493	}
 494
 495	switch (porder->top) {
 496	case MBXFB_PLANE_GRAPHICS:
 497		gscadr |= GSCADR_BLEND_VID;
 498		break;
 499	case MBXFB_PLANE_VIDEO:
 500		vscadr |= GSCADR_BLEND_VID;
 501		break;
 502	default:
 503		return -EINVAL;
 504	}
 505
 506	write_reg_dly(vscadr, VSCADR);
 507	write_reg_dly(gscadr, GSCADR);
 508
 509	return 0;
 510
 511}
 512
 513static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha)
 514{
 515	unsigned long vscadr, vbbase, vcmsk;
 516	unsigned long gscadr, gbbase, gdrctrl;
 517
 518	vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) |
 519				Vbbase_Colkey(alpha->overlay_colorkey);
 520
 521	gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) |
 522				Gbbase_Colkey(alpha->graphics_colorkey);
 523
 524	vcmsk = readl(VCMSK);
 525	vcmsk &= ~(FMsk(VCMSK_COLKEY_M));
 526	vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask);
 527
 528	gdrctrl = readl(GDRCTRL);
 529	gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM));
 530	gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask);
 531
 532	vscadr = readl(VSCADR);
 533	vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN);
 534
 535	gscadr = readl(GSCADR);
 536	gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC);
 537
 538	switch (alpha->overlay_colorkey_mode) {
 539	case MBXFB_COLORKEY_DISABLED:
 540		break;
 541	case MBXFB_COLORKEY_PREVIOUS:
 542		vscadr |= VSCADR_COLKEY_EN;
 543		break;
 544	case MBXFB_COLORKEY_CURRENT:
 545		vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC;
 546		break;
 547	default:
 548		return -EINVAL;
 549	}
 550
 551	switch (alpha->overlay_blend_mode) {
 552	case MBXFB_ALPHABLEND_NONE:
 553		vscadr |= VSCADR_BLEND_NONE;
 554		break;
 555	case MBXFB_ALPHABLEND_GLOBAL:
 556		vscadr |= VSCADR_BLEND_GLOB;
 557		break;
 558	case MBXFB_ALPHABLEND_PIXEL:
 559		vscadr |= VSCADR_BLEND_PIX;
 560		break;
 561	default:
 562		return -EINVAL;
 563	}
 564
 565	switch (alpha->graphics_colorkey_mode) {
 566	case MBXFB_COLORKEY_DISABLED:
 567		break;
 568	case MBXFB_COLORKEY_PREVIOUS:
 569		gscadr |= GSCADR_COLKEY_EN;
 570		break;
 571	case MBXFB_COLORKEY_CURRENT:
 572		gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC;
 573		break;
 574	default:
 575		return -EINVAL;
 576	}
 577
 578	switch (alpha->graphics_blend_mode) {
 579	case MBXFB_ALPHABLEND_NONE:
 580		gscadr |= GSCADR_BLEND_NONE;
 581		break;
 582	case MBXFB_ALPHABLEND_GLOBAL:
 583		gscadr |= GSCADR_BLEND_GLOB;
 584		break;
 585	case MBXFB_ALPHABLEND_PIXEL:
 586		gscadr |= GSCADR_BLEND_PIX;
 587		break;
 588	default:
 589		return -EINVAL;
 590	}
 591
 592	write_reg_dly(vbbase, VBBASE);
 593	write_reg_dly(gbbase, GBBASE);
 594	write_reg_dly(vcmsk, VCMSK);
 595	write_reg_dly(gdrctrl, GDRCTRL);
 596	write_reg_dly(gscadr, GSCADR);
 597	write_reg_dly(vscadr, VSCADR);
 598
 599	return 0;
 600}
 601
 602static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
 603				unsigned long arg)
 604{
 605	struct mbxfb_overlaySetup	setup;
 606	struct mbxfb_planeorder 	porder;
 607	struct mbxfb_alphaCtl 		alpha;
 608	struct mbxfb_reg			reg;
 609	int res;
 610	__u32 tmp;
 611
 612	switch (cmd)
 613	{
 614		case MBXFB_IOCX_OVERLAY:
 615			if (copy_from_user(&setup, (void __user*)arg,
 616						sizeof(struct mbxfb_overlaySetup)))
 617				return -EFAULT;
 618
 619			res = mbxfb_setupOverlay(&setup);
 620			if (res)
 621				return res;
 622
 623			if (copy_to_user((void __user*)arg, &setup,
 624						sizeof(struct mbxfb_overlaySetup)))
 625				return -EFAULT;
 626
 627			return 0;
 628
 629		case MBXFB_IOCS_PLANEORDER:
 630			if (copy_from_user(&porder, (void __user*)arg,
 631					sizeof(struct mbxfb_planeorder)))
 632			return -EFAULT;
 633
 634			return mbxfb_ioctl_planeorder(&porder);
 635
 636		case MBXFB_IOCS_ALPHA:
 637			if (copy_from_user(&alpha, (void __user*)arg,
 638					sizeof(struct mbxfb_alphaCtl)))
 639			return -EFAULT;
 640
 641			return mbxfb_ioctl_alphactl(&alpha);
 642
 643		case MBXFB_IOCS_REG:
 644			if (copy_from_user(&reg, (void __user*)arg,
 645						sizeof(struct mbxfb_reg)))
 646				return -EFAULT;
 647
 648			if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */
 649				return -EINVAL;
 650
 651			tmp = readl(virt_base_2700 + reg.addr);
 652			tmp &= ~reg.mask;
 653			tmp |= reg.val & reg.mask;
 654			writel(tmp, virt_base_2700 + reg.addr);
 655
 656			return 0;
 657		case MBXFB_IOCX_REG:
 658			if (copy_from_user(&reg, (void __user*)arg,
 659						sizeof(struct mbxfb_reg)))
 660				return -EFAULT;
 661
 662			if (reg.addr >= 0x10000)	/* regs are from 0x3fe0000 to 0x3feffff */
 663				return -EINVAL;
 664			reg.val = readl(virt_base_2700 + reg.addr);
 665
 666			if (copy_to_user((void __user*)arg, &reg,
 667						sizeof(struct mbxfb_reg)))
 668				return -EFAULT;
 669
 670			return 0;
 671	}
 672	return -EINVAL;
 673}
 674
 675static struct fb_ops mbxfb_ops = {
 676	.owner = THIS_MODULE,
 677	.fb_check_var = mbxfb_check_var,
 678	.fb_set_par = mbxfb_set_par,
 679	.fb_setcolreg = mbxfb_setcolreg,
 680	.fb_fillrect = cfb_fillrect,
 681	.fb_copyarea = cfb_copyarea,
 682	.fb_imageblit = cfb_imageblit,
 683	.fb_blank = mbxfb_blank,
 684	.fb_ioctl = mbxfb_ioctl,
 685};
 686
 687/*
 688  Enable external SDRAM controller. Assume that all clocks are active
 689  by now.
 690*/
 691static void __devinit setup_memc(struct fb_info *fbi)
 692{
 693	unsigned long tmp;
 694	int i;
 695
 696	/* FIXME: use platform specific parameters */
 697	/* setup SDRAM controller */
 698	write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
 699		LMCFG_LMA_TS),
 700	       LMCFG);
 701
 702	write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
 703
 704	/* setup SDRAM timings */
 705	write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
 706		Lmtim_Trc(9) | Lmtim_Tdpl(2)),
 707	       LMTIM);
 708	/* setup SDRAM refresh rate */
 709	write_reg_dly(0xc2b, LMREFRESH);
 710	/* setup SDRAM type parameters */
 711	write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
 712		LMTYPE_COLSZ_8),
 713	       LMTYPE);
 714	/* enable memory controller */
 715	write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
 716	/* perform dummy reads */
 717	for ( i = 0; i < 16; i++ ) {
 718		tmp = readl(fbi->screen_base);
 719	}
 720}
 721
 722static void enable_clocks(struct fb_info *fbi)
 723{
 724	/* enable clocks */
 725	write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
 726	write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
 727	write_reg_dly(0x00000000, CLKSLEEP);
 728
 729	/* PLL output = (Frefclk * M) / (N * 2^P )
 730	 *
 731	 * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
 732	 * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
 733	 * */
 734	write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
 735		CORE_PLL_EN),
 736	       COREPLL);
 737
 738	write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
 739		DISP_PLL_EN),
 740	       DISPPLL);
 741
 742	write_reg_dly(0x00000000, VOVRCLK);
 743	write_reg_dly(PIXCLK_EN, PIXCLK);
 744	write_reg_dly(MEMCLK_EN, MEMCLK);
 745	write_reg_dly(0x00000001, M24CLK);
 746	write_reg_dly(0x00000001, MBXCLK);
 747	write_reg_dly(SDCLK_EN, SDCLK);
 748	write_reg_dly(0x00000001, PIXCLKDIV);
 749}
 750
 751static void __devinit setup_graphics(struct fb_info *fbi)
 752{
 753	unsigned long gsctrl;
 754	unsigned long vscadr;
 755
 756	gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
 757		Gsctrl_Height(fbi->var.yres);
 758	switch (fbi->var.bits_per_pixel) {
 759	case 16:
 760		if (fbi->var.green.length == 5)
 761			gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
 762		else
 763			gsctrl |= GSCTRL_GPIXFMT_RGB565;
 764		break;
 765	case 24:
 766		gsctrl |= GSCTRL_GPIXFMT_RGB888;
 767		break;
 768	case 32:
 769		gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
 770		break;
 771	}
 772
 773	write_reg_dly(gsctrl, GSCTRL);
 774	write_reg_dly(0x00000000, GBBASE);
 775	write_reg_dly(0x00ffffff, GDRCTRL);
 776	write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
 777	write_reg_dly(0x00000000, GPLUT);
 778
 779	vscadr = readl(VSCADR);
 780	vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M));
 781	vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE;
 782	write_reg_dly(vscadr, VSCADR);
 783}
 784
 785static void __devinit setup_display(struct fb_info *fbi)
 786{
 787	unsigned long dsctrl = 0;
 788
 789	dsctrl = DSCTRL_BLNK_POL;
 790	if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
 791		dsctrl |= DSCTRL_HS_POL;
 792	if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
 793		dsctrl |= DSCTRL_VS_POL;
 794	write_reg_dly(dsctrl, DSCTRL);
 795	write_reg_dly(0xd0303010, DMCTRL);
 796	write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 797}
 798
 799static void __devinit enable_controller(struct fb_info *fbi)
 800{
 801	u32 svctrl, shctrl;
 802
 803	write_reg_dly(SYSRST_RST, SYSRST);
 804
 805	/* setup a timeout, raise drive strength */
 806	write_reg_dly(0xffffff0c, SYSCFG);
 807
 808	enable_clocks(fbi);
 809	setup_memc(fbi);
 810	setup_graphics(fbi);
 811	setup_display(fbi);
 812
 813	shctrl = readl(SHCTRL);
 814	shctrl &= ~(FMsk(SHCTRL_HINITIAL));
 815	shctrl |= Shctrl_Hinitial(4<<11);
 816	writel(shctrl, SHCTRL);
 817
 818	svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
 819	writel(svctrl, SVCTRL);
 820
 821	writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP
 822			, SPOCTRL);
 823
 824	/* Those coefficients are good for scaling up. For scaling
 825	 * down, the application has to calculate them. */
 826	write_reg(0xff000100, VSCOEFF0);
 827	write_reg(0xfdfcfdfe, VSCOEFF1);
 828	write_reg(0x170d0500, VSCOEFF2);
 829	write_reg(0x3d372d22, VSCOEFF3);
 830	write_reg(0x00000040, VSCOEFF4);
 831
 832	write_reg(0xff010100, HSCOEFF0);
 833	write_reg(0x00000000, HSCOEFF1);
 834	write_reg(0x02010000, HSCOEFF2);
 835	write_reg(0x01020302, HSCOEFF3);
 836	write_reg(0xf9fbfe00, HSCOEFF4);
 837	write_reg(0xfbf7f6f7, HSCOEFF5);
 838	write_reg(0x1c110700, HSCOEFF6);
 839	write_reg(0x3e393127, HSCOEFF7);
 840	write_reg(0x00000040, HSCOEFF8);
 841
 842}
 843
 844#ifdef CONFIG_PM
 845/*
 846 * Power management hooks.  Note that we won't be called from IRQ context,
 847 * unlike the blank functions above, so we may sleep.
 848 */
 849static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
 850{
 851	/* make frame buffer memory enter self-refresh mode */
 852	write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
 853	while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
 854		; /* empty statement */
 855
 856	/* reset the device, since it's initial state is 'mostly sleeping' */
 857	write_reg_dly(SYSRST_RST, SYSRST);
 858	return 0;
 859}
 860
 861static int mbxfb_resume(struct platform_device *dev)
 862{
 863	struct fb_info *fbi = platform_get_drvdata(dev);
 864
 865	enable_clocks(fbi);
 866/* 	setup_graphics(fbi); */
 867/* 	setup_display(fbi); */
 868
 869	write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 870	return 0;
 871}
 872#else
 873#define mbxfb_suspend	NULL
 874#define mbxfb_resume	NULL
 875#endif
 876
 877/* debugfs entries */
 878#ifndef CONFIG_FB_MBX_DEBUG
 879#define mbxfb_debugfs_init(x)	do {} while(0)
 880#define mbxfb_debugfs_remove(x)	do {} while(0)
 881#endif
 882
 883#define res_size(_r) (((_r)->end - (_r)->start) + 1)
 884
 885static int __devinit mbxfb_probe(struct platform_device *dev)
 886{
 887	int ret;
 888	struct fb_info *fbi;
 889	struct mbxfb_info *mfbi;
 890	struct mbxfb_platform_data *pdata;
 891
 892	dev_dbg(&dev->dev, "mbxfb_probe\n");
 893
 894	pdata = dev->dev.platform_data;
 895	if (!pdata) {
 896		dev_err(&dev->dev, "platform data is required\n");
 897		return -EINVAL;
 898	}
 899
 900	fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
 901	if (fbi == NULL) {
 902		dev_err(&dev->dev, "framebuffer_alloc failed\n");
 903		return -ENOMEM;
 904	}
 905
 906	mfbi = fbi->par;
 907	fbi->pseudo_palette = mfbi->pseudo_palette;
 908
 909
 910	if (pdata->probe)
 911		mfbi->platform_probe = pdata->probe;
 912	if (pdata->remove)
 913		mfbi->platform_remove = pdata->remove;
 914
 915	mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 916	mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
 917
 918	if (!mfbi->fb_res || !mfbi->reg_res) {
 919		dev_err(&dev->dev, "no resources found\n");
 920		ret = -ENODEV;
 921		goto err1;
 922	}
 923
 924	mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
 925					  res_size(mfbi->fb_res), dev->name);
 926	if (mfbi->fb_req == NULL) {
 927		dev_err(&dev->dev, "failed to claim framebuffer memory\n");
 928		ret = -EINVAL;
 929		goto err1;
 930	}
 931	mfbi->fb_phys_addr = mfbi->fb_res->start;
 932
 933	mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
 934					   res_size(mfbi->reg_res), dev->name);
 935	if (mfbi->reg_req == NULL) {
 936		dev_err(&dev->dev, "failed to claim Marathon registers\n");
 937		ret = -EINVAL;
 938		goto err2;
 939	}
 940	mfbi->reg_phys_addr = mfbi->reg_res->start;
 941
 942	mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
 943					      res_size(mfbi->reg_req));
 944	if (!mfbi->reg_virt_addr) {
 945		dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
 946		ret = -EINVAL;
 947		goto err3;
 948	}
 949	virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
 950
 951	mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
 952					     res_size(mfbi->fb_req));
 953	if (!mfbi->reg_virt_addr) {
 954		dev_err(&dev->dev, "failed to ioremap frame buffer\n");
 955		ret = -EINVAL;
 956		goto err4;
 957	}
 958
 959	fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
 960	fbi->screen_size = pdata->memsize;
 961	fbi->fbops = &mbxfb_ops;
 962
 963	fbi->var = mbxfb_default;
 964	fbi->fix = mbxfb_fix;
 965	fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
 966	fbi->fix.smem_len = pdata->memsize;
 967	fbi->fix.line_length = mbxfb_default.xres_virtual *
 968					mbxfb_default.bits_per_pixel / 8;
 969
 970	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
 971	if (ret < 0) {
 972		dev_err(&dev->dev, "fb_alloc_cmap failed\n");
 973		ret = -EINVAL;
 974		goto err5;
 975	}
 976
 977	platform_set_drvdata(dev, fbi);
 978
 979	printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
 980
 981	if (mfbi->platform_probe)
 982		mfbi->platform_probe(fbi);
 983
 984	enable_controller(fbi);
 985
 986	mbxfb_debugfs_init(fbi);
 987
 988	ret = register_framebuffer(fbi);
 989	if (ret < 0) {
 990		dev_err(&dev->dev, "register_framebuffer failed\n");
 991		ret = -EINVAL;
 992		goto err6;
 993	}
 994
 995	return 0;
 996
 997err6:
 998	fb_dealloc_cmap(&fbi->cmap);
 999err5:
1000	iounmap(mfbi->fb_virt_addr);
1001err4:
1002	iounmap(mfbi->reg_virt_addr);
1003err3:
1004	release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
1005err2:
1006	release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
1007err1:
1008	framebuffer_release(fbi);
1009
1010	return ret;
1011}
1012
1013static int __devexit mbxfb_remove(struct platform_device *dev)
1014{
1015	struct fb_info *fbi = platform_get_drvdata(dev);
1016
1017	write_reg_dly(SYSRST_RST, SYSRST);
1018
1019	mbxfb_debugfs_remove(fbi);
1020
1021	if (fbi) {
1022		struct mbxfb_info *mfbi = fbi->par;
1023
1024		unregister_framebuffer(fbi);
1025		if (mfbi) {
1026			if (mfbi->platform_remove)
1027				mfbi->platform_remove(fbi);
1028
1029			if (mfbi->fb_virt_addr)
1030				iounmap(mfbi->fb_virt_addr);
1031			if (mfbi->reg_virt_addr)
1032				iounmap(mfbi->reg_virt_addr);
1033			if (mfbi->reg_req)
1034				release_mem_region(mfbi->reg_req->start,
1035						   res_size(mfbi->reg_req));
1036			if (mfbi->fb_req)
1037				release_mem_region(mfbi->fb_req->start,
1038						   res_size(mfbi->fb_req));
1039		}
1040		framebuffer_release(fbi);
1041	}
1042
1043	return 0;
1044}
1045
1046static struct platform_driver mbxfb_driver = {
1047	.probe = mbxfb_probe,
1048	.remove = mbxfb_remove,
1049	.suspend = mbxfb_suspend,
1050	.resume = mbxfb_resume,
1051	.driver = {
1052		.name = "mbx-fb",
1053	},
1054};
1055
1056int __devinit mbxfb_init(void)
1057{
1058	return platform_driver_register(&mbxfb_driver);
1059}
1060
1061static void __devexit mbxfb_exit(void)
1062{
1063	platform_driver_unregister(&mbxfb_driver);
1064}
1065
1066module_init(mbxfb_init);
1067module_exit(mbxfb_exit);
1068
1069MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
1070MODULE_AUTHOR("Mike Rapoport, Compulab");
1071MODULE_LICENSE("GPL");