1/*
2 *  linux/drivers/video/mbx/mbxfb.c
3 *
4 *  Copyright (C) 2006 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#define MEMORY_OFFSET	0x60000
55
56struct mbxfb_info {
57	struct device *dev;
58
59	struct resource *fb_res;
60	struct resource *fb_req;
61
62	struct resource *reg_res;
63	struct resource *reg_req;
64
65	void __iomem *fb_virt_addr;
66	unsigned long fb_phys_addr;
67
68	void __iomem *reg_virt_addr;
69	unsigned long reg_phys_addr;
70
71	int (*platform_probe) (struct fb_info * fb);
72	int (*platform_remove) (struct fb_info * fb);
73
74	u32 pseudo_palette[MAX_PALETTES];
75#ifdef CONFIG_FB_MBX_DEBUG
76	void *debugfs_data;
77#endif
78
79};
80
81static struct fb_var_screeninfo mbxfb_default __devinitdata = {
82	.xres = 640,
83	.yres = 480,
84	.xres_virtual = 640,
85	.yres_virtual = 480,
86	.bits_per_pixel = 16,
87	.red = {11, 5, 0},
88	.green = {5, 6, 0},
89	.blue = {0, 5, 0},
90	.activate = FB_ACTIVATE_TEST,
91	.height = -1,
92	.width = -1,
93	.pixclock = 40000,
94	.left_margin = 48,
95	.right_margin = 16,
96	.upper_margin = 33,
97	.lower_margin = 10,
98	.hsync_len = 96,
99	.vsync_len = 2,
100	.vmode = FB_VMODE_NONINTERLACED,
101	.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
102};
103
104static struct fb_fix_screeninfo mbxfb_fix  __devinitdata = {
105	.id = "MBX",
106	.type = FB_TYPE_PACKED_PIXELS,
107	.visual = FB_VISUAL_TRUECOLOR,
108	.xpanstep = 0,
109	.ypanstep = 0,
110	.ywrapstep = 0,
111	.accel = FB_ACCEL_NONE,
112};
113
114struct pixclock_div {
115	u8 m;
116	u8 n;
117	u8 p;
118};
119
120static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
121				       struct pixclock_div *div)
122{
123	u8 m, n, p;
124	unsigned int err = 0;
125	unsigned int min_err = ~0x0;
126	unsigned int clk;
127	unsigned int best_clk = 0;
128	unsigned int ref_clk = 13000;
129	unsigned int pixclock;
130
131	/* convert pixclock to KHz */
132	pixclock = PICOS2KHZ(pixclock_ps);
133
134	/* PLL output freq = (ref_clk * M) / (N * 2^P)
135	 *
136	 * M: 1 to 63
137	 * N: 1 to 7
138	 * P: 0 to 7
139	 */
140
141	/* RAPH: When N==1, the resulting pixel clock appears to
142	 * get divided by 2. Preventing N=1 by starting the following
143	 * loop at 2 prevents this. Is this a bug with my chip
144	 * revision or something I dont understand? */
145	for (m = 1; m < 64; m++) {
146		for (n = 2; n < 8; n++) {
147			for (p = 0; p < 8; p++) {
148				clk = (ref_clk * m) / (n * (1 << p));
149				err = (clk > pixclock) ? (clk - pixclock) :
150					(pixclock - clk);
151				if (err < min_err) {
152					min_err = err;
153					best_clk = clk;
154					div->m = m;
155					div->n = n;
156					div->p = p;
157				}
158			}
159		}
160	}
161	return KHZ2PICOS(best_clk);
162}
163
164static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
165			   u_int trans, struct fb_info *info)
166{
167	u32 val, ret = 1;
168
169	if (regno < MAX_PALETTES) {
170		u32 *pal = info->pseudo_palette;
171
172		val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
173			((blue & 0xf800) >> 11);
174		pal[regno] = val;
175		ret = 0;
176	}
177
178	return ret;
179}
180
181static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
182{
183	struct pixclock_div div;
184
185	var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
186
187	if (var->xres < MIN_XRES)
188		var->xres = MIN_XRES;
189	if (var->yres < MIN_YRES)
190		var->yres = MIN_YRES;
191	if (var->xres > MAX_XRES)
192		return -EINVAL;
193	if (var->yres > MAX_YRES)
194		return -EINVAL;
195	var->xres_virtual = max(var->xres_virtual, var->xres);
196	var->yres_virtual = max(var->yres_virtual, var->yres);
197
198	switch (var->bits_per_pixel) {
199		/* 8 bits-per-pixel is not supported yet */
200	case 8:
201		return -EINVAL;
202	case 16:
203		var->green.length = (var->green.length == 5) ? 5 : 6;
204		var->red.length = 5;
205		var->blue.length = 5;
206		var->transp.length = 6 - var->green.length;
207		var->blue.offset = 0;
208		var->green.offset = 5;
209		var->red.offset = 5 + var->green.length;
210		var->transp.offset = (5 + var->red.offset) & 15;
211		break;
212	case 24:		/* RGB 888   */
213	case 32:		/* RGBA 8888 */
214		var->red.offset = 16;
215		var->red.length = 8;
216		var->green.offset = 8;
217		var->green.length = 8;
218		var->blue.offset = 0;
219		var->blue.length = 8;
220		var->transp.length = var->bits_per_pixel - 24;
221		var->transp.offset = (var->transp.length) ? 24 : 0;
222		break;
223	}
224	var->red.msb_right = 0;
225	var->green.msb_right = 0;
226	var->blue.msb_right = 0;
227	var->transp.msb_right = 0;
228
229	return 0;
230}
231
232static int mbxfb_set_par(struct fb_info *info)
233{
234	struct fb_var_screeninfo *var = &info->var;
235	struct pixclock_div div;
236	ushort hbps, ht, hfps, has;
237	ushort vbps, vt, vfps, vas;
238	u32 gsctrl = readl(GSCTRL);
239	u32 gsadr = readl(GSADR);
240
241	info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
242
243	/* setup color mode */
244	gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
245	if (info->var.bits_per_pixel == 8) {
246		return -EINVAL;
247	} else {
248		fb_dealloc_cmap(&info->cmap);
249		gsctrl &= ~GSCTRL_LUT_EN;
250
251		info->fix.visual = FB_VISUAL_TRUECOLOR;
252		switch (info->var.bits_per_pixel) {
253		case 16:
254			if (info->var.green.length == 5)
255				gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
256			else
257				gsctrl |= GSCTRL_GPIXFMT_RGB565;
258			break;
259		case 24:
260			gsctrl |= GSCTRL_GPIXFMT_RGB888;
261			break;
262		case 32:
263			gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
264			break;
265		}
266	}
267
268	/* setup resolution */
269	gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
270	gsctrl |= Gsctrl_Width(info->var.xres) |
271		Gsctrl_Height(info->var.yres);
272	write_reg_dly(gsctrl, GSCTRL);
273
274	gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
275	gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
276				 (8 * 16) - 1);
277	write_reg_dly(gsadr, GSADR);
278
279	/* setup timings */
280	var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
281
282	write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
283		Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
284
285	hbps = var->hsync_len;
286	has = hbps + var->left_margin;
287	hfps = has + var->xres;
288	ht = hfps + var->right_margin;
289
290	vbps = var->vsync_len;
291	vas = vbps + var->upper_margin;
292	vfps = vas + var->yres;
293	vt = vfps + var->lower_margin;
294
295	write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
296	write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
297	write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
298	write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
299
300	write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
301	write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
302	write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
303	write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
304	write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
305
306	write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
307
308	write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
309
310	return 0;
311}
312
313static int mbxfb_blank(int blank, struct fb_info *info)
314{
315	switch (blank) {
316	case FB_BLANK_POWERDOWN:
317	case FB_BLANK_VSYNC_SUSPEND:
318	case FB_BLANK_HSYNC_SUSPEND:
319	case FB_BLANK_NORMAL:
320		write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
321		write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
322		write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
323		break;
324	case FB_BLANK_UNBLANK:
325		write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
326		write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
327		break;
328	}
329	return 0;
330}
331
332static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
333{
334	u32 vsctrl, vbbase, vscadr, vsadr;
335	u32 sssize, spoctrl, svctrl, shctrl;
336	u32 vubase, vvbase;
337	u32 vovrclk;
338
339	if (set->scaled_width==0 || set->scaled_height==0)
340		return -EINVAL;
341
342	/* read registers which have reserved bits
343	 * so we can write them back as-is. */
344	vovrclk = readl(VOVRCLK);
345	vsctrl = readl(VSCTRL);
346	vscadr = readl(VSCADR);
347	vubase = readl(VUBASE);
348	vvbase = readl(VVBASE);
349
350	spoctrl = readl(SPOCTRL);
351	sssize = readl(SSSIZE);
352
353
354	vbbase = Vbbase_Glalpha(set->alpha);
355
356	vsctrl &= ~(	FMsk(VSCTRL_VSWIDTH) |
357					FMsk(VSCTRL_VSHEIGHT) |
358					FMsk(VSCTRL_VPIXFMT) |
359					VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
360					VSCTRL_COSITED );
361	vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
362				VSCTRL_CSC_EN;
363
364	vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC |
365				FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) |
366				FMsk(VSCADR_VBASE_ADR) );
367	vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
368	vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
369
370	switch (set->fmt)
371	{
372		case MBXFB_FMT_YUV12:
373			vsctrl |= VSCTRL_VPIXFMT_YUV12;
374
375			set->Y_stride = ((set->width) + 0xf ) & ~0xf;
376
377			break;
378		case MBXFB_FMT_UY0VY1:
379			vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
380			set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
381			break;
382		case MBXFB_FMT_VY0UY1:
383			vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
384			set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
385			break;
386		case MBXFB_FMT_Y0UY1V:
387			vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
388			set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
389			break;
390		case MBXFB_FMT_Y0VY1U:
391			vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
392			set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
393			break;
394		default:
395			return -EINVAL;
396	}
397
398	/* VSCTRL has the bits which sets the Video Pixel Format.
399	 * When passing from a packed to planar format,
400	 * if we write VSCTRL first, VVBASE and VUBASE would
401	 * be zero if we would not set them here. (And then,
402	 * the chips hangs and only a reset seems to fix it).
403	 *
404	 * If course, the values calculated here have no meaning
405	 * for packed formats.
406	 */
407	set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
408		set->U_offset = set->height * set->Y_stride;
409		set->V_offset = set->U_offset +
410						set->height * set->UV_stride;
411	vubase |= Vubase_Ubase_Adr(
412			(0x60000 + set->mem_offset + set->U_offset)>>3);
413	vvbase |= Vvbase_Vbase_Adr(
414			(0x60000 + set->mem_offset + set->V_offset)>>3);
415
416
417	vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB |
418		Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
419
420	if (set->enable)
421		vscadr |= VSCADR_STR_EN;
422
423
424	vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
425		Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
426
427	sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
428	sssize = Sssize_Sc_Width(set->scaled_width-1) |
429			Sssize_Sc_Height(set->scaled_height-1);
430
431	spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
432			SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
433			FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH));
434	spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height)
435							| SPOCTRL_VORDER_2TAP;
436
437	/* Bypass horiz/vert scaler when same size */
438	if (set->scaled_width == set->width)
439		spoctrl |= SPOCTRL_H_SC_BP;
440	if (set->scaled_height == set->height)
441		spoctrl |= SPOCTRL_V_SC_BP;
442
443	svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
444
445	shctrl = Shctrl_Hinitial(4<<11)
446			| Shctrl_Hpitch((set->width<<11)/set->scaled_width);
447
448	/* Video plane registers */
449	write_reg(vsctrl, VSCTRL);
450	write_reg(vbbase, VBBASE);
451	write_reg(vscadr, VSCADR);
452	write_reg(vubase, VUBASE);
453	write_reg(vvbase, VVBASE);
454	write_reg(vsadr, VSADR);
455
456	/* Video scaler registers */
457	write_reg(sssize, SSSIZE);
458	write_reg(spoctrl, SPOCTRL);
459	write_reg(svctrl, SVCTRL);
460	write_reg(shctrl, SHCTRL);
461
462	/* RAPH: Using those coefficients, the scaled
463	 * image is quite blurry. I dont know how
464	 * to improve them ; The chip documentation
465	 * was not helpful.. */
466	write_reg(0x21212121, VSCOEFF0);
467	write_reg(0x21212121, VSCOEFF1);
468	write_reg(0x21212121, VSCOEFF2);
469	write_reg(0x21212121, VSCOEFF3);
470	write_reg(0x21212121, VSCOEFF4);
471	write_reg(0x00000000, HSCOEFF0);
472	write_reg(0x00000000, HSCOEFF1);
473	write_reg(0x00000000, HSCOEFF2);
474	write_reg(0x03020201, HSCOEFF3);
475	write_reg(0x09070604, HSCOEFF4);
476	write_reg(0x0f0e0c0a, HSCOEFF5);
477	write_reg(0x15141211, HSCOEFF6);
478	write_reg(0x19181716, HSCOEFF7);
479	write_reg(0x00000019, HSCOEFF8);
480
481	/* Clock */
482	if (set->enable)
483		vovrclk |= 1;
484	else
485		vovrclk &= ~1;
486
487	write_reg(vovrclk, VOVRCLK);
488
489	return 0;
490}
491
492static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
493				unsigned long arg)
494{
495	struct mbxfb_overlaySetup setup;
496	int res;
497
498	if (cmd == MBXFB_IOCX_OVERLAY)
499	{
500		if (copy_from_user(&setup, (void __user*)arg,
501					sizeof(struct mbxfb_overlaySetup)))
502			return -EFAULT;
503
504		res = mbxfb_setupOverlay(&setup);
505		if (res)
506			return res;
507
508		if (copy_to_user((void __user*)arg, &setup,
509					sizeof(struct mbxfb_overlaySetup)))
510			return -EFAULT;
511
512		return 0;
513	}
514	return -EINVAL;
515}
516
517static struct fb_ops mbxfb_ops = {
518	.owner = THIS_MODULE,
519	.fb_check_var = mbxfb_check_var,
520	.fb_set_par = mbxfb_set_par,
521	.fb_setcolreg = mbxfb_setcolreg,
522	.fb_fillrect = cfb_fillrect,
523	.fb_copyarea = cfb_copyarea,
524	.fb_imageblit = cfb_imageblit,
525	.fb_blank = mbxfb_blank,
526	.fb_ioctl = mbxfb_ioctl,
527};
528
529/*
530  Enable external SDRAM controller. Assume that all clocks are active
531  by now.
532*/
533static void __devinit setup_memc(struct fb_info *fbi)
534{
535	unsigned long tmp;
536	int i;
537
538	/* setup SDRAM controller */
539	write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
540		LMCFG_LMA_TS),
541	       LMCFG);
542
543	write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
544
545	/* setup SDRAM timings */
546	write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
547		Lmtim_Trc(9) | Lmtim_Tdpl(2)),
548	       LMTIM);
549	/* setup SDRAM refresh rate */
550	write_reg_dly(0xc2b, LMREFRESH);
551	/* setup SDRAM type parameters */
552	write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
553		LMTYPE_COLSZ_8),
554	       LMTYPE);
555	/* enable memory controller */
556	write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
557
558	/* perform dummy reads */
559	for ( i = 0; i < 16; i++ ) {
560		tmp = readl(fbi->screen_base);
561	}
562}
563
564static void enable_clocks(struct fb_info *fbi)
565{
566	/* enable clocks */
567	write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
568	write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
569	write_reg_dly(0x00000000, CLKSLEEP);
570
571	/* PLL output = (Frefclk * M) / (N * 2^P )
572	 *
573	 * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
574	 * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
575	 * */
576	write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
577		CORE_PLL_EN),
578	       COREPLL);
579
580	write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
581		DISP_PLL_EN),
582	       DISPPLL);
583
584	write_reg_dly(0x00000000, VOVRCLK);
585	write_reg_dly(PIXCLK_EN, PIXCLK);
586	write_reg_dly(MEMCLK_EN, MEMCLK);
587	write_reg_dly(0x00000006, M24CLK);
588	write_reg_dly(0x00000006, MBXCLK);
589	write_reg_dly(SDCLK_EN, SDCLK);
590	write_reg_dly(0x00000001, PIXCLKDIV);
591}
592
593static void __devinit setup_graphics(struct fb_info *fbi)
594{
595	unsigned long gsctrl;
596
597	gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
598		Gsctrl_Height(fbi->var.yres);
599	switch (fbi->var.bits_per_pixel) {
600	case 16:
601		if (fbi->var.green.length == 5)
602			gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
603		else
604			gsctrl |= GSCTRL_GPIXFMT_RGB565;
605		break;
606	case 24:
607		gsctrl |= GSCTRL_GPIXFMT_RGB888;
608		break;
609	case 32:
610		gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
611		break;
612	}
613
614	write_reg_dly(gsctrl, GSCTRL);
615	write_reg_dly(0x00000000, GBBASE);
616	write_reg_dly(0x00ffffff, GDRCTRL);
617	write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
618	write_reg_dly(0x00000000, GPLUT);
619}
620
621static void __devinit setup_display(struct fb_info *fbi)
622{
623	unsigned long dsctrl = 0;
624
625	dsctrl = DSCTRL_BLNK_POL;
626	if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
627		dsctrl |= DSCTRL_HS_POL;
628	if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
629		dsctrl |= DSCTRL_VS_POL;
630	write_reg_dly(dsctrl, DSCTRL);
631	write_reg_dly(0xd0303010, DMCTRL);
632	write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
633}
634
635static void __devinit enable_controller(struct fb_info *fbi)
636{
637	write_reg_dly(SYSRST_RST, SYSRST);
638
639
640	enable_clocks(fbi);
641	setup_memc(fbi);
642	setup_graphics(fbi);
643	setup_display(fbi);
644}
645
646#ifdef CONFIG_PM
647/*
648 * Power management hooks.  Note that we won't be called from IRQ context,
649 * unlike the blank functions above, so we may sleep.
650 */
651static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
652{
653	/* make frame buffer memory enter self-refresh mode */
654	write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
655	while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
656		; /* empty statement */
657
658	/* reset the device, since it's initial state is 'mostly sleeping' */
659	write_reg_dly(SYSRST_RST, SYSRST);
660	return 0;
661}
662
663static int mbxfb_resume(struct platform_device *dev)
664{
665	struct fb_info *fbi = platform_get_drvdata(dev);
666
667	enable_clocks(fbi);
668/* 	setup_graphics(fbi); */
669/* 	setup_display(fbi); */
670
671	write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
672	return 0;
673}
674#else
675#define mbxfb_suspend	NULL
676#define mbxfb_resume	NULL
677#endif
678
679/* debugfs entries */
680#ifndef CONFIG_FB_MBX_DEBUG
681#define mbxfb_debugfs_init(x)	do {} while(0)
682#define mbxfb_debugfs_remove(x)	do {} while(0)
683#endif
684
685#define res_size(_r) (((_r)->end - (_r)->start) + 1)
686
687static int __devinit mbxfb_probe(struct platform_device *dev)
688{
689	int ret;
690	struct fb_info *fbi;
691	struct mbxfb_info *mfbi;
692	struct mbxfb_platform_data *pdata;
693
694	dev_dbg(dev, "mbxfb_probe\n");
695
696	pdata = dev->dev.platform_data;
697	if (!pdata) {
698		dev_err(&dev->dev, "platform data is required\n");
699		return -EINVAL;
700	}
701
702	fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
703	if (fbi == NULL) {
704		dev_err(&dev->dev, "framebuffer_alloc failed\n");
705		return -ENOMEM;
706	}
707
708	mfbi = fbi->par;
709	fbi->pseudo_palette = mfbi->pseudo_palette;
710
711
712	if (pdata->probe)
713		mfbi->platform_probe = pdata->probe;
714	if (pdata->remove)
715		mfbi->platform_remove = pdata->remove;
716
717	mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
718	mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
719
720	if (!mfbi->fb_res || !mfbi->reg_res) {
721		dev_err(&dev->dev, "no resources found\n");
722		ret = -ENODEV;
723		goto err1;
724	}
725
726	mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
727					  res_size(mfbi->fb_res), dev->name);
728	if (mfbi->fb_req == NULL) {
729		dev_err(&dev->dev, "failed to claim framebuffer memory\n");
730		ret = -EINVAL;
731		goto err1;
732	}
733	mfbi->fb_phys_addr = mfbi->fb_res->start;
734
735	mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
736					   res_size(mfbi->reg_res), dev->name);
737	if (mfbi->reg_req == NULL) {
738		dev_err(&dev->dev, "failed to claim Marathon registers\n");
739		ret = -EINVAL;
740		goto err2;
741	}
742	mfbi->reg_phys_addr = mfbi->reg_res->start;
743
744	mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
745					      res_size(mfbi->reg_req));
746	if (!mfbi->reg_virt_addr) {
747		dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
748		ret = -EINVAL;
749		goto err3;
750	}
751	virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
752
753	mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
754					     res_size(mfbi->fb_req));
755	if (!mfbi->reg_virt_addr) {
756		dev_err(&dev->dev, "failed to ioremap frame buffer\n");
757		ret = -EINVAL;
758		goto err4;
759	}
760
761	fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
762	fbi->screen_size = pdata->memsize;
763	fbi->fbops = &mbxfb_ops;
764
765	fbi->var = mbxfb_default;
766	fbi->fix = mbxfb_fix;
767	fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
768	fbi->fix.smem_len = pdata->memsize;
769	fbi->fix.line_length = mbxfb_default.xres_virtual *
770					mbxfb_default.bits_per_pixel / 8;
771
772	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
773	if (ret < 0) {
774		dev_err(&dev->dev, "fb_alloc_cmap failed\n");
775		ret = -EINVAL;
776		goto err5;
777	}
778
779	platform_set_drvdata(dev, fbi);
780
781	printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
782
783	if (mfbi->platform_probe)
784		mfbi->platform_probe(fbi);
785
786	enable_controller(fbi);
787
788	mbxfb_debugfs_init(fbi);
789
790	ret = register_framebuffer(fbi);
791	if (ret < 0) {
792		dev_err(&dev->dev, "register_framebuffer failed\n");
793		ret = -EINVAL;
794		goto err6;
795	}
796
797	return 0;
798
799err6:
800	fb_dealloc_cmap(&fbi->cmap);
801err5:
802	iounmap(mfbi->fb_virt_addr);
803err4:
804	iounmap(mfbi->reg_virt_addr);
805err3:
806	release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
807err2:
808	release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
809err1:
810	framebuffer_release(fbi);
811
812	return ret;
813}
814
815static int __devexit mbxfb_remove(struct platform_device *dev)
816{
817	struct fb_info *fbi = platform_get_drvdata(dev);
818
819	write_reg_dly(SYSRST_RST, SYSRST);
820
821	mbxfb_debugfs_remove(fbi);
822
823	if (fbi) {
824		struct mbxfb_info *mfbi = fbi->par;
825
826		unregister_framebuffer(fbi);
827		if (mfbi) {
828			if (mfbi->platform_remove)
829				mfbi->platform_remove(fbi);
830
831			if (mfbi->fb_virt_addr)
832				iounmap(mfbi->fb_virt_addr);
833			if (mfbi->reg_virt_addr)
834				iounmap(mfbi->reg_virt_addr);
835			if (mfbi->reg_req)
836				release_mem_region(mfbi->reg_req->start,
837						   res_size(mfbi->reg_req));
838			if (mfbi->fb_req)
839				release_mem_region(mfbi->fb_req->start,
840						   res_size(mfbi->fb_req));
841		}
842		framebuffer_release(fbi);
843	}
844
845	return 0;
846}
847
848static struct platform_driver mbxfb_driver = {
849	.probe = mbxfb_probe,
850	.remove = mbxfb_remove,
851	.suspend = mbxfb_suspend,
852	.resume = mbxfb_resume,
853	.driver = {
854		.name = "mbx-fb",
855	},
856};
857
858int __devinit mbxfb_init(void)
859{
860	return platform_driver_register(&mbxfb_driver);
861}
862
863static void __devexit mbxfb_exit(void)
864{
865	platform_driver_unregister(&mbxfb_driver);
866}
867
868module_init(mbxfb_init);
869module_exit(mbxfb_exit);
870
871MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
872MODULE_AUTHOR("Mike Rapoport, Compulab");
873MODULE_LICENSE("GPL");
874