• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* drivers/video/s1d13xxxfb.c
2  *
3  * (c) 2004 Simtec Electronics
4  * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
5  *
6  * Driver for Epson S1D13xxx series framebuffer chips
7  *
8  * Adapted from
9  *  linux/drivers/video/skeletonfb.c
10  *  linux/drivers/video/epson1355fb.c
11  *  linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
12  *
13  * Note, currently only tested on S1D13806 with 16bit CRT.
14  * As such, this driver might still contain some hardcoded bits relating to
15  * S1D13806.
16  * Making it work on other S1D13XXX chips should merely be a matter of adding
17  * a few switch()s, some missing glue here and there maybe, and split header
18  * files.
19  *
20  * TODO: - handle dual screen display (CRT and LCD at the same time).
21  *	 - check_var(), mode change, etc.
22  *	 - PM untested.
23  *	 - Accelerated interfaces.
24  *	 - Probably not SMP safe :)
25  *
26  * This file is subject to the terms and conditions of the GNU General Public
27  * License. See the file COPYING in the main directory of this archive for
28  * more details.
29  */
30 
31 #include <linux/module.h>
32 #include <linux/platform_device.h>
33 #include <linux/delay.h>
34 
35 #include <linux/types.h>
36 #include <linux/errno.h>
37 #include <linux/mm.h>
38 #include <linux/mman.h>
39 #include <linux/fb.h>
40 
41 #include <asm/io.h>
42 
43 #include <video/s1d13xxxfb.h>
44 
45 #define PFX "s1d13xxxfb: "
46 
47 #if 0
48 #define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
49 #else
50 #define dbg(fmt, args...) do { } while (0)
51 #endif
52 
53 static const int __devinitconst s1d13xxxfb_revisions[] = {
54 	S1D13506_CHIP_REV,	/* Rev.4 on HP Jornada 7xx S1D13506 */
55 	S1D13806_CHIP_REV,	/* Rev.7 on .. */
56 };
57 
58 /*
59  * Here we define the default struct fb_fix_screeninfo
60  */
61 static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
62 	.id		= S1D_FBID,
63 	.type		= FB_TYPE_PACKED_PIXELS,
64 	.visual		= FB_VISUAL_PSEUDOCOLOR,
65 	.xpanstep	= 0,
66 	.ypanstep	= 1,
67 	.ywrapstep	= 0,
68 	.accel		= FB_ACCEL_NONE,
69 };
70 
71 static inline u8
s1d13xxxfb_readreg(struct s1d13xxxfb_par * par,u16 regno)72 s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
73 {
74 #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
75 	regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
76 #endif
77 	return readb(par->regs + regno);
78 }
79 
80 static inline void
s1d13xxxfb_writereg(struct s1d13xxxfb_par * par,u16 regno,u8 value)81 s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
82 {
83 #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
84 	regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
85 #endif
86 	writeb(value, par->regs + regno);
87 }
88 
89 static inline void
s1d13xxxfb_runinit(struct s1d13xxxfb_par * par,const struct s1d13xxxfb_regval * initregs,const unsigned int size)90 s1d13xxxfb_runinit(struct s1d13xxxfb_par *par,
91 			const struct s1d13xxxfb_regval *initregs,
92 			const unsigned int size)
93 {
94 	int i;
95 
96 	for (i = 0; i < size; i++) {
97         	if ((initregs[i].addr == S1DREG_DELAYOFF) ||
98 				(initregs[i].addr == S1DREG_DELAYON))
99 			mdelay((int)initregs[i].value);
100         	else {
101 			s1d13xxxfb_writereg(par, initregs[i].addr, initregs[i].value);
102 		}
103         }
104 
105 	/* make sure the hardware can cope with us */
106 	mdelay(1);
107 }
108 
109 static inline void
lcd_enable(struct s1d13xxxfb_par * par,int enable)110 lcd_enable(struct s1d13xxxfb_par *par, int enable)
111 {
112 	u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
113 
114 	if (enable)
115 		mode |= 0x01;
116 	else
117 		mode &= ~0x01;
118 
119 	s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
120 }
121 
122 static inline void
crt_enable(struct s1d13xxxfb_par * par,int enable)123 crt_enable(struct s1d13xxxfb_par *par, int enable)
124 {
125 	u8 mode = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
126 
127 	if (enable)
128 		mode |= 0x02;
129 	else
130 		mode &= ~0x02;
131 
132 	s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
133 }
134 
135 /* framebuffer control routines */
136 
137 static inline void
s1d13xxxfb_setup_pseudocolour(struct fb_info * info)138 s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
139 {
140 	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
141 
142 	info->var.red.length = 4;
143 	info->var.green.length = 4;
144 	info->var.blue.length = 4;
145 }
146 
147 static inline void
s1d13xxxfb_setup_truecolour(struct fb_info * info)148 s1d13xxxfb_setup_truecolour(struct fb_info *info)
149 {
150 	info->fix.visual = FB_VISUAL_TRUECOLOR;
151 	info->var.bits_per_pixel = 16;
152 
153 	info->var.red.length = 5;
154 	info->var.red.offset = 11;
155 
156 	info->var.green.length = 6;
157 	info->var.green.offset = 5;
158 
159 	info->var.blue.length = 5;
160 	info->var.blue.offset = 0;
161 }
162 
163 /**
164  *      s1d13xxxfb_set_par - Alters the hardware state.
165  *      @info: frame buffer structure
166  *
167  *	Using the fb_var_screeninfo in fb_info we set the depth of the
168  *	framebuffer. This function alters the par AND the
169  *	fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
170  *	fb_info since we are using that data. This means we depend on the
171  *	data in var inside fb_info to be supported by the hardware.
172  *	xxxfb_check_var is always called before xxxfb_set_par to ensure this.
173  *
174  *	XXX TODO: write proper s1d13xxxfb_check_var(), without which that
175  *	function is quite useless.
176  */
177 static int
s1d13xxxfb_set_par(struct fb_info * info)178 s1d13xxxfb_set_par(struct fb_info *info)
179 {
180 	struct s1d13xxxfb_par *s1dfb = info->par;
181 	unsigned int val;
182 
183 	dbg("s1d13xxxfb_set_par: bpp=%d\n", info->var.bits_per_pixel);
184 
185 	if ((s1dfb->display & 0x01))	/* LCD */
186 		val = s1d13xxxfb_readreg(s1dfb, S1DREG_LCD_DISP_MODE);   /* read colour control */
187 	else	/* CRT */
188 		val = s1d13xxxfb_readreg(s1dfb, S1DREG_CRT_DISP_MODE);   /* read colour control */
189 
190 	val &= ~0x07;
191 
192 	switch (info->var.bits_per_pixel) {
193 		case 4:
194 			dbg("pseudo colour 4\n");
195 			s1d13xxxfb_setup_pseudocolour(info);
196 			val |= 2;
197 			break;
198 		case 8:
199 			dbg("pseudo colour 8\n");
200 			s1d13xxxfb_setup_pseudocolour(info);
201 			val |= 3;
202 			break;
203 		case 16:
204 			dbg("true colour\n");
205 			s1d13xxxfb_setup_truecolour(info);
206 			val |= 5;
207 			break;
208 
209 		default:
210 			dbg("bpp not supported!\n");
211 			return -EINVAL;
212 	}
213 
214 	dbg("writing %02x to display mode register\n", val);
215 
216 	if ((s1dfb->display & 0x01))	/* LCD */
217 		s1d13xxxfb_writereg(s1dfb, S1DREG_LCD_DISP_MODE, val);
218 	else	/* CRT */
219 		s1d13xxxfb_writereg(s1dfb, S1DREG_CRT_DISP_MODE, val);
220 
221 	info->fix.line_length  = info->var.xres * info->var.bits_per_pixel;
222 	info->fix.line_length /= 8;
223 
224 	dbg("setting line_length to %d\n", info->fix.line_length);
225 
226 	dbg("done setup\n");
227 
228 	return 0;
229 }
230 
231 /**
232  *  	s1d13xxxfb_setcolreg - sets a color register.
233  *      @regno: Which register in the CLUT we are programming
234  *      @red: The red value which can be up to 16 bits wide
235  *	@green: The green value which can be up to 16 bits wide
236  *	@blue:  The blue value which can be up to 16 bits wide.
237  *	@transp: If supported the alpha value which can be up to 16 bits wide.
238  *      @info: frame buffer info structure
239  *
240  *	Returns negative errno on error, or zero on success.
241  */
242 static int
s1d13xxxfb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)243 s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
244 			u_int transp, struct fb_info *info)
245 {
246 	struct s1d13xxxfb_par *s1dfb = info->par;
247 	unsigned int pseudo_val;
248 
249 	if (regno >= S1D_PALETTE_SIZE)
250 		return -EINVAL;
251 
252 	dbg("s1d13xxxfb_setcolreg: %d: rgb=%d,%d,%d, tr=%d\n",
253 		    regno, red, green, blue, transp);
254 
255 	if (info->var.grayscale)
256 		red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16;
257 
258 	switch (info->fix.visual) {
259 		case FB_VISUAL_TRUECOLOR:
260 			if (regno >= 16)
261 				return -EINVAL;
262 
263 			/* deal with creating pseudo-palette entries */
264 
265 			pseudo_val  = (red   >> 11) << info->var.red.offset;
266 			pseudo_val |= (green >> 10) << info->var.green.offset;
267 			pseudo_val |= (blue  >> 11) << info->var.blue.offset;
268 
269 			dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
270 				    regno, pseudo_val);
271 
272 #if defined(CONFIG_PLAT_MAPPI)
273 			((u32 *)info->pseudo_palette)[regno] = cpu_to_le16(pseudo_val);
274 #else
275 			((u32 *)info->pseudo_palette)[regno] = pseudo_val;
276 #endif
277 
278 			break;
279 		case FB_VISUAL_PSEUDOCOLOR:
280 			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_ADDR, regno);
281 			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, red);
282 			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, green);
283 			s1d13xxxfb_writereg(s1dfb, S1DREG_LKUP_DATA, blue);
284 
285 			break;
286 		default:
287 			return -ENOSYS;
288 	}
289 
290 	dbg("s1d13xxxfb_setcolreg: done\n");
291 
292 	return 0;
293 }
294 
295 /**
296  *      s1d13xxxfb_blank - blanks the display.
297  *      @blank_mode: the blank mode we want.
298  *      @info: frame buffer structure that represents a single frame buffer
299  *
300  *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
301  *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a
302  *      video mode which doesn't support it. Implements VESA suspend
303  *      and powerdown modes on hardware that supports disabling hsync/vsync:
304  *      blank_mode == 2: suspend vsync
305  *      blank_mode == 3: suspend hsync
306  *      blank_mode == 4: powerdown
307  *
308  *      Returns negative errno on error, or zero on success.
309  */
310 static int
s1d13xxxfb_blank(int blank_mode,struct fb_info * info)311 s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
312 {
313 	struct s1d13xxxfb_par *par = info->par;
314 
315 	dbg("s1d13xxxfb_blank: blank=%d, info=%p\n", blank_mode, info);
316 
317 	switch (blank_mode) {
318 		case FB_BLANK_UNBLANK:
319 		case FB_BLANK_NORMAL:
320 			if ((par->display & 0x01) != 0)
321 				lcd_enable(par, 1);
322 			if ((par->display & 0x02) != 0)
323 				crt_enable(par, 1);
324 			break;
325 		case FB_BLANK_VSYNC_SUSPEND:
326 		case FB_BLANK_HSYNC_SUSPEND:
327 			break;
328 		case FB_BLANK_POWERDOWN:
329 			lcd_enable(par, 0);
330 			crt_enable(par, 0);
331 			break;
332 		default:
333 			return -EINVAL;
334 	}
335 
336 	/* let fbcon do a soft blank for us */
337 	return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
338 }
339 
340 /**
341  *      s1d13xxxfb_pan_display - Pans the display.
342  *      @var: frame buffer variable screen structure
343  *      @info: frame buffer structure that represents a single frame buffer
344  *
345  *	Pan (or wrap, depending on the `vmode' field) the display using the
346  *  	`yoffset' field of the `var' structure (`xoffset'  not yet supported).
347  *  	If the values don't fit, return -EINVAL.
348  *
349  *      Returns negative errno on error, or zero on success.
350  */
351 static int
s1d13xxxfb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)352 s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
353 {
354 	struct s1d13xxxfb_par *par = info->par;
355 	u32 start;
356 
357 	if (var->xoffset != 0)	/* not yet ... */
358 		return -EINVAL;
359 
360 	if (var->yoffset + info->var.yres > info->var.yres_virtual)
361 		return -EINVAL;
362 
363 	start = (info->fix.line_length >> 1) * var->yoffset;
364 
365 	if ((par->display & 0x01)) {
366 		/* LCD */
367 		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START0, (start & 0xff));
368 		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START1, ((start >> 8) & 0xff));
369 		s1d13xxxfb_writereg(par, S1DREG_LCD_DISP_START2, ((start >> 16) & 0x0f));
370 	} else {
371 		/* CRT */
372 		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START0, (start & 0xff));
373 		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START1, ((start >> 8) & 0xff));
374 		s1d13xxxfb_writereg(par, S1DREG_CRT_DISP_START2, ((start >> 16) & 0x0f));
375 	}
376 
377 	return 0;
378 }
379 
380 
381 /* framebuffer information structures */
382 
383 static struct fb_ops s1d13xxxfb_fbops = {
384 	.owner		= THIS_MODULE,
385 	.fb_set_par	= s1d13xxxfb_set_par,
386 	.fb_setcolreg	= s1d13xxxfb_setcolreg,
387 	.fb_blank	= s1d13xxxfb_blank,
388 
389 	.fb_pan_display	= s1d13xxxfb_pan_display,
390 
391 	/* to be replaced by any acceleration we can */
392 	.fb_fillrect	= cfb_fillrect,
393 	.fb_copyarea	= cfb_copyarea,
394 	.fb_imageblit	= cfb_imageblit,
395 };
396 
397 static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
398 	{4, 8, 16, -1},
399 	{9, 12, 18, -1},
400 };
401 
402 /**
403  *      s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
404  *	hardware setup.
405  *      @info: frame buffer structure
406  *
407  *	We setup the framebuffer structures according to the current
408  *	hardware setup. On some machines, the BIOS will have filled
409  *	the chip registers with such info, on others, these values will
410  *	have been written in some init procedure. In any case, the
411  *	software values needs to match the hardware ones. This is what
412  *	this function ensures.
413  *
414  *	Note: some of the hardcoded values here might need some love to
415  *	work on various chips, and might need to no longer be hardcoded.
416  */
417 static void __devinit
s1d13xxxfb_fetch_hw_state(struct fb_info * info)418 s1d13xxxfb_fetch_hw_state(struct fb_info *info)
419 {
420 	struct fb_var_screeninfo *var = &info->var;
421 	struct fb_fix_screeninfo *fix = &info->fix;
422 	struct s1d13xxxfb_par *par = info->par;
423 	u8 panel, display;
424 	u16 offset;
425 	u32 xres, yres;
426 	u32 xres_virtual, yres_virtual;
427 	int bpp, lcd_bpp;
428 	int is_color, is_dual, is_tft;
429 	int lcd_enabled, crt_enabled;
430 
431 	fix->type = FB_TYPE_PACKED_PIXELS;
432 
433 	/* general info */
434 	par->display = s1d13xxxfb_readreg(par, S1DREG_COM_DISP_MODE);
435 	crt_enabled = (par->display & 0x02) != 0;
436 	lcd_enabled = (par->display & 0x01) != 0;
437 
438 	if (lcd_enabled && crt_enabled)
439 		printk(KERN_WARNING PFX "Warning: LCD and CRT detected, using LCD\n");
440 
441 	if (lcd_enabled)
442 		display = s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_MODE);
443 	else	/* CRT */
444 		display = s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_MODE);
445 
446 	bpp = display & 0x07;
447 
448 	switch (bpp) {
449 		case 2:	/* 4 bpp */
450 		case 3:	/* 8 bpp */
451 			var->bits_per_pixel = 8;
452 			var->red.offset = var->green.offset = var->blue.offset = 0;
453 			var->red.length = var->green.length = var->blue.length = 8;
454 			break;
455 		case 5:	/* 16 bpp */
456 			s1d13xxxfb_setup_truecolour(info);
457 			break;
458 		default:
459 			dbg("bpp: %i\n", bpp);
460 	}
461 	fb_alloc_cmap(&info->cmap, 256, 0);
462 
463 	/* LCD info */
464 	panel = s1d13xxxfb_readreg(par, S1DREG_PANEL_TYPE);
465 	is_color = (panel & 0x04) != 0;
466 	is_dual = (panel & 0x02) != 0;
467 	is_tft = (panel & 0x01) != 0;
468 	lcd_bpp = s1d13xxxfb_width_tab[is_tft][(panel >> 4) & 3];
469 
470 	if (lcd_enabled) {
471 		xres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_HWIDTH) + 1) * 8;
472 		yres = (s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT0) +
473 			((s1d13xxxfb_readreg(par, S1DREG_LCD_DISP_VHEIGHT1) & 0x03) << 8) + 1);
474 
475 		offset = (s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF0) +
476 			((s1d13xxxfb_readreg(par, S1DREG_LCD_MEM_OFF1) & 0x7) << 8));
477 	} else { /* crt */
478 		xres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_HWIDTH) + 1) * 8;
479 		yres = (s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT0) +
480 			((s1d13xxxfb_readreg(par, S1DREG_CRT_DISP_VHEIGHT1) & 0x03) << 8) + 1);
481 
482 		offset = (s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF0) +
483 			((s1d13xxxfb_readreg(par, S1DREG_CRT_MEM_OFF1) & 0x7) << 8));
484 	}
485 	xres_virtual = offset * 16 / var->bits_per_pixel;
486 	yres_virtual = fix->smem_len / (offset * 2);
487 
488 	var->xres		= xres;
489 	var->yres		= yres;
490 	var->xres_virtual	= xres_virtual;
491 	var->yres_virtual	= yres_virtual;
492 	var->xoffset		= var->yoffset = 0;
493 
494 	fix->line_length	= offset * 2;
495 
496 	var->grayscale		= !is_color;
497 
498 	var->activate		= FB_ACTIVATE_NOW;
499 
500 	dbg(PFX "bpp=%d, lcd_bpp=%d, "
501 		"crt_enabled=%d, lcd_enabled=%d\n",
502 		var->bits_per_pixel, lcd_bpp, crt_enabled, lcd_enabled);
503 	dbg(PFX "xres=%d, yres=%d, vxres=%d, vyres=%d "
504 		"is_color=%d, is_dual=%d, is_tft=%d\n",
505 		xres, yres, xres_virtual, yres_virtual, is_color, is_dual, is_tft);
506 }
507 
508 
509 static int
s1d13xxxfb_remove(struct platform_device * pdev)510 s1d13xxxfb_remove(struct platform_device *pdev)
511 {
512 	struct fb_info *info = platform_get_drvdata(pdev);
513 	struct s1d13xxxfb_par *par = NULL;
514 
515 	if (info) {
516 		par = info->par;
517 		if (par && par->regs) {
518 			/* disable output & enable powersave */
519 			s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, 0x00);
520 			s1d13xxxfb_writereg(par, S1DREG_PS_CNF, 0x11);
521 			iounmap(par->regs);
522 		}
523 
524 		fb_dealloc_cmap(&info->cmap);
525 
526 		if (info->screen_base)
527 			iounmap(info->screen_base);
528 
529 		framebuffer_release(info);
530 	}
531 
532 	release_mem_region(pdev->resource[0].start,
533 			pdev->resource[0].end - pdev->resource[0].start +1);
534 	release_mem_region(pdev->resource[1].start,
535 			pdev->resource[1].end - pdev->resource[1].start +1);
536 	return 0;
537 }
538 
539 static int __devinit
s1d13xxxfb_probe(struct platform_device * pdev)540 s1d13xxxfb_probe(struct platform_device *pdev)
541 {
542 	struct s1d13xxxfb_par *default_par;
543 	struct fb_info *info;
544 	struct s1d13xxxfb_pdata *pdata = NULL;
545 	int ret = 0;
546 	int i;
547 	u8 revision;
548 
549 	dbg("probe called: device is %p\n", pdev);
550 
551 	printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
552 
553 	/* enable platform-dependent hardware glue, if any */
554 	if (pdev->dev.platform_data)
555 		pdata = pdev->dev.platform_data;
556 
557 	if (pdata && pdata->platform_init_video)
558 		pdata->platform_init_video();
559 
560 
561 	if (pdev->num_resources != 2) {
562 		dev_err(&pdev->dev, "invalid num_resources: %i\n",
563 		       pdev->num_resources);
564 		ret = -ENODEV;
565 		goto bail;
566 	}
567 
568 	/* resource[0] is VRAM, resource[1] is registers */
569 	if (pdev->resource[0].flags != IORESOURCE_MEM
570 			|| pdev->resource[1].flags != IORESOURCE_MEM) {
571 		dev_err(&pdev->dev, "invalid resource type\n");
572 		ret = -ENODEV;
573 		goto bail;
574 	}
575 
576 	if (!request_mem_region(pdev->resource[0].start,
577 		pdev->resource[0].end - pdev->resource[0].start +1, "s1d13xxxfb mem")) {
578 		dev_dbg(&pdev->dev, "request_mem_region failed\n");
579 		ret = -EBUSY;
580 		goto bail;
581 	}
582 
583 	if (!request_mem_region(pdev->resource[1].start,
584 		pdev->resource[1].end - pdev->resource[1].start +1, "s1d13xxxfb regs")) {
585 		dev_dbg(&pdev->dev, "request_mem_region failed\n");
586 		ret = -EBUSY;
587 		goto bail;
588 	}
589 
590 	info = framebuffer_alloc(sizeof(struct s1d13xxxfb_par) + sizeof(u32) * 256, &pdev->dev);
591 	if (!info) {
592 		ret = -ENOMEM;
593 		goto bail;
594 	}
595 
596 	platform_set_drvdata(pdev, info);
597 	default_par = info->par;
598 	default_par->regs = ioremap_nocache(pdev->resource[1].start,
599 			pdev->resource[1].end - pdev->resource[1].start +1);
600 	if (!default_par->regs) {
601 		printk(KERN_ERR PFX "unable to map registers\n");
602 		ret = -ENOMEM;
603 		goto bail;
604 	}
605 	info->pseudo_palette = default_par->pseudo_palette;
606 
607 	info->screen_base = ioremap_nocache(pdev->resource[0].start,
608 			pdev->resource[0].end - pdev->resource[0].start +1);
609 
610 	if (!info->screen_base) {
611 		printk(KERN_ERR PFX "unable to map framebuffer\n");
612 		ret = -ENOMEM;
613 		goto bail;
614 	}
615 
616 	revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
617 
618 	ret = -ENODEV;
619 
620 	for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) {
621 		if (revision == s1d13xxxfb_revisions[i])
622 			ret = 0;
623 	}
624 
625 	if (!ret)
626 		printk(KERN_INFO PFX "chip revision %i\n", revision);
627 	else {
628 		printk(KERN_INFO PFX "unknown chip revision %i\n", revision);
629 		goto bail;
630 	}
631 
632 	info->fix = s1d13xxxfb_fix;
633 	info->fix.mmio_start = pdev->resource[1].start;
634 	info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1;
635 	info->fix.smem_start = pdev->resource[0].start;
636 	info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1;
637 
638 	printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
639 	       default_par->regs, info->fix.smem_len / 1024, info->screen_base);
640 
641 	info->par = default_par;
642 	info->fbops = &s1d13xxxfb_fbops;
643 	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
644 
645 	/* perform "manual" chip initialization, if needed */
646 	if (pdata && pdata->initregs)
647 		s1d13xxxfb_runinit(info->par, pdata->initregs, pdata->initregssize);
648 
649 	s1d13xxxfb_fetch_hw_state(info);
650 
651 	if (register_framebuffer(info) < 0) {
652 		ret = -EINVAL;
653 		goto bail;
654 	}
655 
656 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
657 	       info->node, info->fix.id);
658 
659 	return 0;
660 
661 bail:
662 	s1d13xxxfb_remove(pdev);
663 	return ret;
664 
665 }
666 
667 #ifdef CONFIG_PM
s1d13xxxfb_suspend(struct platform_device * dev,pm_message_t state)668 static int s1d13xxxfb_suspend(struct platform_device *dev, pm_message_t state)
669 {
670 	struct fb_info *info = platform_get_drvdata(dev);
671 	struct s1d13xxxfb_par *s1dfb = info->par;
672 	struct s1d13xxxfb_pdata *pdata = NULL;
673 
674 	/* disable display */
675 	lcd_enable(s1dfb, 0);
676 	crt_enable(s1dfb, 0);
677 
678 	if (dev->dev.platform_data)
679 		pdata = dev->dev.platform_data;
680 
681 #if 0
682 	if (!s1dfb->disp_save)
683 		s1dfb->disp_save = kmalloc(info->fix.smem_len, GFP_KERNEL);
684 
685 	if (!s1dfb->disp_save) {
686 		printk(KERN_ERR PFX "no memory to save screen");
687 		return -ENOMEM;
688 	}
689 
690 	memcpy_fromio(s1dfb->disp_save, info->screen_base, info->fix.smem_len);
691 #else
692 	s1dfb->disp_save = NULL;
693 #endif
694 
695 	if (!s1dfb->regs_save)
696 		s1dfb->regs_save = kmalloc(info->fix.mmio_len, GFP_KERNEL);
697 
698 	if (!s1dfb->regs_save) {
699 		printk(KERN_ERR PFX "no memory to save registers");
700 		return -ENOMEM;
701 	}
702 
703 	/* backup all registers */
704 	memcpy_fromio(s1dfb->regs_save, s1dfb->regs, info->fix.mmio_len);
705 
706 	/* now activate power save mode */
707 	s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x11);
708 
709 	if (pdata && pdata->platform_suspend_video)
710 		return pdata->platform_suspend_video();
711 	else
712 		return 0;
713 }
714 
s1d13xxxfb_resume(struct platform_device * dev)715 static int s1d13xxxfb_resume(struct platform_device *dev)
716 {
717 	struct fb_info *info = platform_get_drvdata(dev);
718 	struct s1d13xxxfb_par *s1dfb = info->par;
719 	struct s1d13xxxfb_pdata *pdata = NULL;
720 
721 	/* awaken the chip */
722 	s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10);
723 
724 	/* do not let go until SDRAM "wakes up" */
725 	while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
726 		udelay(10);
727 
728 	if (dev->dev.platform_data)
729 		pdata = dev->dev.platform_data;
730 
731 	if (s1dfb->regs_save) {
732 		/* will write RO regs, *should* get away with it :) */
733 		memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len);
734 		kfree(s1dfb->regs_save);
735 	}
736 
737 	if (s1dfb->disp_save) {
738 		memcpy_toio(info->screen_base, s1dfb->disp_save,
739 				info->fix.smem_len);
740 		kfree(s1dfb->disp_save);	/* XXX kmalloc()'d when? */
741 	}
742 
743 	if ((s1dfb->display & 0x01) != 0)
744 		lcd_enable(s1dfb, 1);
745 	if ((s1dfb->display & 0x02) != 0)
746 		crt_enable(s1dfb, 1);
747 
748 	if (pdata && pdata->platform_resume_video)
749 		return pdata->platform_resume_video();
750 	else
751 		return 0;
752 }
753 #endif /* CONFIG_PM */
754 
755 static struct platform_driver s1d13xxxfb_driver = {
756 	.probe		= s1d13xxxfb_probe,
757 	.remove		= s1d13xxxfb_remove,
758 #ifdef CONFIG_PM
759 	.suspend	= s1d13xxxfb_suspend,
760 	.resume		= s1d13xxxfb_resume,
761 #endif
762 	.driver		= {
763 		.name	= S1D_DEVICENAME,
764 	},
765 };
766 
767 
768 static int __init
s1d13xxxfb_init(void)769 s1d13xxxfb_init(void)
770 {
771 
772 #ifndef MODULE
773 	if (fb_get_options("s1d13xxxfb", NULL))
774 		return -ENODEV;
775 #endif
776 
777 	return platform_driver_register(&s1d13xxxfb_driver);
778 }
779 
780 
781 static void __exit
s1d13xxxfb_exit(void)782 s1d13xxxfb_exit(void)
783 {
784 	platform_driver_unregister(&s1d13xxxfb_driver);
785 }
786 
787 module_init(s1d13xxxfb_init);
788 module_exit(s1d13xxxfb_exit);
789 
790 
791 MODULE_LICENSE("GPL");
792 MODULE_DESCRIPTION("Framebuffer driver for S1D13xxx devices");
793 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Thibaut VARENE <varenet@parisc-linux.org>");
794