aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig15
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/offb.c284
-rw-r--r--drivers/video/pnx4008/Makefile7
-rw-r--r--drivers/video/pnx4008/dum.h211
-rw-r--r--drivers/video/pnx4008/fbcommon.h43
-rw-r--r--drivers/video/pnx4008/pnxrgbfb.c213
-rw-r--r--drivers/video/pnx4008/sdum.c872
-rw-r--r--drivers/video/pnx4008/sdum.h139
9 files changed, 1620 insertions, 166 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 17de4c84db69..3badb48d662b 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1557,6 +1557,21 @@ config FB_S3C2410_DEBUG
1557 Turn on debugging messages. Note that you can set/unset at run time 1557 Turn on debugging messages. Note that you can set/unset at run time
1558 through sysfs 1558 through sysfs
1559 1559
1560config FB_PNX4008_DUM
1561 tristate "Display Update Module support on Philips PNX4008 board"
1562 depends on FB && ARCH_PNX4008
1563 ---help---
1564 Say Y here to enable support for PNX4008 Display Update Module (DUM)
1565
1566config FB_PNX4008_DUM_RGB
1567 tristate "RGB Framebuffer support on Philips PNX4008 board"
1568 depends on FB_PNX4008_DUM
1569 select FB_CFB_FILLRECT
1570 select FB_CFB_COPYAREA
1571 select FB_CFB_IMAGEBLIT
1572 ---help---
1573 Say Y here to enable support for PNX4008 RGB Framebuffer
1574
1560config FB_VIRTUAL 1575config FB_VIRTUAL
1561 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" 1576 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
1562 depends on FB 1577 depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index c335e9bc3b20..6283d015f8f5 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -94,6 +94,8 @@ obj-$(CONFIG_FB_TX3912) += tx3912fb.o
94obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o 94obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
95obj-$(CONFIG_FB_IMX) += imxfb.o 95obj-$(CONFIG_FB_IMX) += imxfb.o
96obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o 96obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
97obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
98obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
97 99
98# Platform or fallback drivers go here 100# Platform or fallback drivers go here
99obj-$(CONFIG_FB_VESA) += vesafb.o 101obj-$(CONFIG_FB_VESA) += vesafb.o
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index bfeb11bd4712..71ce1fa45cf4 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -97,14 +97,43 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
97 u_int transp, struct fb_info *info) 97 u_int transp, struct fb_info *info)
98{ 98{
99 struct offb_par *par = (struct offb_par *) info->par; 99 struct offb_par *par = (struct offb_par *) info->par;
100 int i, depth;
101 u32 *pal = info->pseudo_palette;
100 102
101 if (!par->cmap_adr || regno > 255) 103 depth = info->var.bits_per_pixel;
104 if (depth == 16)
105 depth = (info->var.green.length == 5) ? 15 : 16;
106
107 if (regno > 255 ||
108 (depth == 16 && regno > 63) ||
109 (depth == 15 && regno > 31))
102 return 1; 110 return 1;
103 111
112 if (regno < 16) {
113 switch (depth) {
114 case 15:
115 pal[regno] = (regno << 10) | (regno << 5) | regno;
116 break;
117 case 16:
118 pal[regno] = (regno << 11) | (regno << 5) | regno;
119 break;
120 case 24:
121 pal[regno] = (regno << 16) | (regno << 8) | regno;
122 break;
123 case 32:
124 i = (regno << 8) | regno;
125 pal[regno] = (i << 16) | i;
126 break;
127 }
128 }
129
104 red >>= 8; 130 red >>= 8;
105 green >>= 8; 131 green >>= 8;
106 blue >>= 8; 132 blue >>= 8;
107 133
134 if (!par->cmap_adr)
135 return 0;
136
108 switch (par->cmap_type) { 137 switch (par->cmap_type) {
109 case cmap_m64: 138 case cmap_m64:
110 writeb(regno, par->cmap_adr); 139 writeb(regno, par->cmap_adr);
@@ -141,20 +170,6 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
141 break; 170 break;
142 } 171 }
143 172
144 if (regno < 16)
145 switch (info->var.bits_per_pixel) {
146 case 16:
147 ((u16 *) (info->pseudo_palette))[regno] =
148 (regno << 10) | (regno << 5) | regno;
149 break;
150 case 32:
151 {
152 int i = (regno << 8) | regno;
153 ((u32 *) (info->pseudo_palette))[regno] =
154 (i << 16) | i;
155 break;
156 }
157 }
158 return 0; 173 return 0;
159} 174}
160 175
@@ -223,81 +238,9 @@ int __init offb_init(void)
223{ 238{
224 struct device_node *dp = NULL, *boot_disp = NULL; 239 struct device_node *dp = NULL, *boot_disp = NULL;
225 240
226#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
227 struct device_node *macos_display = NULL;
228#endif
229 if (fb_get_options("offb", NULL)) 241 if (fb_get_options("offb", NULL))
230 return -ENODEV; 242 return -ENODEV;
231 243
232#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
233 /* If we're booted from BootX... */
234 if (boot_infos != 0) {
235 unsigned long addr =
236 (unsigned long) boot_infos->dispDeviceBase;
237 u32 *addrp;
238 u64 daddr, dsize;
239 unsigned int flags;
240
241 /* find the device node corresponding to the macos display */
242 while ((dp = of_find_node_by_type(dp, "display"))) {
243 int i;
244
245 /*
246 * Look for an AAPL,address property first.
247 */
248 unsigned int na;
249 unsigned int *ap =
250 (unsigned int *)get_property(dp, "AAPL,address",
251 &na);
252 if (ap != 0) {
253 for (na /= sizeof(unsigned int); na > 0;
254 --na, ++ap)
255 if (*ap <= addr &&
256 addr < *ap + 0x1000000) {
257 macos_display = dp;
258 goto foundit;
259 }
260 }
261
262 /*
263 * See if the display address is in one of the address
264 * ranges for this display.
265 */
266 i = 0;
267 for (;;) {
268 addrp = of_get_address(dp, i++, &dsize, &flags);
269 if (addrp == NULL)
270 break;
271 if (!(flags & IORESOURCE_MEM))
272 continue;
273 daddr = of_translate_address(dp, addrp);
274 if (daddr == OF_BAD_ADDR)
275 continue;
276 if (daddr <= addr && addr < (daddr + dsize)) {
277 macos_display = dp;
278 goto foundit;
279 }
280 }
281 foundit:
282 if (macos_display) {
283 printk(KERN_INFO "MacOS display is %s\n",
284 dp->full_name);
285 break;
286 }
287 }
288
289 /* initialize it */
290 offb_init_fb(macos_display ? macos_display->
291 name : "MacOS display",
292 macos_display ? macos_display->
293 full_name : "MacOS display",
294 boot_infos->dispDeviceRect[2],
295 boot_infos->dispDeviceRect[3],
296 boot_infos->dispDeviceDepth,
297 boot_infos->dispDeviceRowBytes, addr, NULL);
298 }
299#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */
300
301 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { 244 for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
302 if (get_property(dp, "linux,opened", NULL) && 245 if (get_property(dp, "linux,opened", NULL) &&
303 get_property(dp, "linux,boot-display", NULL)) { 246 get_property(dp, "linux,boot-display", NULL)) {
@@ -317,94 +260,93 @@ int __init offb_init(void)
317 260
318static void __init offb_init_nodriver(struct device_node *dp) 261static void __init offb_init_nodriver(struct device_node *dp)
319{ 262{
320 int *pp, i;
321 unsigned int len; 263 unsigned int len;
322 int width = 640, height = 480, depth = 8, pitch; 264 int i, width = 640, height = 480, depth = 8, pitch = 640;
323 unsigned int flags, rsize, *up; 265 unsigned int flags, rsize, addr_prop = 0;
324 u64 address = OF_BAD_ADDR; 266 unsigned long max_size = 0;
325 u32 *addrp; 267 u64 rstart, address = OF_BAD_ADDR;
268 u32 *pp, *addrp, *up;
326 u64 asize; 269 u64 asize;
327 270
328 if ((pp = (int *) get_property(dp, "depth", &len)) != NULL 271 pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
329 && len == sizeof(int)) 272 if (pp == NULL)
273 pp = (u32 *)get_property(dp, "depth", &len);
274 if (pp && len == sizeof(u32))
330 depth = *pp; 275 depth = *pp;
331 if ((pp = (int *) get_property(dp, "width", &len)) != NULL 276
332 && len == sizeof(int)) 277 pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
278 if (pp == NULL)
279 pp = (u32 *)get_property(dp, "width", &len);
280 if (pp && len == sizeof(u32))
333 width = *pp; 281 width = *pp;
334 if ((pp = (int *) get_property(dp, "height", &len)) != NULL 282
335 && len == sizeof(int)) 283 pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
284 if (pp == NULL)
285 pp = (u32 *)get_property(dp, "height", &len);
286 if (pp && len == sizeof(u32))
336 height = *pp; 287 height = *pp;
337 if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL 288
338 && len == sizeof(int)) { 289 pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
290 if (pp == NULL)
291 pp = (u32 *)get_property(dp, "linebytes", &len);
292 if (pp && len == sizeof(u32))
339 pitch = *pp; 293 pitch = *pp;
340 if (pitch == 1) 294 else
341 pitch = 0x1000; 295 pitch = width * ((depth + 7) / 8);
342 } else 296
343 pitch = width; 297 rsize = (unsigned long)pitch * (unsigned long)height;
344 298
345 rsize = (unsigned long)pitch * (unsigned long)height * 299 /* Ok, now we try to figure out the address of the framebuffer.
346 (unsigned long)(depth / 8); 300 *
347 301 * Unfortunately, Open Firmware doesn't provide a standard way to do
348 /* Try to match device to a PCI device in order to get a properly 302 * so. All we can do is a dodgy heuristic that happens to work in
349 * translated address rather then trying to decode the open firmware 303 * practice. On most machines, the "address" property contains what
350 * stuff in various incorrect ways 304 * we need, though not on Matrox cards found in IBM machines. What I've
351 */ 305 * found that appears to give good results is to go through the PCI
352#ifdef CONFIG_PCI 306 * ranges and pick one that is both big enough and if possible encloses
353 /* First try to locate the PCI device if any */ 307 * the "address" property. If none match, we pick the biggest
354 { 308 */
355 struct pci_dev *pdev = NULL; 309 up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
356 310 if (up == NULL)
357 for_each_pci_dev(pdev) { 311 up = (u32 *)get_property(dp, "address", &len);
358 if (dp == pci_device_to_OF_node(pdev)) 312 if (up && len == sizeof(u32))
359 break; 313 addr_prop = *up;
360 } 314
361 if (pdev) { 315 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
362 for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) { 316 != NULL; i++) {
363 if ((pci_resource_flags(pdev, i) & 317 int match_addrp = 0;
364 IORESOURCE_MEM) && 318
365 (pci_resource_len(pdev, i) >= rsize)) 319 if (!(flags & IORESOURCE_MEM))
366 address = pci_resource_start(pdev, i); 320 continue;
367 } 321 if (asize < rsize)
368 pci_dev_put(pdev); 322 continue;
369 } 323 rstart = of_translate_address(dp, addrp);
370 } 324 if (rstart == OF_BAD_ADDR)
371#endif /* CONFIG_PCI */ 325 continue;
372 326 if (addr_prop && (rstart <= addr_prop) &&
373 /* This one is dodgy, we may drop it ... */ 327 ((rstart + asize) >= (addr_prop + rsize)))
374 if (address == OF_BAD_ADDR && 328 match_addrp = 1;
375 (up = (unsigned *) get_property(dp, "address", &len)) != NULL && 329 if (match_addrp) {
376 len == sizeof(unsigned int)) 330 address = addr_prop;
377 address = (u64) * up; 331 break;
378
379 if (address == OF_BAD_ADDR) {
380 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
381 != NULL; i++) {
382 if (!(flags & IORESOURCE_MEM))
383 continue;
384 if (asize >= pitch * height * depth / 8)
385 break;
386 }
387 if (addrp == NULL) {
388 printk(KERN_ERR
389 "no framebuffer address found for %s\n",
390 dp->full_name);
391 return;
392 }
393 address = of_translate_address(dp, addrp);
394 if (address == OF_BAD_ADDR) {
395 printk(KERN_ERR
396 "can't translate framebuffer address for %s\n",
397 dp->full_name);
398 return;
399 } 332 }
333 if (rsize > max_size) {
334 max_size = rsize;
335 address = OF_BAD_ADDR;
336 }
400 337
338 if (address == OF_BAD_ADDR)
339 address = rstart;
340 }
341 if (address == OF_BAD_ADDR && addr_prop)
342 address = (u64)addr_prop;
343 if (address != OF_BAD_ADDR) {
401 /* kludge for valkyrie */ 344 /* kludge for valkyrie */
402 if (strcmp(dp->name, "valkyrie") == 0) 345 if (strcmp(dp->name, "valkyrie") == 0)
403 address += 0x1000; 346 address += 0x1000;
347 offb_init_fb(dp->name, dp->full_name, width, height, depth,
348 pitch, address, dp);
404 } 349 }
405 offb_init_fb(dp->name, dp->full_name, width, height, depth,
406 pitch, address, dp);
407
408} 350}
409 351
410static void __init offb_init_fb(const char *name, const char *full_name, 352static void __init offb_init_fb(const char *name, const char *full_name,
@@ -412,7 +354,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
412 int pitch, unsigned long address, 354 int pitch, unsigned long address,
413 struct device_node *dp) 355 struct device_node *dp)
414{ 356{
415 unsigned long res_size = pitch * height * depth / 8; 357 unsigned long res_size = pitch * height * (depth + 7) / 8;
416 struct offb_par *par = &default_par; 358 struct offb_par *par = &default_par;
417 unsigned long res_start = address; 359 unsigned long res_start = address;
418 struct fb_fix_screeninfo *fix; 360 struct fb_fix_screeninfo *fix;
@@ -426,7 +368,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
426 printk(KERN_INFO 368 printk(KERN_INFO
427 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", 369 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
428 width, height, name, address, depth, pitch); 370 width, height, name, address, depth, pitch);
429 if (depth != 8 && depth != 16 && depth != 32) { 371 if (depth != 8 && depth != 15 && depth != 16 && depth != 32) {
430 printk(KERN_ERR "%s: can't use depth = %d\n", full_name, 372 printk(KERN_ERR "%s: can't use depth = %d\n", full_name,
431 depth); 373 depth);
432 release_mem_region(res_start, res_size); 374 release_mem_region(res_start, res_size);
@@ -502,7 +444,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
502 : */ FB_VISUAL_TRUECOLOR; 444 : */ FB_VISUAL_TRUECOLOR;
503 445
504 var->xoffset = var->yoffset = 0; 446 var->xoffset = var->yoffset = 0;
505 var->bits_per_pixel = depth;
506 switch (depth) { 447 switch (depth) {
507 case 8: 448 case 8:
508 var->bits_per_pixel = 8; 449 var->bits_per_pixel = 8;
@@ -515,7 +456,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
515 var->transp.offset = 0; 456 var->transp.offset = 0;
516 var->transp.length = 0; 457 var->transp.length = 0;
517 break; 458 break;
518 case 16: /* RGB 555 */ 459 case 15: /* RGB 555 */
519 var->bits_per_pixel = 16; 460 var->bits_per_pixel = 16;
520 var->red.offset = 10; 461 var->red.offset = 10;
521 var->red.length = 5; 462 var->red.length = 5;
@@ -526,6 +467,17 @@ static void __init offb_init_fb(const char *name, const char *full_name,
526 var->transp.offset = 0; 467 var->transp.offset = 0;
527 var->transp.length = 0; 468 var->transp.length = 0;
528 break; 469 break;
470 case 16: /* RGB 565 */
471 var->bits_per_pixel = 16;
472 var->red.offset = 11;
473 var->red.length = 5;
474 var->green.offset = 5;
475 var->green.length = 6;
476 var->blue.offset = 0;
477 var->blue.length = 5;
478 var->transp.offset = 0;
479 var->transp.length = 0;
480 break;
529 case 32: /* RGB 888 */ 481 case 32: /* RGB 888 */
530 var->bits_per_pixel = 32; 482 var->bits_per_pixel = 32;
531 var->red.offset = 16; 483 var->red.offset = 16;
diff --git a/drivers/video/pnx4008/Makefile b/drivers/video/pnx4008/Makefile
new file mode 100644
index 000000000000..636aaccf01fd
--- /dev/null
+++ b/drivers/video/pnx4008/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the new PNX4008 framebuffer device driver
3#
4
5obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o
6obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o
7
diff --git a/drivers/video/pnx4008/dum.h b/drivers/video/pnx4008/dum.h
new file mode 100644
index 000000000000..d80a614d89ed
--- /dev/null
+++ b/drivers/video/pnx4008/dum.h
@@ -0,0 +1,211 @@
1/*
2 * linux/drivers/video/pnx4008/dum.h
3 *
4 * Internal header for SDUM
5 *
6 * 2005 (c) Koninklijke Philips N.V. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 */
11
12#ifndef __PNX008_DUM_H__
13#define __PNX008_DUM_H__
14
15#include <asm/arch/platform.h>
16
17#define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE)
18#define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE)
19
20/* DUM CFG ADDRESSES */
21#define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
22#define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
23#define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04)
24#define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08)
25#define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C)
26#define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10)
27
28#define CH_MARG (0x100 / sizeof(u32))
29#define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG))
30#define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG))
31#define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG))
32#define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG))
33#define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG))
34
35#define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00)
36#define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04)
37#define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08)
38#define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C)
39#define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10)
40#define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14)
41#define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18)
42#define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20)
43#define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24)
44#define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28)
45#define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30)
46#define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34)
47#define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38)
48#define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C)
49#define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40)
50#define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44)
51#define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48)
52#define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C)
53#define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50)
54
55#define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR))
56#define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR))
57#define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR))
58#define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR))
59#define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR))
60#define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR))
61#define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR))
62#define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR))
63#define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR))
64#define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR))
65#define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR))
66#define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR))
67#define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR))
68#define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR))
69#define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR))
70#define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR))
71#define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR))
72#define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR))
73#define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR))
74
75/* DUM SLAVE ADDRESSES */
76#define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000)
77#define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000)
78#define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004)
79#define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008)
80#define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C)
81
82#define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR))
83#define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR))
84#define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR))
85#define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR))
86#define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR))
87#define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR))
88
89/* Sony display register addresses */
90#define DISP_0_REG (0x00)
91#define DISP_1_REG (0x01)
92#define DISP_CAL_REG (0x20)
93#define DISP_ID_REG (0x2A)
94#define DISP_XMIN_L_REG (0x30)
95#define DISP_XMIN_H_REG (0x31)
96#define DISP_YMIN_REG (0x32)
97#define DISP_XMAX_L_REG (0x34)
98#define DISP_XMAX_H_REG (0x35)
99#define DISP_YMAX_REG (0x36)
100#define DISP_SYNC_EN_REG (0x38)
101#define DISP_SYNC_RISE_L_REG (0x3C)
102#define DISP_SYNC_RISE_H_REG (0x3D)
103#define DISP_SYNC_FALL_L_REG (0x3E)
104#define DISP_SYNC_FALL_H_REG (0x3F)
105#define DISP_PIXEL_REG (0x0B)
106#define DISP_DUMMY1_REG (0x28)
107#define DISP_DUMMY2_REG (0x29)
108#define DISP_TIMING_REG (0x98)
109#define DISP_DUMP_REG (0x99)
110
111/* Sony display constants */
112#define SONY_ID1 (0x22)
113#define SONY_ID2 (0x23)
114
115/* Philips display register addresses */
116#define PH_DISP_ORIENT_REG (0x003)
117#define PH_DISP_YPOINT_REG (0x200)
118#define PH_DISP_XPOINT_REG (0x201)
119#define PH_DISP_PIXEL_REG (0x202)
120#define PH_DISP_YMIN_REG (0x406)
121#define PH_DISP_YMAX_REG (0x407)
122#define PH_DISP_XMIN_REG (0x408)
123#define PH_DISP_XMAX_REG (0x409)
124
125/* Misc constants */
126#define NO_VALID_DISPLAY_FOUND (0)
127#define DISPLAY2_IS_NOT_CONNECTED (0)
128
129/* register values */
130#define V_BAC_ENABLE (BIT(0))
131#define V_BAC_DISABLE_IDLE (BIT(1))
132#define V_BAC_DISABLE_TRIG (BIT(2))
133#define V_DUM_RESET (BIT(3))
134#define V_MUX_RESET (BIT(4))
135#define BAC_ENABLED (BIT(0))
136#define BAC_DISABLED 0
137
138/* Sony LCD commands */
139#define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG)
140#define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG)
141#define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG)
142#define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG)
143#define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG)
144#define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG)
145#define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG)
146#define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG)
147
148enum {
149 PAD_NONE,
150 PAD_512,
151 PAD_1024
152};
153
154enum {
155 RGB888,
156 RGB666,
157 RGB565,
158 BGR565,
159 ARGB1555,
160 ABGR1555,
161 ARGB4444,
162 ABGR4444
163};
164
165struct dum_setup {
166 int sync_neg_edge;
167 int round_robin;
168 int mux_int;
169 int synced_dirty_flag_int;
170 int dirty_flag_int;
171 int error_int;
172 int pf_empty_int;
173 int sf_empty_int;
174 int bac_dis_int;
175 u32 dirty_base_adr;
176 u32 command_base_adr;
177 u32 sync_clk_div;
178 int sync_output;
179 u32 sync_restart_val;
180 u32 set_sync_high;
181 u32 set_sync_low;
182};
183
184struct dum_ch_setup {
185 int disp_no;
186 u32 xmin;
187 u32 ymin;
188 u32 xmax;
189 u32 ymax;
190 int xmirror;
191 int ymirror;
192 int rotate;
193 u32 minadr;
194 u32 maxadr;
195 u32 dirtybuffer;
196 int pad;
197 int format;
198 int hwdirty;
199 int slave_trans;
200};
201
202struct disp_window {
203 u32 xmin_l;
204 u32 xmin_h;
205 u32 ymin;
206 u32 xmax_l;
207 u32 xmax_h;
208 u32 ymax;
209};
210
211#endif /* #ifndef __PNX008_DUM_H__ */
diff --git a/drivers/video/pnx4008/fbcommon.h b/drivers/video/pnx4008/fbcommon.h
new file mode 100644
index 000000000000..4ebc87dafafb
--- /dev/null
+++ b/drivers/video/pnx4008/fbcommon.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2005 Philips Semiconductors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
18*/
19
20#define QCIF_W (176)
21#define QCIF_H (144)
22
23#define CIF_W (352)
24#define CIF_H (288)
25
26#define LCD_X_RES 208
27#define LCD_Y_RES 320
28#define LCD_X_PAD 256
29#define LCD_BBP 4 /* Bytes Per Pixel */
30
31#define DISP_MAX_X_SIZE (320)
32#define DISP_MAX_Y_SIZE (208)
33
34#define RETURNVAL_BASE (0x400)
35
36enum fb_ioctl_returntype {
37 ENORESOURCESLEFT = RETURNVAL_BASE,
38 ERESOURCESNOTFREED,
39 EPROCNOTOWNER,
40 EFBNOTOWNER,
41 ECOPYFAILED,
42 EIOREMAPFAILED,
43};
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
new file mode 100644
index 000000000000..7d9453c91a42
--- /dev/null
+++ b/drivers/video/pnx4008/pnxrgbfb.c
@@ -0,0 +1,213 @@
1/*
2 * drivers/video/pnx4008/pnxrgbfb.c
3 *
4 * PNX4008's framebuffer support
5 *
6 * Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
7 * Based on Philips Semiconductors's code
8 *
9 * Copyrght (c) 2005 MontaVista Software, Inc.
10 * Copyright (c) 2005 Philips Semiconductors
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#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/string.h>
20#include <linux/mm.h>
21#include <linux/slab.h>
22#include <linux/vmalloc.h>
23#include <linux/delay.h>
24#include <linux/interrupt.h>
25#include <linux/fb.h>
26#include <linux/init.h>
27#include <linux/platform_device.h>
28
29#include <asm/uaccess.h>
30#include "sdum.h"
31#include "fbcommon.h"
32
33static u32 colreg[16];
34
35static struct fb_var_screeninfo rgbfb_var __initdata = {
36 .xres = LCD_X_RES,
37 .yres = LCD_Y_RES,
38 .xres_virtual = LCD_X_RES,
39 .yres_virtual = LCD_Y_RES,
40 .bits_per_pixel = 32,
41 .red.offset = 16,
42 .red.length = 8,
43 .green.offset = 8,
44 .green.length = 8,
45 .blue.offset = 0,
46 .blue.length = 8,
47 .left_margin = 0,
48 .right_margin = 0,
49 .upper_margin = 0,
50 .lower_margin = 0,
51 .vmode = FB_VMODE_NONINTERLACED,
52};
53static struct fb_fix_screeninfo rgbfb_fix __initdata = {
54 .id = "RGBFB",
55 .line_length = LCD_X_RES * LCD_BBP,
56 .type = FB_TYPE_PACKED_PIXELS,
57 .visual = FB_VISUAL_TRUECOLOR,
58 .xpanstep = 0,
59 .ypanstep = 0,
60 .ywrapstep = 0,
61 .accel = FB_ACCEL_NONE,
62};
63
64static int channel_owned;
65
66static int no_cursor(struct fb_info *info, struct fb_cursor *cursor)
67{
68 return 0;
69}
70
71static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
72 u_int transp, struct fb_info *info)
73{
74 if (regno > 15)
75 return 1;
76
77 colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) |
78 ((blue & 0xff00) >> 8);
79 return 0;
80}
81
82static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
83{
84 return pnx4008_sdum_mmap(info, vma, NULL);
85}
86
87static struct fb_ops rgbfb_ops = {
88 .fb_mmap = rgbfb_mmap,
89 .fb_setcolreg = rgbfb_setcolreg,
90 .fb_fillrect = cfb_fillrect,
91 .fb_copyarea = cfb_copyarea,
92 .fb_imageblit = cfb_imageblit,
93};
94
95static int rgbfb_remove(struct platform_device *pdev)
96{
97 struct fb_info *info = platform_get_drvdata(pdev);
98
99 if (info) {
100 unregister_framebuffer(info);
101 fb_dealloc_cmap(&info->cmap);
102 framebuffer_release(info);
103 platform_set_drvdata(pdev, NULL);
104 kfree(info);
105 }
106
107 pnx4008_free_dum_channel(channel_owned, pdev->id);
108 pnx4008_set_dum_exit_notification(pdev->id);
109
110 return 0;
111}
112
113static int __devinit rgbfb_probe(struct platform_device *pdev)
114{
115 struct fb_info *info;
116 struct dumchannel_uf chan_uf;
117 int ret;
118 char *option;
119
120 info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
121 if (!info) {
122 ret = -ENOMEM;
123 goto err;
124 }
125
126 pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base,
127 (dma_addr_t *) &rgbfb_fix.smem_start,
128 &rgbfb_fix.smem_len);
129
130 if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0)
131 goto err0;
132 else {
133 channel_owned = ret;
134 chan_uf.channelnr = channel_owned;
135 chan_uf.dirty = (u32 *) NULL;
136 chan_uf.source = (u32 *) rgbfb_fix.smem_start;
137 chan_uf.x_offset = 0;
138 chan_uf.y_offset = 0;
139 chan_uf.width = LCD_X_RES;
140 chan_uf.height = LCD_Y_RES;
141
142 if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0)
143 goto err1;
144
145 if ((ret =
146 pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON,
147 pdev->id)) < 0)
148 goto err1;
149
150 if ((ret =
151 pnx4008_set_dum_channel_dirty_detect(channel_owned,
152 CONF_DIRTYDETECTION_ON,
153 pdev->id)) < 0)
154 goto err1;
155 }
156
157 if (!fb_get_options("pnxrgbfb", &option) && !strcmp(option, "nocursor"))
158 rgbfb_ops.fb_cursor = no_cursor;
159
160 info->node = -1;
161 info->flags = FBINFO_FLAG_DEFAULT;
162 info->fbops = &rgbfb_ops;
163 info->fix = rgbfb_fix;
164 info->var = rgbfb_var;
165 info->screen_size = rgbfb_fix.smem_len;
166 info->pseudo_palette = info->par;
167 info->par = NULL;
168
169 ret = fb_alloc_cmap(&info->cmap, 256, 0);
170 if (ret < 0)
171 goto err2;
172
173 ret = register_framebuffer(info);
174 if (ret < 0)
175 goto err3;
176 platform_set_drvdata(pdev, info);
177
178 return 0;
179
180err3:
181 fb_dealloc_cmap(&info->cmap);
182err2:
183 framebuffer_release(info);
184err1:
185 pnx4008_free_dum_channel(channel_owned, pdev->id);
186err0:
187 kfree(info);
188err:
189 return ret;
190}
191
192static struct platform_driver rgbfb_driver = {
193 .driver = {
194 .name = "rgbfb",
195 },
196 .probe = rgbfb_probe,
197 .remove = rgbfb_remove,
198};
199
200static int __init rgbfb_init(void)
201{
202 return platform_driver_register(&rgbfb_driver);
203}
204
205static void __exit rgbfb_exit(void)
206{
207 platform_driver_unregister(&rgbfb_driver);
208}
209
210module_init(rgbfb_init);
211module_exit(rgbfb_exit);
212
213MODULE_LICENSE("GPL");
diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c
new file mode 100644
index 000000000000..51f0ecc2a511
--- /dev/null
+++ b/drivers/video/pnx4008/sdum.c
@@ -0,0 +1,872 @@
1/*
2 * drivers/video/pnx4008/sdum.c
3 *
4 * Display Update Master support
5 *
6 * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
7 * Vitaly Wool <vitalywool@gmail.com>
8 * Based on Philips Semiconductors's code
9 *
10 * Copyrght (c) 2005-2006 MontaVista Software, Inc.
11 * Copyright (c) 2005 Philips Semiconductors
12 * This file is licensed under the terms of the GNU General Public License
13 * version 2. This program is licensed "as is" without any warranty of any
14 * kind, whether express or implied.
15 */
16
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/string.h>
21#include <linux/mm.h>
22#include <linux/tty.h>
23#include <linux/slab.h>
24#include <linux/vmalloc.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/platform_device.h>
28#include <linux/fb.h>
29#include <linux/init.h>
30#include <linux/dma-mapping.h>
31#include <linux/clk.h>
32#include <asm/uaccess.h>
33#include <asm/arch/gpio.h>
34
35#include "sdum.h"
36#include "fbcommon.h"
37#include "dum.h"
38
39/* Framebuffers we have */
40
41static struct pnx4008_fb_addr {
42 int fb_type;
43 long addr_offset;
44 long fb_length;
45} fb_addr[] = {
46 [0] = {
47 FB_TYPE_YUV, 0, 0xB0000
48 },
49 [1] = {
50 FB_TYPE_RGB, 0xB0000, 0x50000
51 },
52};
53
54static struct dum_data {
55 u32 lcd_phys_start;
56 u32 lcd_virt_start;
57 u32 slave_phys_base;
58 u32 *slave_virt_base;
59 int fb_owning_channel[MAX_DUM_CHANNELS];
60 struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS];
61} dum_data;
62
63/* Different local helper functions */
64
65static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup)
66{
67 return (ch_setup->xmax - ch_setup->xmin + 1);
68}
69
70static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup)
71{
72 return (ch_setup->ymax - ch_setup->ymin + 1);
73}
74
75static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup)
76{
77 return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup));
78}
79
80static u32 nof_bytes(struct dum_ch_setup *ch_setup)
81{
82 u32 r = nof_pixels_dxy(ch_setup);
83 switch (ch_setup->format) {
84 case RGB888:
85 case RGB666:
86 r *= 4;
87 break;
88
89 default:
90 r *= 2;
91 break;
92 }
93 return r;
94}
95
96static u32 build_command(int disp_no, u32 reg, u32 val)
97{
98 return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) |
99 (reg << 0));
100}
101
102static u32 build_double_index(int disp_no, u32 val)
103{
104 return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0));
105}
106
107static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw)
108{
109 dw->ymin = ch_setup->ymin;
110 dw->ymax = ch_setup->ymax;
111 dw->xmin_l = ch_setup->xmin & 0xFF;
112 dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8;
113 dw->xmax_l = ch_setup->xmax & 0xFF;
114 dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8;
115}
116
117static int put_channel(struct dumchannel chan)
118{
119 int i = chan.channelnr;
120
121 if (i < 0 || i > MAX_DUM_CHANNELS)
122 return -EINVAL;
123 else {
124 DUM_CH_MIN(i) = chan.dum_ch_min;
125 DUM_CH_MAX(i) = chan.dum_ch_max;
126 DUM_CH_CONF(i) = chan.dum_ch_conf;
127 DUM_CH_CTRL(i) = chan.dum_ch_ctrl;
128 }
129
130 return 0;
131}
132
133static void clear_channel(int channr)
134{
135 struct dumchannel chan;
136
137 chan.channelnr = channr;
138 chan.dum_ch_min = 0;
139 chan.dum_ch_max = 0;
140 chan.dum_ch_conf = 0;
141 chan.dum_ch_ctrl = 0;
142
143 put_channel(chan);
144}
145
146static int put_cmd_string(struct cmdstring cmds)
147{
148 u16 *cmd_str_virtaddr;
149 u32 *cmd_ptr0_virtaddr;
150 u32 cmd_str_physaddr;
151
152 int i = cmds.channelnr;
153
154 if (i < 0 || i > MAX_DUM_CHANNELS)
155 return -EINVAL;
156 else if ((cmd_ptr0_virtaddr =
157 (int *)ioremap_nocache(DUM_COM_BASE,
158 sizeof(int) * MAX_DUM_CHANNELS)) ==
159 NULL)
160 return -EIOREMAPFAILED;
161 else {
162 cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]);
163 if ((cmd_str_virtaddr =
164 (u16 *) ioremap_nocache(cmd_str_physaddr,
165 sizeof(cmds))) == NULL) {
166 iounmap(cmd_ptr0_virtaddr);
167 return -EIOREMAPFAILED;
168 } else {
169 int t;
170 for (t = 0; t < 8; t++)
171 iowrite16(*((u16 *)&cmds.prestringlen + t),
172 cmd_str_virtaddr + t);
173
174 for (t = 0; t < cmds.prestringlen / 2; t++)
175 iowrite16(*((u16 *)&cmds.precmd + t),
176 cmd_str_virtaddr + t + 8);
177
178 for (t = 0; t < cmds.poststringlen / 2; t++)
179 iowrite16(*((u16 *)&cmds.postcmd + t),
180 cmd_str_virtaddr + t + 8 +
181 cmds.prestringlen / 2);
182
183 iounmap(cmd_ptr0_virtaddr);
184 iounmap(cmd_str_virtaddr);
185 }
186 }
187
188 return 0;
189}
190
191static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup)
192{
193 struct cmdstring cmds_c;
194 struct cmdstring *cmds = &cmds_c;
195 struct disp_window dw;
196 int standard;
197 u32 orientation = 0;
198 struct dumchannel chan = { 0 };
199 int ret;
200
201 if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) {
202 standard = 0;
203
204 orientation = BIT(1); /* always set 9-bit-bus */
205 if (ch_setup->xmirror)
206 orientation |= BIT(4);
207 if (ch_setup->ymirror)
208 orientation |= BIT(3);
209 if (ch_setup->rotate)
210 orientation |= BIT(0);
211 } else
212 standard = 1;
213
214 cmds->channelnr = ch_no;
215
216 /* build command string header */
217 if (standard) {
218 cmds->prestringlen = 32;
219 cmds->poststringlen = 0;
220 } else {
221 cmds->prestringlen = 48;
222 cmds->poststringlen = 16;
223 }
224
225 cmds->format =
226 (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format));
227 cmds->reserved = 0x0;
228 cmds->startaddr_low = (ch_setup->minadr & 0xFFFF);
229 cmds->startaddr_high = (ch_setup->minadr >> 16);
230
231 if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0)
232 && (ch_setup->xmin == 0)
233 && (ch_setup->ymin == 0) && (ch_setup->xmax == 0)
234 && (ch_setup->ymax == 0)) {
235 cmds->pixdatlen_low = 0;
236 cmds->pixdatlen_high = 0;
237 } else {
238 u32 nbytes = nof_bytes(ch_setup);
239 cmds->pixdatlen_low = (nbytes & 0xFFFF);
240 cmds->pixdatlen_high = (nbytes >> 16);
241 }
242
243 if (ch_setup->slave_trans)
244 cmds->pixdatlen_high |= BIT(15);
245
246 /* build pre-string */
247 build_disp_window(ch_setup, &dw);
248
249 if (standard) {
250 cmds->precmd[0] =
251 build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99);
252 cmds->precmd[1] =
253 build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
254 dw.xmin_l);
255 cmds->precmd[2] =
256 build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
257 dw.xmin_h);
258 cmds->precmd[3] =
259 build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
260 cmds->precmd[4] =
261 build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
262 dw.xmax_l);
263 cmds->precmd[5] =
264 build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
265 dw.xmax_h);
266 cmds->precmd[6] =
267 build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
268 cmds->precmd[7] =
269 build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
270 } else {
271 if (dw.xmin_l == ch_no)
272 cmds->precmd[0] =
273 build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
274 0x99);
275 else
276 cmds->precmd[0] =
277 build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
278 ch_no);
279
280 cmds->precmd[1] =
281 build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
282 dw.xmin_l);
283 cmds->precmd[2] =
284 build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
285 dw.xmin_h);
286 cmds->precmd[3] =
287 build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
288 cmds->precmd[4] =
289 build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
290 dw.xmax_l);
291 cmds->precmd[5] =
292 build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
293 dw.xmax_h);
294 cmds->precmd[6] =
295 build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
296 cmds->precmd[7] =
297 build_command(ch_setup->disp_no, DISP_1_REG, orientation);
298 cmds->precmd[8] =
299 build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
300 cmds->precmd[9] =
301 build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
302 cmds->precmd[0xA] =
303 build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
304 cmds->precmd[0xB] =
305 build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
306 cmds->postcmd[0] =
307 build_command(ch_setup->disp_no, DISP_1_REG, BIT(1));
308 cmds->postcmd[1] =
309 build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1);
310 cmds->postcmd[2] =
311 build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2);
312 cmds->postcmd[3] =
313 build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3);
314 }
315
316 if ((ret = put_cmd_string(cmds_c)) != 0) {
317 return ret;
318 }
319
320 chan.channelnr = cmds->channelnr;
321 chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr;
322 chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr;
323 chan.dum_ch_conf = 0x002;
324 chan.dum_ch_ctrl = 0x04;
325
326 put_channel(chan);
327
328 return 0;
329}
330
331static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer,
332 u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h)
333{
334
335 struct dum_ch_setup k;
336 int ret;
337
338 /* keep width & height within display area */
339 if ((xpos + w) > DISP_MAX_X_SIZE)
340 w = DISP_MAX_X_SIZE - xpos;
341
342 if ((ypos + h) > DISP_MAX_Y_SIZE)
343 h = DISP_MAX_Y_SIZE - ypos;
344
345 /* assume 1 display only */
346 k.disp_no = 0;
347 k.xmin = xpos;
348 k.ymin = ypos;
349 k.xmax = xpos + (w - 1);
350 k.ymax = ypos + (h - 1);
351
352 /* adjust min and max values if necessary */
353 if (k.xmin > DISP_MAX_X_SIZE - 1)
354 k.xmin = DISP_MAX_X_SIZE - 1;
355 if (k.ymin > DISP_MAX_Y_SIZE - 1)
356 k.ymin = DISP_MAX_Y_SIZE - 1;
357
358 if (k.xmax > DISP_MAX_X_SIZE - 1)
359 k.xmax = DISP_MAX_X_SIZE - 1;
360 if (k.ymax > DISP_MAX_Y_SIZE - 1)
361 k.ymax = DISP_MAX_Y_SIZE - 1;
362
363 k.xmirror = 0;
364 k.ymirror = 0;
365 k.rotate = 0;
366 k.minadr = (u32) frame_buffer;
367 k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2));
368 k.pad = PAD_1024;
369 k.dirtybuffer = (u32) dirty_buffer;
370 k.format = RGB888;
371 k.hwdirty = 0;
372 k.slave_trans = 0;
373
374 ret = dum_ch_setup(ch_no, &k);
375
376 return ret;
377}
378
379static void lcd_reset(void)
380{
381 u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE);
382
383 udelay(1);
384 iowrite32(BIT(19), &dum_pio_base[2]);
385 udelay(1);
386 iowrite32(BIT(19), &dum_pio_base[1]);
387 udelay(1);
388}
389
390static int dum_init(struct platform_device *pdev)
391{
392 struct clk *clk;
393
394 /* enable DUM clock */
395 clk = clk_get(&pdev->dev, "dum_ck");
396 if (IS_ERR(clk)) {
397 printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n");
398 return PTR_ERR(clk);
399 }
400
401 clk_set_rate(clk, 1);
402 clk_put(clk);
403
404 DUM_CTRL = V_DUM_RESET;
405
406 /* set priority to "round-robin". All other params to "false" */
407 DUM_CONF = BIT(9);
408
409 /* Display 1 */
410 DUM_WTCFG1 = PNX4008_DUM_WT_CFG;
411 DUM_RTCFG1 = PNX4008_DUM_RT_CFG;
412 DUM_TCFG = PNX4008_DUM_T_CFG;
413
414 return 0;
415}
416
417static void dum_chan_init(void)
418{
419 int i = 0, ch = 0;
420 u32 *cmdptrs;
421 u32 *cmdstrings;
422
423 DUM_COM_BASE =
424 CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS;
425
426 if ((cmdptrs =
427 (u32 *) ioremap_nocache(DUM_COM_BASE,
428 sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL)
429 return;
430
431 for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++)
432 iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch,
433 cmdptrs + ch);
434
435 for (ch = 0; ch < MAX_DUM_CHANNELS; ch++)
436 clear_channel(ch);
437
438 /* Clear the cmdstrings */
439 cmdstrings =
440 (u32 *)ioremap_nocache(*cmdptrs,
441 BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS);
442
443 if (!cmdstrings)
444 goto out;
445
446 for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32);
447 i++)
448 iowrite32(0, cmdstrings + i);
449
450 iounmap((u32 *)cmdstrings);
451
452out:
453 iounmap((u32 *)cmdptrs);
454}
455
456static void lcd_init(void)
457{
458 lcd_reset();
459
460 DUM_OUTP_FORMAT1 = 0; /* RGB666 */
461
462 udelay(1);
463 iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base);
464 udelay(1);
465 iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base);
466 udelay(1);
467 iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base);
468 udelay(1);
469 iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base);
470 udelay(1);
471 iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base);
472 udelay(1);
473 iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base);
474 udelay(1);
475 iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base);
476 udelay(1);
477 iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base);
478 udelay(1);
479}
480
481/* Interface exported to framebuffer drivers */
482
483int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
484 dma_addr_t *phys_addr, int *fb_length)
485{
486 int i;
487 int ret = -1;
488 for (i = 0; i < ARRAY_SIZE(fb_addr); i++)
489 if (fb_addr[i].fb_type == fb_type) {
490 *virt_addr = (void *)(dum_data.lcd_virt_start +
491 fb_addr[i].addr_offset);
492 *phys_addr =
493 dum_data.lcd_phys_start + fb_addr[i].addr_offset;
494 *fb_length = fb_addr[i].fb_length;
495 ret = 0;
496 break;
497 }
498
499 return ret;
500}
501
502EXPORT_SYMBOL(pnx4008_get_fb_addresses);
503
504int pnx4008_alloc_dum_channel(int dev_id)
505{
506 int i = 0;
507
508 while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1))
509 i++;
510
511 if (i == MAX_DUM_CHANNELS)
512 return -ENORESOURCESLEFT;
513 else {
514 dum_data.fb_owning_channel[i] = dev_id;
515 return i;
516 }
517}
518
519EXPORT_SYMBOL(pnx4008_alloc_dum_channel);
520
521int pnx4008_free_dum_channel(int channr, int dev_id)
522{
523 if (channr < 0 || channr > MAX_DUM_CHANNELS)
524 return -EINVAL;
525 else if (dum_data.fb_owning_channel[channr] != dev_id)
526 return -EFBNOTOWNER;
527 else {
528 clear_channel(channr);
529 dum_data.fb_owning_channel[channr] = -1;
530 }
531
532 return 0;
533}
534
535EXPORT_SYMBOL(pnx4008_free_dum_channel);
536
537int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id)
538{
539 int i = chan_uf.channelnr;
540 int ret;
541
542 if (i < 0 || i > MAX_DUM_CHANNELS)
543 return -EINVAL;
544 else if (dum_data.fb_owning_channel[i] != dev_id)
545 return -EFBNOTOWNER;
546 else if ((ret =
547 display_open(chan_uf.channelnr, 0, chan_uf.dirty,
548 chan_uf.source, chan_uf.y_offset,
549 chan_uf.x_offset, chan_uf.height,
550 chan_uf.width)) != 0)
551 return ret;
552 else {
553 dum_data.chan_uf_store[i].dirty = chan_uf.dirty;
554 dum_data.chan_uf_store[i].source = chan_uf.source;
555 dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset;
556 dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset;
557 dum_data.chan_uf_store[i].width = chan_uf.width;
558 dum_data.chan_uf_store[i].height = chan_uf.height;
559 }
560
561 return 0;
562}
563
564EXPORT_SYMBOL(pnx4008_put_dum_channel_uf);
565
566int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id)
567{
568 if (channr < 0 || channr > MAX_DUM_CHANNELS)
569 return -EINVAL;
570 else if (dum_data.fb_owning_channel[channr] != dev_id)
571 return -EFBNOTOWNER;
572 else {
573 if (val == CONF_SYNC_ON) {
574 DUM_CH_CONF(channr) |= CONF_SYNCENABLE;
575 DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK |
576 DUM_CHANNEL_CFG_SYNC_MASK_SET;
577 } else if (val == CONF_SYNC_OFF)
578 DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE;
579 else
580 return -EINVAL;
581 }
582
583 return 0;
584}
585
586EXPORT_SYMBOL(pnx4008_set_dum_channel_sync);
587
588int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id)
589{
590 if (channr < 0 || channr > MAX_DUM_CHANNELS)
591 return -EINVAL;
592 else if (dum_data.fb_owning_channel[channr] != dev_id)
593 return -EFBNOTOWNER;
594 else {
595 if (val == CONF_DIRTYDETECTION_ON)
596 DUM_CH_CONF(channr) |= CONF_DIRTYENABLE;
597 else if (val == CONF_DIRTYDETECTION_OFF)
598 DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE;
599 else
600 return -EINVAL;
601 }
602
603 return 0;
604}
605
606EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect);
607
608#if 0 /* Functions not used currently, but likely to be used in future */
609
610static int get_channel(struct dumchannel *p_chan)
611{
612 int i = p_chan->channelnr;
613
614 if (i < 0 || i > MAX_DUM_CHANNELS)
615 return -EINVAL;
616 else {
617 p_chan->dum_ch_min = DUM_CH_MIN(i);
618 p_chan->dum_ch_max = DUM_CH_MAX(i);
619 p_chan->dum_ch_conf = DUM_CH_CONF(i);
620 p_chan->dum_ch_stat = DUM_CH_STAT(i);
621 p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */
622 }
623
624 return 0;
625}
626
627int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id)
628{
629 int i = p_chan_uf->channelnr;
630
631 if (i < 0 || i > MAX_DUM_CHANNELS)
632 return -EINVAL;
633 else if (dum_data.fb_owning_channel[i] != dev_id)
634 return -EFBNOTOWNER;
635 else {
636 p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty;
637 p_chan_uf->source = dum_data.chan_uf_store[i].source;
638 p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset;
639 p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset;
640 p_chan_uf->width = dum_data.chan_uf_store[i].width;
641 p_chan_uf->height = dum_data.chan_uf_store[i].height;
642 }
643
644 return 0;
645}
646
647EXPORT_SYMBOL(pnx4008_get_dum_channel_uf);
648
649int pnx4008_get_dum_channel_config(int channr, int dev_id)
650{
651 int ret;
652 struct dumchannel chan;
653
654 if (channr < 0 || channr > MAX_DUM_CHANNELS)
655 return -EINVAL;
656 else if (dum_data.fb_owning_channel[channr] != dev_id)
657 return -EFBNOTOWNER;
658 else {
659 chan.channelnr = channr;
660 if ((ret = get_channel(&chan)) != 0)
661 return ret;
662 }
663
664 return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK);
665}
666
667EXPORT_SYMBOL(pnx4008_get_dum_channel_config);
668
669int pnx4008_force_update_dum_channel(int channr, int dev_id)
670{
671 if (channr < 0 || channr > MAX_DUM_CHANNELS)
672 return -EINVAL;
673
674 else if (dum_data.fb_owning_channel[channr] != dev_id)
675 return -EFBNOTOWNER;
676 else
677 DUM_CH_CTRL(channr) = CTRL_SETDIRTY;
678
679 return 0;
680}
681
682EXPORT_SYMBOL(pnx4008_force_update_dum_channel);
683
684#endif
685
686int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma,
687 struct device *dev)
688{
689 unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
690
691 if (off < info->fix.smem_len) {
692 vma->vm_pgoff += 1;
693 return dma_mmap_writecombine(dev, vma,
694 (void *)dum_data.lcd_virt_start,
695 dum_data.lcd_phys_start,
696 FB_DMA_SIZE);
697 }
698 return -EINVAL;
699}
700
701EXPORT_SYMBOL(pnx4008_sdum_mmap);
702
703int pnx4008_set_dum_exit_notification(int dev_id)
704{
705 int i;
706
707 for (i = 0; i < MAX_DUM_CHANNELS; i++)
708 if (dum_data.fb_owning_channel[i] == dev_id)
709 return -ERESOURCESNOTFREED;
710
711 return 0;
712}
713
714EXPORT_SYMBOL(pnx4008_set_dum_exit_notification);
715
716/* Platform device driver for DUM */
717
718static int sdum_suspend(struct platform_device *pdev, pm_message_t state)
719{
720 int retval = 0;
721 struct clk *clk;
722
723 clk = clk_get(0, "dum_ck");
724 if (!IS_ERR(clk)) {
725 clk_set_rate(clk, 0);
726 clk_put(clk);
727 } else
728 retval = PTR_ERR(clk);
729
730 /* disable BAC */
731 DUM_CTRL = V_BAC_DISABLE_IDLE;
732
733 /* LCD standby & turn off display */
734 lcd_reset();
735
736 return retval;
737}
738
739static int sdum_resume(struct platform_device *pdev)
740{
741 int retval = 0;
742 struct clk *clk;
743
744 clk = clk_get(0, "dum_ck");
745 if (!IS_ERR(clk)) {
746 clk_set_rate(clk, 1);
747 clk_put(clk);
748 } else
749 retval = PTR_ERR(clk);
750
751 /* wait for BAC disable */
752 DUM_CTRL = V_BAC_DISABLE_TRIG;
753
754 while (DUM_CTRL & BAC_ENABLED)
755 udelay(10);
756
757 /* re-init LCD */
758 lcd_init();
759
760 /* enable BAC and reset MUX */
761 DUM_CTRL = V_BAC_ENABLE;
762 udelay(1);
763 DUM_CTRL = V_MUX_RESET;
764 return 0;
765}
766
767static int __devinit sdum_probe(struct platform_device *pdev)
768{
769 int ret = 0, i = 0;
770
771 /* map frame buffer */
772 dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev,
773 FB_DMA_SIZE,
774 &dum_data.lcd_phys_start,
775 GFP_KERNEL);
776
777 if (!dum_data.lcd_virt_start) {
778 ret = -ENOMEM;
779 goto out_3;
780 }
781
782 /* map slave registers */
783 dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE;
784 dum_data.slave_virt_base =
785 (u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32));
786
787 if (dum_data.slave_virt_base == NULL) {
788 ret = -ENOMEM;
789 goto out_2;
790 }
791
792 /* initialize DUM and LCD display */
793 ret = dum_init(pdev);
794 if (ret)
795 goto out_1;
796
797 dum_chan_init();
798 lcd_init();
799
800 DUM_CTRL = V_BAC_ENABLE;
801 udelay(1);
802 DUM_CTRL = V_MUX_RESET;
803
804 /* set decode address and sync clock divider */
805 DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK;
806 DUM_CLK_DIV = PNX4008_DUM_CLK_DIV;
807
808 for (i = 0; i < MAX_DUM_CHANNELS; i++)
809 dum_data.fb_owning_channel[i] = -1;
810
811 /*setup wakeup interrupt */
812 start_int_set_rising_edge(SE_DISP_SYNC_INT);
813 start_int_ack(SE_DISP_SYNC_INT);
814 start_int_umask(SE_DISP_SYNC_INT);
815
816 return 0;
817
818out_1:
819 iounmap((void *)dum_data.slave_virt_base);
820out_2:
821 dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
822 (void *)dum_data.lcd_virt_start,
823 dum_data.lcd_phys_start);
824out_3:
825 return ret;
826}
827
828static int sdum_remove(struct platform_device *pdev)
829{
830 struct clk *clk;
831
832 start_int_mask(SE_DISP_SYNC_INT);
833
834 clk = clk_get(0, "dum_ck");
835 if (!IS_ERR(clk)) {
836 clk_set_rate(clk, 0);
837 clk_put(clk);
838 }
839
840 iounmap((void *)dum_data.slave_virt_base);
841
842 dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
843 (void *)dum_data.lcd_virt_start,
844 dum_data.lcd_phys_start);
845
846 return 0;
847}
848
849static struct platform_driver sdum_driver = {
850 .driver = {
851 .name = "sdum",
852 },
853 .probe = sdum_probe,
854 .remove = sdum_remove,
855 .suspend = sdum_suspend,
856 .resume = sdum_resume,
857};
858
859int __init sdum_init(void)
860{
861 return platform_driver_register(&sdum_driver);
862}
863
864static void __exit sdum_exit(void)
865{
866 platform_driver_unregister(&sdum_driver);
867};
868
869module_init(sdum_init);
870module_exit(sdum_exit);
871
872MODULE_LICENSE("GPL");
diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h
new file mode 100644
index 000000000000..e8c5dcdd8813
--- /dev/null
+++ b/drivers/video/pnx4008/sdum.h
@@ -0,0 +1,139 @@
1/*
2 * Copyright (C) 2005 Philips Semiconductors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
18*/
19
20#define MAX_DUM_CHANNELS 64
21
22#define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000)
23
24#define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1)
25#define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1)
26
27#define CTRL_SETDIRTY (0x00000001)
28#define CONF_DIRTYENABLE (0x00000020)
29#define CONF_SYNCENABLE (0x00000004)
30
31#define DIRTY_ENABLED(conf) ((conf) & 0x0020)
32#define SYNC_ENABLED(conf) ((conf) & 0x0004)
33
34/* Display 1 & 2 Write Timing Configuration */
35#define PNX4008_DUM_WT_CFG 0x00372000
36
37/* Display 1 & 2 Read Timing Configuration */
38#define PNX4008_DUM_RT_CFG 0x00003A47
39
40/* DUM Transit State Timing Configuration */
41#define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */
42
43/* DUM Sync count clock divider */
44#define PNX4008_DUM_CLK_DIV 0x02DD
45
46/* Memory size for framebuffer, allocated through dma_alloc_writecombine().
47 * Must be PAGE aligned
48 */
49#define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE))
50
51#define OFFSET_RGBBUFFER (0xB0000)
52#define OFFSET_YUVBUFFER (0x00000)
53
54#define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER)
55#define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER)
56
57#define CMDSTRING_BASEADDR (0x00C000) /* iram */
58#define BYTES_PER_CMDSTRING (0x80)
59#define NR_OF_CMDSTRINGS (64)
60
61#define MAX_NR_PRESTRINGS (0x40)
62#define MAX_NR_POSTSTRINGS (0x40)
63
64/* various mask definitions */
65#define DUM_CLK_ENABLE 0x01
66#define DUM_CLK_DISABLE 0
67#define DUM_DECODE_MASK 0x1FFFFFFF
68#define DUM_CHANNEL_CFG_MASK 0x01FF
69#define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF
70#define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00
71
72#define SDUM_RETURNVAL_BASE (0x500)
73
74#define CONF_SYNC_OFF (0x602)
75#define CONF_SYNC_ON (0x603)
76
77#define CONF_DIRTYDETECTION_OFF (0x600)
78#define CONF_DIRTYDETECTION_ON (0x601)
79
80/* Set the corresponding bit. */
81#define BIT(n) (0x1U << (n))
82
83struct dumchannel_uf {
84 int channelnr;
85 u32 *dirty;
86 u32 *source;
87 u32 x_offset;
88 u32 y_offset;
89 u32 width;
90 u32 height;
91};
92
93enum {
94 FB_TYPE_YUV,
95 FB_TYPE_RGB
96};
97
98struct cmdstring {
99 int channelnr;
100 uint16_t prestringlen;
101 uint16_t poststringlen;
102 uint16_t format;
103 uint16_t reserved;
104 uint16_t startaddr_low;
105 uint16_t startaddr_high;
106 uint16_t pixdatlen_low;
107 uint16_t pixdatlen_high;
108 u32 precmd[MAX_NR_PRESTRINGS];
109 u32 postcmd[MAX_NR_POSTSTRINGS];
110
111};
112
113struct dumchannel {
114 int channelnr;
115 int dum_ch_min;
116 int dum_ch_max;
117 int dum_ch_conf;
118 int dum_ch_stat;
119 int dum_ch_ctrl;
120};
121
122int pnx4008_alloc_dum_channel(int dev_id);
123int pnx4008_free_dum_channel(int channr, int dev_id);
124
125int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id);
126int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id);
127
128int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id);
129int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id);
130
131int pnx4008_force_dum_update_channel(int channr, int dev_id);
132
133int pnx4008_get_dum_channel_config(int channr, int dev_id);
134
135int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev);
136int pnx4008_set_dum_exit_notification(int dev_id);
137
138int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
139 dma_addr_t * phys_addr, int *fb_length);