• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/video/
1/*
2 * Xilinx TFT frame buffer driver
3 *
4 * Author: MontaVista Software, Inc.
5 *         source@mvista.com
6 *
7 * 2002-2007 (c) MontaVista Software, Inc.
8 * 2007 (c) Secret Lab Technologies, Ltd.
9 * 2009 (c) Xilinx Inc.
10 *
11 * This file is licensed under the terms of the GNU General Public License
12 * version 2.  This program is licensed "as is" without any warranty of any
13 * kind, whether express or implied.
14 */
15
16/*
17 * This driver was based on au1100fb.c by MontaVista rewritten for 2.6
18 * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn
19 * was based on skeletonfb.c, Skeleton for a frame buffer device by
20 * Geert Uytterhoeven.
21 */
22
23#include <linux/device.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/version.h>
27#include <linux/errno.h>
28#include <linux/string.h>
29#include <linux/mm.h>
30#include <linux/fb.h>
31#include <linux/init.h>
32#include <linux/dma-mapping.h>
33#include <linux/of_device.h>
34#include <linux/of_platform.h>
35#include <linux/io.h>
36#include <linux/xilinxfb.h>
37#include <linux/slab.h>
38#include <asm/dcr.h>
39
40#define DRIVER_NAME		"xilinxfb"
41
42
43/*
44 * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for
45 * the VGA port on the Xilinx ML40x board. This is a hardware display
46 * controller for a 640x480 resolution TFT or VGA screen.
47 *
48 * The interface to the framebuffer is nice and simple.  There are two
49 * control registers.  The first tells the LCD interface where in memory
50 * the frame buffer is (only the 11 most significant bits are used, so
51 * don't start thinking about scrolling).  The second allows the LCD to
52 * be turned on or off as well as rotated 180 degrees.
53 *
54 * In case of direct PLB access the second control register will be at
55 * an offset of 4 as compared to the DCR access where the offset is 1
56 * i.e. REG_CTRL. So this is taken care in the function
57 * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of
58 * direct PLB access.
59 */
60#define NUM_REGS	2
61#define REG_FB_ADDR	0
62#define REG_CTRL	1
63#define REG_CTRL_ENABLE	 0x0001
64#define REG_CTRL_ROTATE	 0x0002
65
66/*
67 * The hardware only handles a single mode: 640x480 24 bit true
68 * color. Each pixel gets a word (32 bits) of memory.  Within each word,
69 * the 8 most significant bits are ignored, the next 8 bits are the red
70 * level, the next 8 bits are the green level and the 8 least
71 * significant bits are the blue level.  Each row of the LCD uses 1024
72 * words, but only the first 640 pixels are displayed with the other 384
73 * words being ignored.  There are 480 rows.
74 */
75#define BYTES_PER_PIXEL	4
76#define BITS_PER_PIXEL	(BYTES_PER_PIXEL * 8)
77
78#define RED_SHIFT	16
79#define GREEN_SHIFT	8
80#define BLUE_SHIFT	0
81
82#define PALETTE_ENTRIES_NO	16	/* passed to fb_alloc_cmap() */
83
84/*
85 * Default xilinxfb configuration
86 */
87static struct xilinxfb_platform_data xilinx_fb_default_pdata = {
88	.xres = 640,
89	.yres = 480,
90	.xvirt = 1024,
91	.yvirt = 480,
92};
93
94/*
95 * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
96 */
97static struct fb_fix_screeninfo xilinx_fb_fix = {
98	.id =		"Xilinx",
99	.type =		FB_TYPE_PACKED_PIXELS,
100	.visual =	FB_VISUAL_TRUECOLOR,
101	.accel =	FB_ACCEL_NONE
102};
103
104static struct fb_var_screeninfo xilinx_fb_var = {
105	.bits_per_pixel =	BITS_PER_PIXEL,
106
107	.red =		{ RED_SHIFT, 8, 0 },
108	.green =	{ GREEN_SHIFT, 8, 0 },
109	.blue =		{ BLUE_SHIFT, 8, 0 },
110	.transp =	{ 0, 0, 0 },
111
112	.activate =	FB_ACTIVATE_NOW
113};
114
115
116#define PLB_ACCESS_FLAG	0x1		/* 1 = PLB, 0 = DCR */
117
118struct xilinxfb_drvdata {
119
120	struct fb_info	info;		/* FB driver info record */
121
122	phys_addr_t	regs_phys;	/* phys. address of the control
123						registers */
124	void __iomem	*regs;		/* virt. address of the control
125						registers */
126
127	dcr_host_t      dcr_host;
128	unsigned int    dcr_len;
129
130	void		*fb_virt;	/* virt. address of the frame buffer */
131	dma_addr_t	fb_phys;	/* phys. address of the frame buffer */
132	int		fb_alloced;	/* Flag, was the fb memory alloced? */
133
134	u8 		flags;		/* features of the driver */
135
136	u32		reg_ctrl_default;
137
138	u32		pseudo_palette[PALETTE_ENTRIES_NO];
139					/* Fake palette of 16 colors */
140};
141
142#define to_xilinxfb_drvdata(_info) \
143	container_of(_info, struct xilinxfb_drvdata, info)
144
145/*
146 * The XPS TFT Controller can be accessed through PLB or DCR interface.
147 * To perform the read/write on the registers we need to check on
148 * which bus its connected and call the appropriate write API.
149 */
150static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset,
151				u32 val)
152{
153	if (drvdata->flags & PLB_ACCESS_FLAG)
154		out_be32(drvdata->regs + (offset << 2), val);
155	else
156		dcr_write(drvdata->dcr_host, offset, val);
157
158}
159
160static int
161xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
162	unsigned transp, struct fb_info *fbi)
163{
164	u32 *palette = fbi->pseudo_palette;
165
166	if (regno >= PALETTE_ENTRIES_NO)
167		return -EINVAL;
168
169	if (fbi->var.grayscale) {
170		/* Convert color to grayscale.
171		 * grayscale = 0.30*R + 0.59*G + 0.11*B */
172		red = green = blue =
173			(red * 77 + green * 151 + blue * 28 + 127) >> 8;
174	}
175
176	/* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */
177
178	/* We only handle 8 bits of each color. */
179	red >>= 8;
180	green >>= 8;
181	blue >>= 8;
182	palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) |
183			 (blue << BLUE_SHIFT);
184
185	return 0;
186}
187
188static int
189xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
190{
191	struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi);
192
193	switch (blank_mode) {
194	case FB_BLANK_UNBLANK:
195		/* turn on panel */
196		xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
197		break;
198
199	case FB_BLANK_NORMAL:
200	case FB_BLANK_VSYNC_SUSPEND:
201	case FB_BLANK_HSYNC_SUSPEND:
202	case FB_BLANK_POWERDOWN:
203		/* turn off panel */
204		xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
205	default:
206		break;
207
208	}
209	return 0; /* success */
210}
211
212static struct fb_ops xilinxfb_ops =
213{
214	.owner			= THIS_MODULE,
215	.fb_setcolreg		= xilinx_fb_setcolreg,
216	.fb_blank		= xilinx_fb_blank,
217	.fb_fillrect		= cfb_fillrect,
218	.fb_copyarea		= cfb_copyarea,
219	.fb_imageblit		= cfb_imageblit,
220};
221
222/* ---------------------------------------------------------------------
223 * Bus independent setup/teardown
224 */
225
226static int xilinxfb_assign(struct device *dev,
227			   struct xilinxfb_drvdata *drvdata,
228			   unsigned long physaddr,
229			   struct xilinxfb_platform_data *pdata)
230{
231	int rc;
232	int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
233
234	if (drvdata->flags & PLB_ACCESS_FLAG) {
235		/*
236		 * Map the control registers in if the controller
237		 * is on direct PLB interface.
238		 */
239		if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
240			dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
241				physaddr);
242			rc = -ENODEV;
243			goto err_region;
244		}
245
246		drvdata->regs_phys = physaddr;
247		drvdata->regs = ioremap(physaddr, 8);
248		if (!drvdata->regs) {
249			dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
250				physaddr);
251			rc = -ENODEV;
252			goto err_map;
253		}
254	}
255
256	/* Allocate the framebuffer memory */
257	if (pdata->fb_phys) {
258		drvdata->fb_phys = pdata->fb_phys;
259		drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
260	} else {
261		drvdata->fb_alloced = 1;
262		drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
263					&drvdata->fb_phys, GFP_KERNEL);
264	}
265
266	if (!drvdata->fb_virt) {
267		dev_err(dev, "Could not allocate frame buffer memory\n");
268		rc = -ENOMEM;
269		if (drvdata->flags & PLB_ACCESS_FLAG)
270			goto err_fbmem;
271		else
272			goto err_region;
273	}
274
275	/* Clear (turn to black) the framebuffer */
276	memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
277
278	/* Tell the hardware where the frame buffer is */
279	xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
280
281	/* Turn on the display */
282	drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
283	if (pdata->rotate_screen)
284		drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
285	xilinx_fb_out_be32(drvdata, REG_CTRL,
286					drvdata->reg_ctrl_default);
287
288	/* Fill struct fb_info */
289	drvdata->info.device = dev;
290	drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
291	drvdata->info.fbops = &xilinxfb_ops;
292	drvdata->info.fix = xilinx_fb_fix;
293	drvdata->info.fix.smem_start = drvdata->fb_phys;
294	drvdata->info.fix.smem_len = fbsize;
295	drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
296
297	drvdata->info.pseudo_palette = drvdata->pseudo_palette;
298	drvdata->info.flags = FBINFO_DEFAULT;
299	drvdata->info.var = xilinx_fb_var;
300	drvdata->info.var.height = pdata->screen_height_mm;
301	drvdata->info.var.width = pdata->screen_width_mm;
302	drvdata->info.var.xres = pdata->xres;
303	drvdata->info.var.yres = pdata->yres;
304	drvdata->info.var.xres_virtual = pdata->xvirt;
305	drvdata->info.var.yres_virtual = pdata->yvirt;
306
307	/* Allocate a colour map */
308	rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
309	if (rc) {
310		dev_err(dev, "Fail to allocate colormap (%d entries)\n",
311			PALETTE_ENTRIES_NO);
312		goto err_cmap;
313	}
314
315	/* Register new frame buffer */
316	rc = register_framebuffer(&drvdata->info);
317	if (rc) {
318		dev_err(dev, "Could not register frame buffer\n");
319		goto err_regfb;
320	}
321
322	if (drvdata->flags & PLB_ACCESS_FLAG) {
323		/* Put a banner in the log (for DEBUG) */
324		dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr,
325					drvdata->regs);
326	}
327	/* Put a banner in the log (for DEBUG) */
328	dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
329		(unsigned long long)drvdata->fb_phys, drvdata->fb_virt, fbsize);
330
331	return 0;	/* success */
332
333err_regfb:
334	fb_dealloc_cmap(&drvdata->info.cmap);
335
336err_cmap:
337	if (drvdata->fb_alloced)
338		dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
339			drvdata->fb_phys);
340	else
341		iounmap(drvdata->fb_virt);
342
343	/* Turn off the display */
344	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
345
346err_fbmem:
347	if (drvdata->flags & PLB_ACCESS_FLAG)
348		iounmap(drvdata->regs);
349
350err_map:
351	if (drvdata->flags & PLB_ACCESS_FLAG)
352		release_mem_region(physaddr, 8);
353
354err_region:
355	kfree(drvdata);
356	dev_set_drvdata(dev, NULL);
357
358	return rc;
359}
360
361static int xilinxfb_release(struct device *dev)
362{
363	struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
364
365#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
366	xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
367#endif
368
369	unregister_framebuffer(&drvdata->info);
370
371	fb_dealloc_cmap(&drvdata->info.cmap);
372
373	if (drvdata->fb_alloced)
374		dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
375				  drvdata->fb_virt, drvdata->fb_phys);
376	else
377		iounmap(drvdata->fb_virt);
378
379	/* Turn off the display */
380	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
381
382	/* Release the resources, as allocated based on interface */
383	if (drvdata->flags & PLB_ACCESS_FLAG) {
384		iounmap(drvdata->regs);
385		release_mem_region(drvdata->regs_phys, 8);
386	} else
387		dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
388
389	kfree(drvdata);
390	dev_set_drvdata(dev, NULL);
391
392	return 0;
393}
394
395/* ---------------------------------------------------------------------
396 * OF bus binding
397 */
398
399static int __devinit
400xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
401{
402	const u32 *prop;
403	u32 *p;
404	u32 tft_access;
405	struct xilinxfb_platform_data pdata;
406	struct resource res;
407	int size, rc, start;
408	struct xilinxfb_drvdata *drvdata;
409
410	/* Copy with the default pdata (not a ptr reference!) */
411	pdata = xilinx_fb_default_pdata;
412
413	dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match);
414
415	/* Allocate the driver data region */
416	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
417	if (!drvdata) {
418		dev_err(&op->dev, "Couldn't allocate device private record\n");
419		return -ENOMEM;
420	}
421
422	/*
423	 * To check whether the core is connected directly to DCR or PLB
424	 * interface and initialize the tft_access accordingly.
425	 */
426	p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL);
427	tft_access = p ? *p : 0;
428
429	/*
430	 * Fill the resource structure if its direct PLB interface
431	 * otherwise fill the dcr_host structure.
432	 */
433	if (tft_access) {
434		drvdata->flags |= PLB_ACCESS_FLAG;
435		rc = of_address_to_resource(op->dev.of_node, 0, &res);
436		if (rc) {
437			dev_err(&op->dev, "invalid address\n");
438			goto err;
439		}
440	} else {
441		res.start = 0;
442		start = dcr_resource_start(op->dev.of_node, 0);
443		drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
444		drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
445		if (!DCR_MAP_OK(drvdata->dcr_host)) {
446			dev_err(&op->dev, "invalid DCR address\n");
447			goto err;
448		}
449	}
450
451	prop = of_get_property(op->dev.of_node, "phys-size", &size);
452	if ((prop) && (size >= sizeof(u32)*2)) {
453		pdata.screen_width_mm = prop[0];
454		pdata.screen_height_mm = prop[1];
455	}
456
457	prop = of_get_property(op->dev.of_node, "resolution", &size);
458	if ((prop) && (size >= sizeof(u32)*2)) {
459		pdata.xres = prop[0];
460		pdata.yres = prop[1];
461	}
462
463	prop = of_get_property(op->dev.of_node, "virtual-resolution", &size);
464	if ((prop) && (size >= sizeof(u32)*2)) {
465		pdata.xvirt = prop[0];
466		pdata.yvirt = prop[1];
467	}
468
469	if (of_find_property(op->dev.of_node, "rotate-display", NULL))
470		pdata.rotate_screen = 1;
471
472	dev_set_drvdata(&op->dev, drvdata);
473	return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata);
474
475 err:
476	kfree(drvdata);
477	return -ENODEV;
478}
479
480static int __devexit xilinxfb_of_remove(struct platform_device *op)
481{
482	return xilinxfb_release(&op->dev);
483}
484
485/* Match table for of_platform binding */
486static struct of_device_id xilinxfb_of_match[] __devinitdata = {
487	{ .compatible = "xlnx,xps-tft-1.00.a", },
488	{ .compatible = "xlnx,xps-tft-2.00.a", },
489	{ .compatible = "xlnx,xps-tft-2.01.a", },
490	{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
491	{ .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
492	{},
493};
494MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
495
496static struct of_platform_driver xilinxfb_of_driver = {
497	.probe = xilinxfb_of_probe,
498	.remove = __devexit_p(xilinxfb_of_remove),
499	.driver = {
500		.name = DRIVER_NAME,
501		.owner = THIS_MODULE,
502		.of_match_table = xilinxfb_of_match,
503	},
504};
505
506
507/* ---------------------------------------------------------------------
508 * Module setup and teardown
509 */
510
511static int __init
512xilinxfb_init(void)
513{
514	return of_register_platform_driver(&xilinxfb_of_driver);
515}
516
517static void __exit
518xilinxfb_cleanup(void)
519{
520	of_unregister_platform_driver(&xilinxfb_of_driver);
521}
522
523module_init(xilinxfb_init);
524module_exit(xilinxfb_cleanup);
525
526MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
527MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
528MODULE_LICENSE("GPL");
529