1/* linux/drivers/video/sm501fb.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 *	Vincent Sanders <vince@simtec.co.uk>
5 *	Ben Dooks <ben@simtec.co.uk>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Framebuffer driver for the Silicon Motion SM501
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/tty.h>
20#include <linux/slab.h>
21#include <linux/delay.h>
22#include <linux/fb.h>
23#include <linux/init.h>
24#include <linux/vmalloc.h>
25#include <linux/dma-mapping.h>
26#include <linux/interrupt.h>
27#include <linux/workqueue.h>
28#include <linux/wait.h>
29#include <linux/platform_device.h>
30#include <linux/clk.h>
31
32#include <asm/io.h>
33#include <asm/uaccess.h>
34#include <asm/div64.h>
35
36#ifdef CONFIG_PM
37#include <linux/pm.h>
38#endif
39
40#include <linux/sm501.h>
41#include <linux/sm501-regs.h>
42
43#define NR_PALETTE	256
44
45enum sm501_controller {
46	HEAD_CRT	= 0,
47	HEAD_PANEL	= 1,
48};
49
50/* SM501 memory adress */
51struct sm501_mem {
52	unsigned long	 size;
53	unsigned long	 sm_addr;
54	void __iomem	*k_addr;
55};
56
57/* private data that is shared between all frambuffers* */
58struct sm501fb_info {
59	struct device		*dev;
60	struct fb_info		*fb[2];		/* fb info for both heads */
61	struct resource		*fbmem_res;	/* framebuffer resource */
62	struct resource		*regs_res;	/* registers resource */
63	struct sm501_platdata_fb *pdata;	/* our platform data */
64
65	int			 irq;
66	int			 swap_endian;	/* set to swap rgb=>bgr */
67	void __iomem		*regs;		/* remapped registers */
68	void __iomem		*fbmem;		/* remapped framebuffer */
69	size_t			 fbmem_len;	/* length of remapped region */
70};
71
72/* per-framebuffer private data */
73struct sm501fb_par {
74	u32			 pseudo_palette[16];
75
76	enum sm501_controller	 head;
77	struct sm501_mem	 cursor;
78	struct sm501_mem	 screen;
79	struct fb_ops		 ops;
80
81	void			*store_fb;
82	void			*store_cursor;
83	void __iomem		*cursor_regs;
84	struct sm501fb_info	*info;
85};
86
87/* Helper functions */
88
89static inline int h_total(struct fb_var_screeninfo *var)
90{
91	return var->xres + var->left_margin +
92		var->right_margin + var->hsync_len;
93}
94
95static inline int v_total(struct fb_var_screeninfo *var)
96{
97	return var->yres + var->upper_margin +
98		var->lower_margin + var->vsync_len;
99}
100
101/* sm501fb_sync_regs()
102 *
103 * This call is mainly for PCI bus systems where we need to
104 * ensure that any writes to the bus are completed before the
105 * next phase, or after completing a function.
106*/
107
108static inline void sm501fb_sync_regs(struct sm501fb_info *info)
109{
110	readl(info->regs);
111}
112
113/* sm501_alloc_mem
114 *
115 * This is an attempt to lay out memory for the two framebuffers and
116 * everything else
117 *
118 * |fbmem_res->start	                                       fbmem_res->end|
119 * |                                                                         |
120 * |fb[0].fix.smem_start    |         |fb[1].fix.smem_start    |     2K      |
121 * |-> fb[0].fix.smem_len <-| spare   |-> fb[1].fix.smem_len <-|-> cursors <-|
122 *
123 * The "spare" space is for the 2d engine data
124 * the fixed is space for the cursors (2x1Kbyte)
125 *
126 * we need to allocate memory for the 2D acceleration engine
127 * command list and the data for the engine to deal with.
128 *
129 * - all allocations must be 128bit aligned
130 * - cursors are 64x64x2 bits (1Kbyte)
131 *
132 */
133
134#define SM501_MEMF_CURSOR		(1)
135#define SM501_MEMF_PANEL		(2)
136#define SM501_MEMF_CRT			(4)
137#define SM501_MEMF_ACCEL		(8)
138
139static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
140			   unsigned int why, size_t size)
141{
142	unsigned int ptr = 0;
143
144	switch (why) {
145	case SM501_MEMF_CURSOR:
146		ptr = inf->fbmem_len - size;
147		inf->fbmem_len = ptr;
148		break;
149
150	case SM501_MEMF_PANEL:
151		ptr = inf->fbmem_len - size;
152		if (ptr < inf->fb[0]->fix.smem_len)
153			return -ENOMEM;
154
155		break;
156
157	case SM501_MEMF_CRT:
158		ptr = 0;
159		break;
160
161	case SM501_MEMF_ACCEL:
162		ptr = inf->fb[0]->fix.smem_len;
163
164		if ((ptr + size) >
165		    (inf->fb[1]->fix.smem_start - inf->fbmem_res->start))
166			return -ENOMEM;
167		break;
168
169	default:
170		return -EINVAL;
171	}
172
173	mem->size    = size;
174	mem->sm_addr = ptr;
175	mem->k_addr  = inf->fbmem + ptr;
176
177	dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
178		__func__, mem->sm_addr, mem->k_addr, why, size);
179
180	return 0;
181}
182
183/* sm501fb_ps_to_hz
184 *
185 * Converts a period in picoseconds to Hz.
186 *
187 * Note, we try to keep this in Hz to minimise rounding with
188 * the limited PLL settings on the SM501.
189*/
190
191static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
192{
193	unsigned long long numerator=1000000000000ULL;
194
195	/* 10^12 / picosecond period gives frequency in Hz */
196	do_div(numerator, psvalue);
197	return (unsigned long)numerator;
198}
199
200/* sm501fb_hz_to_ps is identical to the oposite transform */
201
202#define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
203
204/* sm501fb_setup_gamma
205 *
206 * Programs a linear 1.0 gamma ramp in case the gamma
207 * correction is enabled without programming anything else.
208*/
209
210static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
211				unsigned long palette)
212{
213	unsigned long value = 0;
214	int offset;
215
216	/* set gamma values */
217	for (offset = 0; offset < 256 * 4; offset += 4) {
218		writel(value, fbi->regs + palette + offset);
219		value += 0x010101; 	/* Advance RGB by 1,1,1.*/
220	}
221}
222
223/* sm501fb_check_var
224 *
225 * check common variables for both panel and crt
226*/
227
228static int sm501fb_check_var(struct fb_var_screeninfo *var,
229			     struct fb_info *info)
230{
231	struct sm501fb_par  *par = info->par;
232	struct sm501fb_info *sm  = par->info;
233	unsigned long tmp;
234
235	/* check we can fit these values into the registers */
236
237	if (var->hsync_len > 255 || var->vsync_len > 255)
238		return -EINVAL;
239
240	if ((var->xres + var->right_margin) >= 4096)
241		return -EINVAL;
242
243	if ((var->yres + var->lower_margin) > 2048)
244		return -EINVAL;
245
246	/* hard limits of device */
247
248	if (h_total(var) > 4096 || v_total(var) > 2048)
249		return -EINVAL;
250
251	/* check our line length is going to be 128 bit aligned */
252
253	tmp = (var->xres * var->bits_per_pixel) / 8;
254	if ((tmp & 15) != 0)
255		return -EINVAL;
256
257	/* check the virtual size */
258
259	if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
260		return -EINVAL;
261
262	/* can cope with 8,16 or 32bpp */
263
264	if (var->bits_per_pixel <= 8)
265		var->bits_per_pixel = 8;
266	else if (var->bits_per_pixel <= 16)
267		var->bits_per_pixel = 16;
268	else if (var->bits_per_pixel == 24)
269		var->bits_per_pixel = 32;
270
271	/* set r/g/b positions and validate bpp */
272	switch(var->bits_per_pixel) {
273	case 8:
274		var->red.length		= var->bits_per_pixel;
275		var->red.offset		= 0;
276		var->green.length	= var->bits_per_pixel;
277		var->green.offset	= 0;
278		var->blue.length	= var->bits_per_pixel;
279		var->blue.offset	= 0;
280		var->transp.length	= 0;
281
282		break;
283
284	case 16:
285		if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
286			var->red.offset		= 11;
287			var->green.offset	= 5;
288			var->blue.offset	= 0;
289		} else {
290			var->blue.offset	= 11;
291			var->green.offset	= 5;
292			var->red.offset		= 0;
293		}
294
295		var->red.length		= 5;
296		var->green.length	= 6;
297		var->blue.length	= 5;
298		var->transp.length	= 0;
299		break;
300
301	case 32:
302		if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
303			var->transp.offset	= 0;
304			var->red.offset		= 8;
305			var->green.offset	= 16;
306			var->blue.offset	= 24;
307		} else {
308			var->transp.offset	= 24;
309			var->red.offset		= 16;
310			var->green.offset	= 8;
311			var->blue.offset	= 0;
312		}
313
314		var->red.length		= 8;
315		var->green.length	= 8;
316		var->blue.length	= 8;
317		var->transp.length	= 0;
318		break;
319
320	default:
321		return -EINVAL;
322	}
323
324	return 0;
325}
326
327/*
328 * sm501fb_check_var_crt():
329 *
330 * check the parameters for the CRT head, and either bring them
331 * back into range, or return -EINVAL.
332*/
333
334static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
335				 struct fb_info *info)
336{
337	return sm501fb_check_var(var, info);
338}
339
340/* sm501fb_check_var_pnl():
341 *
342 * check the parameters for the CRT head, and either bring them
343 * back into range, or return -EINVAL.
344*/
345
346static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
347				 struct fb_info *info)
348{
349	return sm501fb_check_var(var, info);
350}
351
352/* sm501fb_set_par_common
353 *
354 * set common registers for framebuffers
355*/
356
357static int sm501fb_set_par_common(struct fb_info *info,
358				  struct fb_var_screeninfo *var)
359{
360	struct sm501fb_par  *par = info->par;
361	struct sm501fb_info *fbi = par->info;
362	unsigned long pixclock;      /* pixelclock in Hz */
363	unsigned long sm501pixclock; /* pixelclock the 501 can achive in Hz */
364	unsigned int mem_type;
365	unsigned int clock_type;
366	unsigned int head_addr;
367
368	dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
369		__func__, var->xres, var->yres, var->bits_per_pixel,
370		var->xres_virtual, var->yres_virtual);
371
372	switch (par->head) {
373	case HEAD_CRT:
374		mem_type = SM501_MEMF_CRT;
375		clock_type = SM501_CLOCK_V2XCLK;
376		head_addr = SM501_DC_CRT_FB_ADDR;
377		break;
378
379	case HEAD_PANEL:
380		mem_type = SM501_MEMF_PANEL;
381		clock_type = SM501_CLOCK_P2XCLK;
382		head_addr = SM501_DC_PANEL_FB_ADDR;
383		break;
384
385	default:
386		mem_type = 0;		/* stop compiler warnings */
387		head_addr = 0;
388		clock_type = 0;
389	}
390
391	switch (var->bits_per_pixel) {
392	case 8:
393		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
394		break;
395
396	case 16:
397		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
398		break;
399
400	case 32:
401		info->fix.visual = FB_VISUAL_TRUECOLOR;
402		break;
403	}
404
405	/* allocate fb memory within 501 */
406	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
407	info->fix.smem_len    = info->fix.line_length * var->yres_virtual;
408
409	dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
410		info->fix.line_length);
411
412	if (sm501_alloc_mem(fbi, &par->screen, mem_type,
413			    info->fix.smem_len)) {
414		dev_err(fbi->dev, "no memory available\n");
415		return -ENOMEM;
416	}
417
418	info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
419
420	info->screen_base = fbi->fbmem + par->screen.sm_addr;
421	info->screen_size = info->fix.smem_len;
422
423	/* set start of framebuffer to the screen */
424
425	writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
426
427	/* program CRT clock  */
428
429	pixclock = sm501fb_ps_to_hz(var->pixclock);
430
431	sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
432					pixclock);
433
434	/* update fb layer with actual clock used */
435	var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
436
437	dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz)  = %lu, "
438	       "sm501pixclock = %lu,  error = %ld%%\n",
439	       __func__, var->pixclock, pixclock, sm501pixclock,
440	       ((pixclock - sm501pixclock)*100)/pixclock);
441
442	return 0;
443}
444
445/* sm501fb_set_par_geometry
446 *
447 * set the geometry registers for specified framebuffer.
448*/
449
450static void sm501fb_set_par_geometry(struct fb_info *info,
451				     struct fb_var_screeninfo *var)
452{
453	struct sm501fb_par  *par = info->par;
454	struct sm501fb_info *fbi = par->info;
455	void __iomem *base = fbi->regs;
456	unsigned long reg;
457
458	if (par->head == HEAD_CRT)
459		base += SM501_DC_CRT_H_TOT;
460	else
461		base += SM501_DC_PANEL_H_TOT;
462
463	/* set framebuffer width and display width */
464
465	reg = info->fix.line_length;
466	reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
467
468	writel(reg, fbi->regs + (par->head == HEAD_CRT ?
469		    SM501_DC_CRT_FB_OFFSET :  SM501_DC_PANEL_FB_OFFSET));
470
471	/* program horizontal total */
472
473	reg  = (h_total(var) - 1) << 16;
474	reg |= (var->xres - 1);
475
476	writel(reg, base + SM501_OFF_DC_H_TOT);
477
478	/* program horizontal sync */
479
480	reg  = var->hsync_len << 16;
481	reg |= var->xres + var->right_margin - 1;
482
483	writel(reg, base + SM501_OFF_DC_H_SYNC);
484
485	/* program vertical total */
486
487	reg  = (v_total(var) - 1) << 16;
488	reg |= (var->yres - 1);
489
490	writel(reg, base + SM501_OFF_DC_V_TOT);
491
492	/* program vertical sync */
493	reg  = var->vsync_len << 16;
494	reg |= var->yres + var->lower_margin - 1;
495
496	writel(reg, base + SM501_OFF_DC_V_SYNC);
497}
498
499/* sm501fb_pan_crt
500 *
501 * pan the CRT display output within an virtual framebuffer
502*/
503
504static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
505			   struct fb_info *info)
506{
507	struct sm501fb_par  *par = info->par;
508	struct sm501fb_info *fbi = par->info;
509	unsigned int bytes_pixel = var->bits_per_pixel / 8;
510	unsigned long reg;
511	unsigned long xoffs;
512
513	xoffs = var->xoffset * bytes_pixel;
514
515	reg = readl(fbi->regs + SM501_DC_CRT_CONTROL);
516
517	reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
518	reg |= ((xoffs & 15) / bytes_pixel) << 4;
519	writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
520
521	reg = (par->screen.sm_addr + xoffs +
522	       var->yoffset * info->fix.line_length);
523	writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
524
525	sm501fb_sync_regs(fbi);
526	return 0;
527}
528
529/* sm501fb_pan_pnl
530 *
531 * pan the panel display output within an virtual framebuffer
532*/
533
534static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
535			   struct fb_info *info)
536{
537	struct sm501fb_par  *par = info->par;
538	struct sm501fb_info *fbi = par->info;
539	unsigned long reg;
540
541	reg = var->xoffset | (var->xres_virtual << 16);
542	writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
543
544	reg = var->yoffset | (var->yres_virtual << 16);
545	writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
546
547	sm501fb_sync_regs(fbi);
548	return 0;
549}
550
551/* sm501fb_set_par_crt
552 *
553 * Set the CRT video mode from the fb_info structure
554*/
555
556static int sm501fb_set_par_crt(struct fb_info *info)
557{
558	struct sm501fb_par  *par = info->par;
559	struct sm501fb_info *fbi = par->info;
560	struct fb_var_screeninfo *var = &info->var;
561	unsigned long control;       /* control register */
562	int ret;
563
564	/* activate new configuration */
565
566	dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
567
568	/* enable CRT DAC - note 0 is on!*/
569	sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
570
571	control = readl(fbi->regs + SM501_DC_CRT_CONTROL);
572
573	control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
574		    SM501_DC_CRT_CONTROL_GAMMA |
575		    SM501_DC_CRT_CONTROL_BLANK |
576		    SM501_DC_CRT_CONTROL_SEL |
577		    SM501_DC_CRT_CONTROL_CP |
578		    SM501_DC_CRT_CONTROL_TVP);
579
580	/* set the sync polarities before we check data source  */
581
582	if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
583		control |= SM501_DC_CRT_CONTROL_HSP;
584
585	if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
586		control |= SM501_DC_CRT_CONTROL_VSP;
587
588	if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
589		/* the head is displaying panel data... */
590
591		sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
592		goto out_update;
593	}
594
595	ret = sm501fb_set_par_common(info, var);
596	if (ret) {
597		dev_err(fbi->dev, "failed to set common parameters\n");
598		return ret;
599	}
600
601	sm501fb_pan_crt(var, info);
602	sm501fb_set_par_geometry(info, var);
603
604	control |= SM501_FIFO_3;	/* fill if >3 free slots */
605
606	switch(var->bits_per_pixel) {
607	case 8:
608		control |= SM501_DC_CRT_CONTROL_8BPP;
609		break;
610
611	case 16:
612		control |= SM501_DC_CRT_CONTROL_16BPP;
613		break;
614
615	case 32:
616		control |= SM501_DC_CRT_CONTROL_32BPP;
617		sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
618		break;
619
620	default:
621		BUG();
622	}
623
624	control |= SM501_DC_CRT_CONTROL_SEL;	/* CRT displays CRT data */
625	control |= SM501_DC_CRT_CONTROL_TE;	/* enable CRT timing */
626	control |= SM501_DC_CRT_CONTROL_ENABLE;	/* enable CRT plane */
627
628 out_update:
629	dev_dbg(fbi->dev, "new control is %08lx\n", control);
630
631	writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
632	sm501fb_sync_regs(fbi);
633
634	return 0;
635}
636
637static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
638{
639	unsigned long control;
640	void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
641
642	control = readl(ctrl_reg);
643
644	if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
645		/* enable panel power */
646
647		control |= SM501_DC_PANEL_CONTROL_VDD;	/* FPVDDEN */
648		writel(control, ctrl_reg);
649		sm501fb_sync_regs(fbi);
650		mdelay(10);
651
652		control |= SM501_DC_PANEL_CONTROL_DATA;	/* DATA */
653		writel(control, ctrl_reg);
654		sm501fb_sync_regs(fbi);
655		mdelay(10);
656
657		control |= SM501_DC_PANEL_CONTROL_BIAS;	/* VBIASEN */
658		writel(control, ctrl_reg);
659		sm501fb_sync_regs(fbi);
660		mdelay(10);
661
662		control |= SM501_DC_PANEL_CONTROL_FPEN;
663		writel(control, ctrl_reg);
664
665	} else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
666		/* disable panel power */
667
668		control &= ~SM501_DC_PANEL_CONTROL_FPEN;
669		writel(control, ctrl_reg);
670		sm501fb_sync_regs(fbi);
671		mdelay(10);
672
673		control &= ~SM501_DC_PANEL_CONTROL_BIAS;
674		writel(control, ctrl_reg);
675		sm501fb_sync_regs(fbi);
676		mdelay(10);
677
678		control &= ~SM501_DC_PANEL_CONTROL_DATA;
679		writel(control, ctrl_reg);
680		sm501fb_sync_regs(fbi);
681		mdelay(10);
682
683		control &= ~SM501_DC_PANEL_CONTROL_VDD;
684		writel(control, ctrl_reg);
685		sm501fb_sync_regs(fbi);
686		mdelay(10);
687	}
688
689	sm501fb_sync_regs(fbi);
690}
691
692/* sm501fb_set_par_pnl
693 *
694 * Set the panel video mode from the fb_info structure
695*/
696
697static int sm501fb_set_par_pnl(struct fb_info *info)
698{
699	struct sm501fb_par  *par = info->par;
700	struct sm501fb_info *fbi = par->info;
701	struct fb_var_screeninfo *var = &info->var;
702	unsigned long control;
703	unsigned long reg;
704	int ret;
705
706	dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
707
708	/* activate this new configuration */
709
710	ret = sm501fb_set_par_common(info, var);
711	if (ret)
712		return ret;
713
714	sm501fb_pan_pnl(var, info);
715	sm501fb_set_par_geometry(info, var);
716
717	/* update control register */
718
719	control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);
720	control &= (SM501_DC_PANEL_CONTROL_GAMMA |
721		    SM501_DC_PANEL_CONTROL_VDD  |
722		    SM501_DC_PANEL_CONTROL_DATA |
723		    SM501_DC_PANEL_CONTROL_BIAS |
724		    SM501_DC_PANEL_CONTROL_FPEN |
725		    SM501_DC_PANEL_CONTROL_CP |
726		    SM501_DC_PANEL_CONTROL_CK |
727		    SM501_DC_PANEL_CONTROL_HP |
728		    SM501_DC_PANEL_CONTROL_VP |
729		    SM501_DC_PANEL_CONTROL_HPD |
730		    SM501_DC_PANEL_CONTROL_VPD);
731
732	control |= SM501_FIFO_3;	/* fill if >3 free slots */
733
734	switch(var->bits_per_pixel) {
735	case 8:
736		control |= SM501_DC_PANEL_CONTROL_8BPP;
737		break;
738
739	case 16:
740		control |= SM501_DC_PANEL_CONTROL_16BPP;
741		break;
742
743	case 32:
744		control |= SM501_DC_PANEL_CONTROL_32BPP;
745		sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
746		break;
747
748	default:
749		BUG();
750	}
751
752	writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
753
754	/* panel plane top left and bottom right location */
755
756	writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
757
758	reg  = var->xres - 1;
759	reg |= (var->yres - 1) << 16;
760
761	writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
762
763	/* program panel control register */
764
765	control |= SM501_DC_PANEL_CONTROL_TE;	/* enable PANEL timing */
766	control |= SM501_DC_PANEL_CONTROL_EN;	/* enable PANEL gfx plane */
767
768	if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
769		control |= SM501_DC_PANEL_CONTROL_HSP;
770
771	if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
772		control |= SM501_DC_PANEL_CONTROL_VSP;
773
774	writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
775	sm501fb_sync_regs(fbi);
776
777	/* power the panel up */
778	sm501fb_panel_power(fbi, 1);
779	return 0;
780}
781
782
783/* chan_to_field
784 *
785 * convert a colour value into a field position
786 *
787 * from pxafb.c
788*/
789
790static inline unsigned int chan_to_field(unsigned int chan,
791					 struct fb_bitfield *bf)
792{
793	chan &= 0xffff;
794	chan >>= 16 - bf->length;
795	return chan << bf->offset;
796}
797
798/* sm501fb_setcolreg
799 *
800 * set the colour mapping for modes that support palettised data
801*/
802
803static int sm501fb_setcolreg(unsigned regno,
804			     unsigned red, unsigned green, unsigned blue,
805			     unsigned transp, struct fb_info *info)
806{
807	struct sm501fb_par  *par = info->par;
808	struct sm501fb_info *fbi = par->info;
809	void __iomem *base = fbi->regs;
810	unsigned int val;
811
812	if (par->head == HEAD_CRT)
813		base += SM501_DC_CRT_PALETTE;
814	else
815		base += SM501_DC_PANEL_PALETTE;
816
817	switch (info->fix.visual) {
818	case FB_VISUAL_TRUECOLOR:
819		/* true-colour, use pseuo-palette */
820
821		if (regno < 16) {
822			u32 *pal = par->pseudo_palette;
823
824			val  = chan_to_field(red,   &info->var.red);
825			val |= chan_to_field(green, &info->var.green);
826			val |= chan_to_field(blue,  &info->var.blue);
827
828			pal[regno] = val;
829		}
830		break;
831
832	case FB_VISUAL_PSEUDOCOLOR:
833		if (regno < 256) {
834			val = (red >> 8) << 16;
835			val |= (green >> 8) << 8;
836			val |= blue >> 8;
837
838			writel(val, base + (regno * 4));
839		}
840
841		break;
842
843	default:
844		return 1;   /* unknown type */
845	}
846
847	return 0;
848}
849
850/* sm501fb_blank_pnl
851 *
852 * Blank or un-blank the panel interface
853*/
854
855static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
856{
857	struct sm501fb_par  *par = info->par;
858	struct sm501fb_info *fbi = par->info;
859
860	dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
861
862	switch (blank_mode) {
863	case FB_BLANK_POWERDOWN:
864		sm501fb_panel_power(fbi, 0);
865		break;
866
867	case FB_BLANK_UNBLANK:
868		sm501fb_panel_power(fbi, 1);
869		break;
870
871	case FB_BLANK_NORMAL:
872	case FB_BLANK_VSYNC_SUSPEND:
873	case FB_BLANK_HSYNC_SUSPEND:
874	default:
875		return 1;
876	}
877
878	return 0;
879}
880
881/* sm501fb_blank_crt
882 *
883 * Blank or un-blank the crt interface
884*/
885
886static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
887{
888	struct sm501fb_par  *par = info->par;
889	struct sm501fb_info *fbi = par->info;
890	unsigned long ctrl;
891
892	dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
893
894	ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);
895
896	switch (blank_mode) {
897	case FB_BLANK_POWERDOWN:
898		ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
899		sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
900
901	case FB_BLANK_NORMAL:
902		ctrl |= SM501_DC_CRT_CONTROL_BLANK;
903		break;
904
905	case FB_BLANK_UNBLANK:
906		ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
907		ctrl |=  SM501_DC_CRT_CONTROL_ENABLE;
908		sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
909		break;
910
911	case FB_BLANK_VSYNC_SUSPEND:
912	case FB_BLANK_HSYNC_SUSPEND:
913	default:
914		return 1;
915
916	}
917
918	writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
919	sm501fb_sync_regs(fbi);
920
921	return 0;
922}
923
924/* sm501fb_cursor
925 *
926 * set or change the hardware cursor parameters
927*/
928
929static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
930{
931	struct sm501fb_par  *par = info->par;
932	struct sm501fb_info *fbi = par->info;
933	void __iomem *base = fbi->regs;
934	unsigned long hwc_addr;
935	unsigned long fg, bg;
936
937	dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
938
939	if (par->head == HEAD_CRT)
940		base += SM501_DC_CRT_HWC_BASE;
941	else
942		base += SM501_DC_PANEL_HWC_BASE;
943
944	/* check not being asked to exceed capabilities */
945
946	if (cursor->image.width > 64)
947		return -EINVAL;
948
949	if (cursor->image.height > 64)
950		return -EINVAL;
951
952	if (cursor->image.depth > 1)
953		return -EINVAL;
954
955	hwc_addr = readl(base + SM501_OFF_HWC_ADDR);
956
957	if (cursor->enable)
958		writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
959	else
960		writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
961
962	/* set data */
963	if (cursor->set & FB_CUR_SETPOS) {
964		unsigned int x = cursor->image.dx;
965		unsigned int y = cursor->image.dy;
966
967		if (x >= 2048 || y >= 2048 )
968			return -EINVAL;
969
970		dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
971
972		//y += cursor->image.height;
973
974		writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
975	}
976
977	if (cursor->set & FB_CUR_SETCMAP) {
978		unsigned int bg_col = cursor->image.bg_color;
979		unsigned int fg_col = cursor->image.fg_color;
980
981		dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
982			__func__, bg_col, fg_col);
983
984		bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
985			((info->cmap.green[bg_col] & 0xFC) << 3) |
986			((info->cmap.blue[bg_col] & 0xF8) >> 3);
987
988		fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
989			((info->cmap.green[fg_col] & 0xFC) << 3) |
990			((info->cmap.blue[fg_col] & 0xF8) >> 3);
991
992		dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
993
994		writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
995		writel(fg, base + SM501_OFF_HWC_COLOR_3);
996	}
997
998	if (cursor->set & FB_CUR_SETSIZE ||
999	    cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
1000		/* SM501 cursor is a two bpp 64x64 bitmap this routine
1001		 * clears it to transparent then combines the cursor
1002		 * shape plane with the colour plane to set the
1003		 * cursor */
1004		int x, y;
1005		const unsigned char *pcol = cursor->image.data;
1006		const unsigned char *pmsk = cursor->mask;
1007		void __iomem   *dst = par->cursor.k_addr;
1008		unsigned char  dcol = 0;
1009		unsigned char  dmsk = 0;
1010		unsigned int   op;
1011
1012		dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
1013			__func__, cursor->image.width, cursor->image.height);
1014
1015		for (op = 0; op < (64*64*2)/8; op+=4)
1016			writel(0x0, dst + op);
1017
1018		for (y = 0; y < cursor->image.height; y++) {
1019			for (x = 0; x < cursor->image.width; x++) {
1020				if ((x % 8) == 0) {
1021					dcol = *pcol++;
1022					dmsk = *pmsk++;
1023				} else {
1024					dcol >>= 1;
1025					dmsk >>= 1;
1026				}
1027
1028				if (dmsk & 1) {
1029					op = (dcol & 1) ? 1 : 3;
1030					op <<= ((x % 4) * 2);
1031
1032					op |= readb(dst + (x / 4));
1033					writeb(op, dst + (x / 4));
1034				}
1035			}
1036			dst += (64*2)/8;
1037		}
1038	}
1039
1040	sm501fb_sync_regs(fbi);	/* ensure cursor data flushed */
1041	return 0;
1042}
1043
1044/* sm501fb_crtsrc_show
1045 *
1046 * device attribute code to show where the crt output is sourced from
1047*/
1048
1049static ssize_t sm501fb_crtsrc_show(struct device *dev,
1050			       struct device_attribute *attr, char *buf)
1051{
1052	struct sm501fb_info *info = dev_get_drvdata(dev);
1053	unsigned long ctrl;
1054
1055	ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
1056	ctrl &= SM501_DC_CRT_CONTROL_SEL;
1057
1058	return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
1059}
1060
1061/* sm501fb_crtsrc_show
1062 *
1063 * device attribute code to set where the crt output is sourced from
1064*/
1065
1066static ssize_t sm501fb_crtsrc_store(struct device *dev,
1067				struct device_attribute *attr,
1068				const char *buf, size_t len)
1069{
1070	struct sm501fb_info *info = dev_get_drvdata(dev);
1071	enum sm501_controller head;
1072	unsigned long ctrl;
1073
1074	if (len < 1)
1075		return -EINVAL;
1076
1077	if (strnicmp(buf, "crt", 3) == 0)
1078		head = HEAD_CRT;
1079	else if (strnicmp(buf, "panel", 5) == 0)
1080		head = HEAD_PANEL;
1081	else
1082		return -EINVAL;
1083
1084	dev_info(dev, "setting crt source to head %d\n", head);
1085
1086	ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
1087
1088	if (head == HEAD_CRT) {
1089		ctrl |= SM501_DC_CRT_CONTROL_SEL;
1090		ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
1091		ctrl |= SM501_DC_CRT_CONTROL_TE;
1092	} else {
1093		ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
1094		ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
1095		ctrl &= ~SM501_DC_CRT_CONTROL_TE;
1096	}
1097
1098	writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
1099	sm501fb_sync_regs(info);
1100
1101	return len;
1102}
1103
1104/* Prepare the device_attr for registration with sysfs later */
1105static DEVICE_ATTR(crt_src, 0666, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
1106
1107/* sm501fb_show_regs
1108 *
1109 * show the primary sm501 registers
1110*/
1111static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
1112			     unsigned int start, unsigned int len)
1113{
1114	void __iomem *mem = info->regs;
1115	char *buf = ptr;
1116	unsigned int reg;
1117
1118	for (reg = start; reg < (len + start); reg += 4)
1119		ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));
1120
1121	return ptr - buf;
1122}
1123
1124/* sm501fb_debug_show_crt
1125 *
1126 * show the crt control and cursor registers
1127*/
1128
1129static ssize_t sm501fb_debug_show_crt(struct device *dev,
1130				  struct device_attribute *attr, char *buf)
1131{
1132	struct sm501fb_info *info = dev_get_drvdata(dev);
1133	char *ptr = buf;
1134
1135	ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
1136	ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
1137
1138	return ptr - buf;
1139}
1140
1141static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
1142
1143/* sm501fb_debug_show_pnl
1144 *
1145 * show the panel control and cursor registers
1146*/
1147
1148static ssize_t sm501fb_debug_show_pnl(struct device *dev,
1149				  struct device_attribute *attr, char *buf)
1150{
1151	struct sm501fb_info *info = dev_get_drvdata(dev);
1152	char *ptr = buf;
1153
1154	ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
1155	ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
1156
1157	return ptr - buf;
1158}
1159
1160static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
1161
1162/* framebuffer ops */
1163
1164static struct fb_ops sm501fb_ops_crt = {
1165	.owner		= THIS_MODULE,
1166	.fb_check_var	= sm501fb_check_var_crt,
1167	.fb_set_par	= sm501fb_set_par_crt,
1168	.fb_blank	= sm501fb_blank_crt,
1169	.fb_setcolreg	= sm501fb_setcolreg,
1170	.fb_pan_display	= sm501fb_pan_crt,
1171	.fb_cursor	= sm501fb_cursor,
1172	.fb_fillrect	= cfb_fillrect,
1173	.fb_copyarea	= cfb_copyarea,
1174	.fb_imageblit	= cfb_imageblit,
1175};
1176
1177static struct fb_ops sm501fb_ops_pnl = {
1178	.owner		= THIS_MODULE,
1179	.fb_check_var	= sm501fb_check_var_pnl,
1180	.fb_set_par	= sm501fb_set_par_pnl,
1181	.fb_pan_display	= sm501fb_pan_pnl,
1182	.fb_blank	= sm501fb_blank_pnl,
1183	.fb_setcolreg	= sm501fb_setcolreg,
1184	.fb_cursor	= sm501fb_cursor,
1185	.fb_fillrect	= cfb_fillrect,
1186	.fb_copyarea	= cfb_copyarea,
1187	.fb_imageblit	= cfb_imageblit,
1188};
1189
1190/* sm501fb_info_alloc
1191 *
1192 * creates and initialises an sm501fb_info structure
1193*/
1194
1195static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
1196					       struct fb_info *fbinfo_pnl)
1197{
1198	struct sm501fb_info *info;
1199	struct sm501fb_par  *par;
1200
1201	info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
1202	if (info) {
1203		/* set the references back */
1204
1205		par = fbinfo_crt->par;
1206		par->info = info;
1207		par->head = HEAD_CRT;
1208		fbinfo_crt->pseudo_palette = &par->pseudo_palette;
1209
1210		par = fbinfo_pnl->par;
1211		par->info = info;
1212		par->head = HEAD_PANEL;
1213		fbinfo_pnl->pseudo_palette = &par->pseudo_palette;
1214
1215		/* store the two fbs into our info */
1216		info->fb[HEAD_CRT] = fbinfo_crt;
1217		info->fb[HEAD_PANEL] = fbinfo_pnl;
1218	}
1219
1220	return info;
1221}
1222
1223/* sm501_init_cursor
1224 *
1225 * initialise hw cursor parameters
1226*/
1227
1228static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
1229{
1230	struct sm501fb_par *par = fbi->par;
1231	struct sm501fb_info *info = par->info;
1232	int ret;
1233
1234	par->cursor_regs = info->regs + reg_base;
1235
1236	ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
1237	if (ret < 0)
1238		return ret;
1239
1240	/* initialise the colour registers */
1241
1242	writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);
1243
1244	writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
1245	writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
1246	writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
1247	sm501fb_sync_regs(info);
1248
1249	return 0;
1250}
1251
1252/* sm501fb_info_start
1253 *
1254 * fills the par structure claiming resources and remapping etc.
1255*/
1256
1257static int sm501fb_start(struct sm501fb_info *info,
1258			 struct platform_device *pdev)
1259{
1260	struct resource	*res;
1261	struct device *dev;
1262	int ret;
1263
1264	info->dev = dev = &pdev->dev;
1265	platform_set_drvdata(pdev, info);
1266
1267	info->irq = ret = platform_get_irq(pdev, 0);
1268	if (ret < 0) {
1269		/* we currently do not use the IRQ */
1270		dev_warn(dev, "no irq for device\n");
1271	}
1272
1273	/* allocate, reserve and remap resources for registers */
1274	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1275	if (res == NULL) {
1276		dev_err(dev, "no resource definition for registers\n");
1277		ret = -ENOENT;
1278		goto err_release;
1279	}
1280
1281	info->regs_res = request_mem_region(res->start,
1282					    res->end - res->start,
1283					    pdev->name);
1284
1285	if (info->regs_res == NULL) {
1286		dev_err(dev, "cannot claim registers\n");
1287		ret = -ENXIO;
1288		goto err_release;
1289	}
1290
1291	info->regs = ioremap(res->start, (res->end - res->start)+1);
1292	if (info->regs == NULL) {
1293		dev_err(dev, "cannot remap registers\n");
1294		ret = -ENXIO;
1295		goto err_regs_res;
1296	}
1297
1298	/* allocate, reserve resources for framebuffer */
1299	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
1300	if (res == NULL) {
1301		dev_err(dev, "no memory resource defined\n");
1302		ret = -ENXIO;
1303		goto err_regs_map;
1304	}
1305
1306	info->fbmem_res = request_mem_region(res->start,
1307					     (res->end - res->start)+1,
1308					     pdev->name);
1309	if (info->fbmem_res == NULL) {
1310		dev_err(dev, "cannot claim framebuffer\n");
1311		ret = -ENXIO;
1312		goto err_regs_map;
1313	}
1314
1315	info->fbmem = ioremap(res->start, (res->end - res->start)+1);
1316	if (info->fbmem == NULL) {
1317		dev_err(dev, "cannot remap framebuffer\n");
1318		goto err_mem_res;
1319	}
1320
1321	info->fbmem_len = (res->end - res->start)+1;
1322
1323	/* enable display controller */
1324	sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
1325
1326	/* setup cursors */
1327
1328	sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
1329	sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
1330
1331	return 0; /* everything is setup */
1332
1333 err_mem_res:
1334	release_resource(info->fbmem_res);
1335	kfree(info->fbmem_res);
1336
1337 err_regs_map:
1338	iounmap(info->regs);
1339
1340 err_regs_res:
1341	release_resource(info->regs_res);
1342	kfree(info->regs_res);
1343
1344 err_release:
1345	return ret;
1346}
1347
1348static void sm501fb_stop(struct sm501fb_info *info)
1349{
1350	/* disable display controller */
1351	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
1352
1353	iounmap(info->fbmem);
1354	release_resource(info->fbmem_res);
1355	kfree(info->fbmem_res);
1356
1357	iounmap(info->regs);
1358	release_resource(info->regs_res);
1359	kfree(info->regs_res);
1360}
1361
1362static void sm501fb_info_release(struct sm501fb_info *info)
1363{
1364	kfree(info);
1365}
1366
1367static int sm501fb_init_fb(struct fb_info *fb,
1368			   enum sm501_controller head,
1369			   const char *fbname)
1370{
1371	struct sm501_platdata_fbsub *pd;
1372	struct sm501fb_par *par = fb->par;
1373	struct sm501fb_info *info = par->info;
1374	unsigned long ctrl;
1375	unsigned int enable;
1376	int ret;
1377
1378	switch (head) {
1379	case HEAD_CRT:
1380		pd = info->pdata->fb_crt;
1381		ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
1382		enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
1383
1384		/* ensure we set the correct source register */
1385		if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
1386			ctrl |= SM501_DC_CRT_CONTROL_SEL;
1387			writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
1388		}
1389
1390		break;
1391
1392	case HEAD_PANEL:
1393		pd = info->pdata->fb_pnl;
1394		ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
1395		enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
1396		break;
1397
1398	default:
1399		pd = NULL;		/* stop compiler warnings */
1400		ctrl = 0;
1401		enable = 0;
1402		BUG();
1403	}
1404
1405	dev_info(info->dev, "fb %s %sabled at start\n",
1406		 fbname, enable ? "en" : "dis");
1407
1408	/* check to see if our routing allows this */
1409
1410	if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
1411		ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
1412		writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
1413		enable = 0;
1414	}
1415
1416	strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
1417
1418	memcpy(&par->ops,
1419	       (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
1420	       sizeof(struct fb_ops));
1421
1422	/* update ops dependant on what we've been passed */
1423
1424	if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
1425		par->ops.fb_cursor = NULL;
1426
1427	fb->fbops = &par->ops;
1428	fb->flags = FBINFO_FLAG_DEFAULT |
1429		FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
1430
1431	/* fixed data */
1432
1433	fb->fix.type		= FB_TYPE_PACKED_PIXELS;
1434	fb->fix.type_aux	= 0;
1435	fb->fix.xpanstep	= 1;
1436	fb->fix.ypanstep	= 1;
1437	fb->fix.ywrapstep	= 0;
1438	fb->fix.accel		= FB_ACCEL_NONE;
1439
1440	/* screenmode */
1441
1442	fb->var.nonstd		= 0;
1443	fb->var.activate	= FB_ACTIVATE_NOW;
1444	fb->var.accel_flags	= 0;
1445	fb->var.vmode		= FB_VMODE_NONINTERLACED;
1446	fb->var.bits_per_pixel  = 16;
1447
1448	if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
1449		/* TODO read the mode from the current display */
1450
1451	} else {
1452		if (pd->def_mode) {
1453			dev_info(info->dev, "using supplied mode\n");
1454			fb_videomode_to_var(&fb->var, pd->def_mode);
1455
1456			fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
1457			fb->var.xres_virtual = fb->var.xres;
1458			fb->var.yres_virtual = fb->var.yres;
1459		} else {
1460			ret = fb_find_mode(&fb->var, fb,
1461					   NULL, NULL, 0, NULL, 8);
1462
1463			if (ret == 0 || ret == 4) {
1464				dev_err(info->dev,
1465					"failed to get initial mode\n");
1466				return -EINVAL;
1467			}
1468		}
1469	}
1470
1471	/* initialise and set the palette */
1472	fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
1473	fb_set_cmap(&fb->cmap, fb);
1474
1475	ret = (fb->fbops->fb_check_var)(&fb->var, fb);
1476	if (ret)
1477		dev_err(info->dev, "check_var() failed on initial setup?\n");
1478
1479	/* ensure we've activated our new configuration */
1480	(fb->fbops->fb_set_par)(fb);
1481
1482	return 0;
1483}
1484
1485/* default platform data if none is supplied (ie, PCI device) */
1486
1487static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
1488	.flags		= (SM501FB_FLAG_USE_INIT_MODE |
1489			   SM501FB_FLAG_USE_HWCURSOR |
1490			   SM501FB_FLAG_USE_HWACCEL |
1491			   SM501FB_FLAG_DISABLE_AT_EXIT),
1492
1493};
1494
1495static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
1496	.flags		= (SM501FB_FLAG_USE_INIT_MODE |
1497			   SM501FB_FLAG_USE_HWCURSOR |
1498			   SM501FB_FLAG_USE_HWACCEL |
1499			   SM501FB_FLAG_DISABLE_AT_EXIT),
1500};
1501
1502static struct sm501_platdata_fb sm501fb_def_pdata = {
1503	.fb_route		= SM501_FB_OWN,
1504	.fb_crt			= &sm501fb_pdata_crt,
1505	.fb_pnl			= &sm501fb_pdata_pnl,
1506};
1507
1508static char driver_name_crt[] = "sm501fb-crt";
1509static char driver_name_pnl[] = "sm501fb-panel";
1510
1511static int __init sm501fb_probe(struct platform_device *pdev)
1512{
1513	struct sm501fb_info *info;
1514	struct device	    *dev = &pdev->dev;
1515	struct fb_info	    *fbinfo_crt;
1516	struct fb_info	    *fbinfo_pnl;
1517	int		     ret;
1518
1519	/* allocate our framebuffers */
1520
1521	fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
1522	if (fbinfo_crt == NULL) {
1523		dev_err(dev, "cannot allocate crt framebuffer\n");
1524		return -ENOMEM;
1525	}
1526
1527	fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
1528	if (fbinfo_pnl == NULL) {
1529		dev_err(dev, "cannot allocate panel framebuffer\n");
1530		ret = -ENOMEM;
1531		goto fbinfo_crt_alloc_fail;
1532	}
1533
1534	info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl);
1535	if (info == NULL) {
1536		dev_err(dev, "cannot allocate par\n");
1537		ret = -ENOMEM;
1538		goto sm501fb_alloc_fail;
1539	}
1540
1541	if (dev->parent->platform_data) {
1542		struct sm501_platdata *pd = dev->parent->platform_data;
1543		info->pdata = pd->fb;
1544	}
1545
1546	if (info->pdata == NULL) {
1547		dev_info(dev, "using default configuration data\n");
1548		info->pdata = &sm501fb_def_pdata;
1549	}
1550
1551	/* start the framebuffers */
1552
1553	ret = sm501fb_start(info, pdev);
1554	if (ret) {
1555		dev_err(dev, "cannot initialise SM501\n");
1556		goto sm501fb_start_fail;
1557	}
1558
1559	/* CRT framebuffer setup */
1560
1561	ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt);
1562	if (ret) {
1563		dev_err(dev, "cannot initialise CRT fb\n");
1564		goto sm501fb_start_fail;
1565	}
1566
1567	/* Panel framebuffer setup */
1568
1569	ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl);
1570	if (ret) {
1571		dev_err(dev, "cannot initialise Panel fb\n");
1572		goto sm501fb_start_fail;
1573	}
1574
1575	/* register framebuffers */
1576
1577	ret = register_framebuffer(fbinfo_crt);
1578	if (ret < 0) {
1579		dev_err(dev, "failed to register CRT fb (%d)\n", ret);
1580		goto register_crt_fail;
1581	}
1582
1583	ret = register_framebuffer(fbinfo_pnl);
1584	if (ret < 0) {
1585		dev_err(dev, "failed to register panel fb (%d)\n", ret);
1586		goto register_pnl_fail;
1587	}
1588
1589	dev_info(dev, "fb%d: %s frame buffer device\n",
1590		 fbinfo_crt->node, fbinfo_crt->fix.id);
1591
1592	dev_info(dev, "fb%d: %s frame buffer device\n",
1593	       fbinfo_pnl->node, fbinfo_pnl->fix.id);
1594
1595	/* create device files */
1596
1597	ret = device_create_file(dev, &dev_attr_crt_src);
1598	if (ret)
1599		goto crtsrc_fail;
1600
1601	ret = device_create_file(dev, &dev_attr_fbregs_pnl);
1602	if (ret)
1603		goto fbregs_pnl_fail;
1604
1605	ret = device_create_file(dev, &dev_attr_fbregs_crt);
1606	if (ret)
1607		goto fbregs_crt_fail;
1608
1609	/* we registered, return ok */
1610	return 0;
1611
1612 fbregs_crt_fail:
1613	device_remove_file(dev, &dev_attr_fbregs_pnl);
1614
1615 fbregs_pnl_fail:
1616	device_remove_file(dev, &dev_attr_crt_src);
1617
1618 crtsrc_fail:
1619	unregister_framebuffer(fbinfo_pnl);
1620
1621 register_pnl_fail:
1622	unregister_framebuffer(fbinfo_crt);
1623
1624 register_crt_fail:
1625	sm501fb_stop(info);
1626
1627 sm501fb_start_fail:
1628	sm501fb_info_release(info);
1629
1630 sm501fb_alloc_fail:
1631	framebuffer_release(fbinfo_pnl);
1632
1633 fbinfo_crt_alloc_fail:
1634	framebuffer_release(fbinfo_crt);
1635
1636	return ret;
1637}
1638
1639
1640/*
1641 *  Cleanup
1642 */
1643static int sm501fb_remove(struct platform_device *pdev)
1644{
1645	struct sm501fb_info *info = platform_get_drvdata(pdev);
1646	struct fb_info	   *fbinfo_crt = info->fb[0];
1647	struct fb_info	   *fbinfo_pnl = info->fb[1];
1648
1649	device_remove_file(&pdev->dev, &dev_attr_fbregs_crt);
1650	device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
1651	device_remove_file(&pdev->dev, &dev_attr_crt_src);
1652
1653	unregister_framebuffer(fbinfo_crt);
1654	unregister_framebuffer(fbinfo_pnl);
1655
1656	sm501fb_stop(info);
1657	sm501fb_info_release(info);
1658
1659	framebuffer_release(fbinfo_pnl);
1660	framebuffer_release(fbinfo_crt);
1661
1662	return 0;
1663}
1664
1665#ifdef CONFIG_PM
1666
1667static int sm501fb_suspend_fb(struct sm501fb_info *info,
1668			      enum sm501_controller head)
1669{
1670	struct fb_info *fbi = info->fb[head];
1671	struct sm501fb_par *par = fbi->par;
1672
1673	if (par->screen.size == 0)
1674		return 0;
1675
1676	/* backup copies in case chip is powered down over suspend */
1677
1678	par->store_fb = vmalloc(par->screen.size);
1679	if (par->store_fb == NULL) {
1680		dev_err(info->dev, "no memory to store screen\n");
1681		return -ENOMEM;
1682	}
1683
1684	par->store_cursor = vmalloc(par->cursor.size);
1685	if (par->store_cursor == NULL) {
1686		dev_err(info->dev, "no memory to store cursor\n");
1687		goto err_nocursor;
1688	}
1689
1690	memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
1691	memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
1692
1693	/* blank the relevant interface to ensure unit power minimised */
1694	(par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
1695
1696	return 0;
1697
1698 err_nocursor:
1699	vfree(par->store_fb);
1700
1701	return -ENOMEM;
1702
1703}
1704
1705static void sm501fb_resume_fb(struct sm501fb_info *info,
1706			      enum sm501_controller head)
1707{
1708	struct fb_info *fbi = info->fb[head];
1709	struct sm501fb_par *par = fbi->par;
1710
1711	if (par->screen.size == 0)
1712		return;
1713
1714	/* re-activate the configuration */
1715
1716	(par->ops.fb_set_par)(fbi);
1717
1718	/* restore the data */
1719
1720	memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size);
1721	memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size);
1722
1723	vfree(par->store_fb);
1724	vfree(par->store_cursor);
1725}
1726
1727
1728/* suspend and resume support */
1729
1730static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
1731{
1732	struct sm501fb_info *info = platform_get_drvdata(pdev);
1733
1734	sm501fb_suspend_fb(info, HEAD_CRT);
1735	sm501fb_suspend_fb(info, HEAD_PANEL);
1736
1737	/* turn off the clocks, in case the device is not powered down */
1738	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
1739
1740	return 0;
1741}
1742
1743static int sm501fb_resume(struct platform_device *pdev)
1744{
1745	struct sm501fb_info *info = platform_get_drvdata(pdev);
1746
1747	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
1748
1749	sm501fb_resume_fb(info, HEAD_CRT);
1750	sm501fb_resume_fb(info, HEAD_PANEL);
1751
1752	return 0;
1753}
1754
1755#else
1756#define sm501fb_suspend NULL
1757#define sm501fb_resume  NULL
1758#endif
1759
1760static struct platform_driver sm501fb_driver = {
1761	.probe		= sm501fb_probe,
1762	.remove		= sm501fb_remove,
1763	.suspend	= sm501fb_suspend,
1764	.resume		= sm501fb_resume,
1765	.driver		= {
1766		.name	= "sm501-fb",
1767		.owner	= THIS_MODULE,
1768	},
1769};
1770
1771static int __devinit sm501fb_init(void)
1772{
1773	return platform_driver_register(&sm501fb_driver);
1774}
1775
1776static void __exit sm501fb_cleanup(void)
1777{
1778	platform_driver_unregister(&sm501fb_driver);
1779}
1780
1781module_init(sm501fb_init);
1782module_exit(sm501fb_cleanup);
1783
1784MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
1785MODULE_DESCRIPTION("SM501 Framebuffer driver");
1786MODULE_LICENSE("GPL v2");
1787