* PXA fb overlay support (RESUBMIT 2).
@ 2008-09-10 8:07 Rodolfo Giometti
2008-09-10 8:07 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Rodolfo Giometti
0 siblings, 1 reply; 5+ messages in thread
From: Rodolfo Giometti @ 2008-09-10 8:07 UTC (permalink / raw)
To: linux-arm; +Cc: Eric Miao, Russell King, linux-kernel
This patch set implements the port of the old pxafb overlay support
for 2.6.22 to the latest kernel version.
It also adds the mmap() methods and fixes up an issue related to the
consistent memory allocation error which causes a segfault during
mmap().
Rodolfo
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x.
2008-09-10 8:07 PXA fb overlay support (RESUBMIT 2) Rodolfo Giometti
@ 2008-09-10 8:07 ` Rodolfo Giometti
2008-09-10 8:07 ` [PATCH 2/2] PXA: add configurable consistent memory DMA size Rodolfo Giometti
2008-09-13 10:05 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Andrew Morton
0 siblings, 2 replies; 5+ messages in thread
From: Rodolfo Giometti @ 2008-09-10 8:07 UTC (permalink / raw)
To: linux-arm; +Cc: Eric Miao, Russell King, linux-kernel, Rodolfo Giometti
From: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
arch/arm/mach-pxa/include/mach/regs-lcd.h | 39 +
drivers/video/Kconfig | 6 +
drivers/video/Makefile | 1 +
drivers/video/pxafb.c | 75 ++-
drivers/video/pxafb.h | 74 ++
drivers/video/pxafb_overlay.c | 1476 +++++++++++++++++++++++++++++
6 files changed, 1654 insertions(+), 17 deletions(-)
create mode 100644 drivers/video/pxafb_overlay.c
diff --git a/arch/arm/mach-pxa/include/mach/regs-lcd.h b/arch/arm/mach-pxa/include/mach/regs-lcd.h
index c689c4e..7439bfb 100644
--- a/arch/arm/mach-pxa/include/mach/regs-lcd.h
+++ b/arch/arm/mach-pxa/include/mach/regs-lcd.h
@@ -14,10 +14,21 @@
#define LCCR5 (0x014) /* LCD Controller Control Register 5 */
#define DFBR0 (0x020) /* DMA Channel 0 Frame Branch Register */
#define DFBR1 (0x024) /* DMA Channel 1 Frame Branch Register */
+#define DFBR2 (0x028) /* DMA Channel 2 Frame Branch Register */
+#define DFBR3 (0x02C) /* DMA Channel 3 Frame Branch Register */
+#define DFBR4 (0x030) /* DMA Channel 4 Frame Branch Register */
+#define DFBR5 (0x110) /* DMA Channel 5 Frame Branch Register */
+#define DFBR6 (0x114) /* DMA Channel 6 Frame Branch Register */
+#define LCSR1 (0x034) /* LCD Controller Status Register 1 */
#define LCSR (0x038) /* LCD Controller Status Register */
#define LIIDR (0x03C) /* LCD Controller Interrupt ID Register */
#define TMEDRGBR (0x040) /* TMED RGB Seed Register */
#define TMEDCR (0x044) /* TMED Control Register */
+#define OVL1C1 (0x050) /* Overlay 1 Control Register 1 */
+#define OVL1C2 (0x060) /* Overlay 1 Control Register 2 */
+#define OVL2C1 (0x070) /* Overlay 2 Control Register 1 */
+#define OVL2C2 (0x080) /* Overlay 2 Control Register 2 */
+#define CCR (0x090) /* Cursor Control Register */
#define CMDCR (0x100) /* Command Control Register */
#define PRSR (0x104) /* Panel Read Status Register */
@@ -52,6 +63,21 @@
#define FSADR1 (0x214) /* DMA Channel 1 Frame Source Address Register */
#define FIDR1 (0x218) /* DMA Channel 1 Frame ID Register */
#define LDCMD1 (0x21C) /* DMA Channel 1 Command Register */
+#define FDADR2 (0x220) /* DMA Channel 2 Frame Descriptor Address Register */
+#define FSADR2 (0x224) /* DMA Channel 2 Frame Source Address Register */
+#define FIDR2 (0x228) /* DMA Channel 2 Frame ID Register */
+#define FDADR3 (0x230) /* DMA Channel 3 Frame Descriptor Address Register */
+#define FSADR3 (0x234) /* DMA Channel 3 Frame Source Address Register */
+#define FIDR3 (0x238) /* DMA Channel 3 Frame ID Register */
+#define LDCMD3 (0x23C) /* DMA Channel 3 Command Register */
+#define FDADR4 (0x240) /* DMA Channel 4 Frame Descriptor Address Register */
+#define FSADR4 (0x244) /* DMA Channel 4 Frame Source Address Register */
+#define FIDR4 (0x248) /* DMA Channel 4 Frame ID Register */
+#define LDCMD4 (0x24C) /* DMA Channel 4 Command Register */
+#define FDADR5 (0x250) /* DMA Channel 5 Frame Descriptor Address Register */
+#define FSADR5 (0x254) /* DMA Channel 5 Frame Source Address Register */
+#define FIDR5 (0x258) /* DMA Channel 5 Frame ID Register */
+#define LDCMD5 (0x25C) /* DMA Channel 5 Command Register */
#define FDADR6 (0x260) /* DMA Channel 6 Frame Descriptor Address Register */
#define FSADR6 (0x264) /* DMA Channel 6 Frame Source Address Register */
#define FIDR6 (0x268) /* DMA Channel 6 Frame ID Register */
@@ -143,6 +169,10 @@
#define LCCR5_EOFM(x) (1 << ((x) + 7)) /* end of frame mask */
#define LCCR5_SOFM(x) (1 << ((x) + 0)) /* start of frame mask */
+#define OVL1C1_O1EN (1 << 31) /* Enable bit for Overlay 1 */
+#define OVL2C1_O2EN (1 << 31) /* Enable bit for Overlay 2 */
+#define CCR_CEN (1 << 31) /* Enable bit for Cursor */
+
#define LCSR_LDD (1 << 0) /* LCD Disable Done */
#define LCSR_SOF (1 << 1) /* Start of frame */
#define LCSR_BER (1 << 2) /* Bus error */
@@ -159,6 +189,15 @@
#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
+/* Overlay1 & Overlay2 & Hardware Cursor */
+#define LCSR1_SOF(x) (1 << ((x) + 0)) /* start of frame */
+#define LCSR1_EOF(x) (1 << ((x) + 7)) /* end of frame */
+#define LCSR1_BS(x) (1 << ((x) + 15)) /* branch status */
+#define LCSR1_IU(x) (1 << ((x) + 23)) /* input FIFO underrun */
+
+#define LDCMD_SOFINT (1 << 22)
+#define LDCMD_EOFINT (1 << 21)
+
/* smartpanel related */
#define PRSR_DATA(x) ((x) & 0xff) /* Panel Data */
#define PRSR_A0 (1 << 8) /* Read Data Source */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 70d135e..5d5c8c8 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1802,6 +1802,12 @@ config FB_PXA_SMARTPANEL
default n
depends on FB_PXA
+config FB_PXA_OVERLAY
+ bool "PXA LCD overlay support"
+ depends on FB_PXA && PXA27x
+ ---help---
+ Frame buffer overlay driver for PXA27x
+
config FB_PXA_PARAMETERS
bool "PXA LCD command line parameters"
default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a6b5529..4968776 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE) += gbefb.o
obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o
obj-$(CONFIG_FB_PXA) += pxafb.o
+obj-$(CONFIG_FB_PXA_OVERLAY) += pxafb_overlay.o
obj-$(CONFIG_FB_W100) += w100fb.o
obj-$(CONFIG_FB_AU1100) += au1100fb.o
obj-$(CONFIG_FB_AU1200) += au1200fb.o
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 9720449..c17a6f3 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -74,19 +74,6 @@ static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
static int pxafb_activate_var(struct fb_var_screeninfo *var,
struct pxafb_info *);
-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
-
-static inline unsigned long
-lcd_readl(struct pxafb_info *fbi, unsigned int off)
-{
- return __raw_readl(fbi->mmio_base + off);
-}
-
-static inline void
-lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
-{
- __raw_writel(val, fbi->mmio_base + off);
-}
static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
{
@@ -488,7 +475,7 @@ static int pxafb_blank(int blank, struct fb_info *info)
for (i = 0; i < fbi->palette_size; i++)
pxafb_setpalettereg(i, 0, 0, 0, 0, info);
- pxafb_schedule_work(fbi, C_DISABLE);
+ pxafb_schedule_work(fbi, C_BLANK);
/* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
break;
@@ -497,7 +484,7 @@ static int pxafb_blank(int blank, struct fb_info *info)
if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&fbi->fb.cmap, info);
- pxafb_schedule_work(fbi, C_ENABLE);
+ pxafb_schedule_work(fbi, C_UNBLANK);
}
return 0;
}
@@ -928,6 +915,9 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
fbi->reg_lccr0 = fbi->lccr0 |
(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+#ifdef CONFIG_FB_PXA_OVERLAY
+ LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM |
+#endif
LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
@@ -936,7 +926,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) {
nbytes = nbytes / 2;
- setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes);
+ setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes,
+ nbytes | LDCMD_EOFINT);
}
if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT))
@@ -1116,7 +1107,7 @@ static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
* sleep when disabling the LCD controller, or if we get two contending
* processes trying to alter state.
*/
-static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
+void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
{
u_int old_state;
@@ -1139,6 +1130,8 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
fbi->state = state;
/* TODO __pxafb_lcd_power(fbi, 0); */
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
pxafb_disable_controller(fbi);
}
break;
@@ -1152,6 +1145,8 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
fbi->state = state;
__pxafb_backlight_power(fbi, 0);
__pxafb_lcd_power(fbi, 0);
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
if (old_state != C_DISABLE_CLKCHANGE)
pxafb_disable_controller(fbi);
}
@@ -1166,6 +1161,8 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
fbi->state = C_ENABLE;
pxafb_enable_controller(fbi);
/* TODO __pxafb_lcd_power(fbi, 1); */
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
}
break;
@@ -1177,9 +1174,13 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
*/
if (old_state == C_ENABLE) {
__pxafb_lcd_power(fbi, 0);
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_DISABLE);
pxafb_disable_controller(fbi);
pxafb_setup_gpio(fbi);
pxafb_enable_controller(fbi);
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
__pxafb_lcd_power(fbi, 1);
}
break;
@@ -1205,8 +1206,42 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
pxafb_enable_controller(fbi);
__pxafb_lcd_power(fbi, 1);
__pxafb_backlight_power(fbi, 1);
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_ENABLE);
}
break;
+
+ case C_BLANK:
+ /*
+ * Disable controller, blank overlays if exist.
+ */
+ if ((old_state != C_DISABLE) && (old_state != C_BLANK)) {
+ fbi->state = state;
+ __pxafb_backlight_power(fbi, 0);
+ __pxafb_lcd_power(fbi, 0);
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_BLANK);
+ if (old_state != C_DISABLE_CLKCHANGE)
+ pxafb_disable_controller(fbi);
+ }
+ break;
+
+ case C_UNBLANK:
+ /*
+ * Power up the LCD screen, enable controller, and
+ * turn on the backlight, unblank overlays if exist.
+ */
+ if ((old_state != C_ENABLE) && (old_state != C_UNBLANK)) {
+ fbi->state = C_UNBLANK;
+ pxafb_setup_gpio(fbi);
+ pxafb_enable_controller(fbi);
+ __pxafb_lcd_power(fbi, 1);
+ __pxafb_backlight_power(fbi, 1);
+ if (fbi->set_overlay_ctrlr_state)
+ fbi->set_overlay_ctrlr_state(fbi, C_UNBLANK);
+ }
+ break;
+
}
mutex_unlock(&fbi->ctrlr_lock);
}
@@ -1362,6 +1397,8 @@ static void pxafb_decode_mode_info(struct pxafb_info *fbi,
if (smemlen > fbi->fb.fix.smem_len)
fbi->fb.fix.smem_len = smemlen;
}
+
+ fbi->set_overlay_ctrlr_state = NULL;
}
static void pxafb_decode_mach_info(struct pxafb_info *fbi,
@@ -1839,6 +1876,10 @@ static int __devinit pxafb_probe(struct platform_device *dev)
CPUFREQ_POLICY_NOTIFIER);
#endif
+#ifdef CONFIG_FB_PXA_OVERLAY
+ pxafb_overlay_probe(&dev->dev);
+#endif
+
/*
* Ok, now enable the LCD controller
*/
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 31541b8..16b12f4 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -61,6 +61,56 @@ struct pxafb_dma_buff {
struct pxafb_dma_descriptor dma_desc[DMA_MAX];
};
+#ifdef CONFIG_FB_PXA_OVERLAY
+struct overlayfb_info
+{
+ struct fb_info fb;
+
+ struct fb_var_screeninfo old_var;
+
+ atomic_t refcount;
+
+ u_char * map_cpu;
+ u_char * screen_cpu;
+ u_int * palette_cpu;
+ unsigned long map_size;
+ unsigned long palette_size;
+ ssize_t video_offset;
+
+ dma_addr_t screen_dma;
+ dma_addr_t map_dma;
+ dma_addr_t palette_dma;
+
+ volatile u_char state;
+
+ /* Overlay specific info */
+ unsigned long xpos; /* screen position (x, y) */
+ unsigned long ypos;
+ unsigned long format;
+
+ /* Additional */
+ union {
+ struct pxafb_dma_descriptor *dma0;
+ struct pxafb_dma_descriptor *dma1;
+ struct {
+ struct pxafb_dma_descriptor *dma2;
+ struct pxafb_dma_descriptor *dma3;
+ struct pxafb_dma_descriptor *dma4;
+ };
+ struct {
+ struct pxafb_dma_descriptor *dma5_pal;
+ struct pxafb_dma_descriptor *dma5_frame;
+ };
+ };
+};
+
+#define o1_to_basefb(d) container_of(d, struct pxafb_info, overlay1fb)
+#define o2_to_basefb(d) container_of(d, struct pxafb_info, overlay2fb)
+#define cu_to_basefb(d) container_of(d, struct pxafb_info, cursorfb)
+
+extern void pxafb_overlay_probe(struct device *dev);
+#endif
+
struct pxafb_info {
struct fb_info fb;
struct device *dev;
@@ -120,6 +170,13 @@ struct pxafb_info {
struct task_struct *smart_thread;
#endif
+#ifdef CONFIG_FB_PXA_OVERLAY
+ struct overlayfb_info overlay1fb;
+ struct overlayfb_info overlay2fb;
+ struct overlayfb_info cursorfb;
+#endif
+ void (*set_overlay_ctrlr_state)(struct pxafb_info *, u_int);
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
struct notifier_block freq_policy;
@@ -139,6 +196,11 @@ struct pxafb_info {
#define C_DISABLE_PM (5)
#define C_ENABLE_PM (6)
#define C_STARTUP (7)
+#define C_BLANK (8)
+#define C_UNBLANK (9)
+
+extern void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+
#define PXA_NAME "PXA"
@@ -148,4 +210,16 @@ struct pxafb_info {
#define MIN_XRES 64
#define MIN_YRES 64
+static inline unsigned long
+lcd_readl(struct pxafb_info *fbi, unsigned int off)
+{
+ return __raw_readl(fbi->mmio_base + off);
+}
+
+static inline void
+lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
+{
+ __raw_writel(val, fbi->mmio_base + off);
+}
+
#endif /* __PXAFB_H__ */
diff --git a/drivers/video/pxafb_overlay.c b/drivers/video/pxafb_overlay.c
new file mode 100644
index 0000000..25935b5
--- /dev/null
+++ b/drivers/video/pxafb_overlay.c
@@ -0,0 +1,1476 @@
+/*
+ * linux/drivers/video/pxafb_overlay.c
+ *
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * Code Status:
+ * 2008/07/21: Rodolfo Giometti <giometti@linux.it>
+ * - Ported to 2.6.26 kernel
+ * 2004/10/28: <yan.yin@intel.com>
+ * - Ported to 2.6 kernel
+ * - Made overlay driver a loadable module
+ * - Merged overlay optimized patch
+ * 2004/03/10: <stanley.cai@intel.com>
+ * - Fixed Bugs
+ * - Added workaround for overlay1&2
+ * 2003/08/27: <yu.tang@intel.com>
+ * - Added Overlay 1 & Overlay2 & Hardware Cursor support
+ *
+ *
+ * This software program is licensed subject to the GNU Lesser General
+ * Public License (LGPL). Version 2.1, February 1999, available at
+ * http://www.gnu.org/copyleft/lesser.html
+ *
+ * Intel PXA27x LCD Controller Frame Buffer Overlay Driver
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/bitfield.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "pxafb.h"
+
+/* LCD enhancement : Overlay 1 & 2 & Hardware Cursor */
+
+/*
+ * LCD enhancement : Overlay 1
+ *
+ * Features:
+ * - support 16bpp (No palette)
+ */
+
+static int overlay1fb_enable(struct fb_info *info);
+static int overlay2fb_enable(struct fb_info *info);
+static int cursorfb_enable(struct fb_info *info);
+
+static int overlay1fb_disable(struct fb_info *info);
+static int overlay2fb_disable(struct fb_info *info);
+static int cursorfb_disable(struct fb_info *info);
+
+static int overlay1fb_blank(int blank, struct fb_info *info);
+static int overlay2fb_blank(int blank, struct fb_info *info);
+static int cursorfb_blank(int blank, struct fb_info *info);
+
+static struct pxafb_rgb def_rgb_18 = {
+ .red = { offset: 12, length: 6, },
+ .green = { offset: 6, length: 6, },
+ .blue = { offset: 0, length: 6, },
+ .transp = { offset: 0, length: 0, },
+};
+
+static struct pxafb_rgb def_rgbt_16 = {
+ .red = { offset: 10, length: 5, },
+ .green = { offset: 5, length: 5, },
+ .blue = { offset: 0, length: 5, },
+ .transp = { offset: 15, length: 1, },
+};
+
+static struct pxafb_rgb def_rgbt_19 = {
+ .red = { offset: 12, length: 6, },
+ .green = { offset: 6, length: 6, },
+ .blue = { offset: 0, length: 6, },
+ .transp = { offset: 18, length: 1, },
+};
+
+static struct pxafb_rgb def_rgbt_24 = {
+ .red = { offset: 16, length: 7, },
+ .green = { offset: 8, length: 8, },
+ .blue = { offset: 0, length: 8, },
+ .transp = { offset: 0, length: 0, },
+};
+
+static struct pxafb_rgb def_rgbt_25 = {
+ .red = { offset: 16, length: 8, },
+ .green = { offset: 8, length: 8, },
+ .blue = { offset: 0, length: 8, },
+ .transp = { offset: 24, length: 1, },
+};
+
+#define CLEAR_LCD_INTR(reg, intr) do { \
+ reg = (intr); \
+} while (0)
+
+#define WAIT_FOR_LCD_INTR(bfi, reg, intr, timeout) ({ \
+ int __done = 0; \
+ int __t = timeout; \
+ while (__t) { \
+ __done = lcd_readl(bfi, reg) & (intr); \
+ if (__done) \
+ break; \
+ mdelay(10); \
+ __t--; \
+ } \
+ if (!__t) \
+ dev_info(bfi->dev, "wait " #intr " timeount"); \
+ __done; \
+})
+
+#define DISABLE_OVERLAYS(fbi) do { \
+ if (fbi->overlay1fb.state == C_ENABLE) \
+ overlay1fb_disable((struct fb_info *) &fbi->overlay1fb);\
+ if (fbi->overlay2fb.state == C_ENABLE) \
+ overlay2fb_disable((struct fb_info *) &fbi->overlay2fb);\
+ if (fbi->cursorfb.state == C_ENABLE) \
+ cursorfb_disable((struct fb_info *) &fbi->cursorfb); \
+} while (0)
+
+#define ENABLE_OVERLAYS(fbi) do { \
+ if (fbi->overlay1fb.state == C_DISABLE) \
+ overlay1fb_enable((struct fb_info *) &fbi->overlay1fb); \
+ if (fbi->overlay2fb.state == C_DISABLE) \
+ overlay2fb_enable((struct fb_info *) &fbi->overlay2fb); \
+ if (fbi->cursorfb.state == C_DISABLE) \
+ cursorfb_enable((struct fb_info *) &fbi->cursorfb); \
+} while (0)
+
+#define BLANK_OVERLAYS(fbi) do { \
+ if (fbi->overlay1fb.state == C_ENABLE) { \
+ overlay1fb_disable((struct fb_info *) &fbi->overlay1fb);\
+ fbi->overlay1fb.state = C_BLANK; \
+ } \
+ if (fbi->overlay2fb.state == C_ENABLE) { \
+ overlay2fb_disable((struct fb_info *) &fbi->overlay2fb);\
+ fbi->overlay2fb.state = C_BLANK; \
+ } \
+ if (fbi->cursorfb.state == C_ENABLE) { \
+ cursorfb_disable((struct fb_info *) &fbi->cursorfb); \
+ fbi->cursorfb.state = C_BLANK; \
+ } \
+} while (0)
+
+#define UNBLANK_OVERLAYS(fbi) do { \
+ if (fbi->overlay1fb.state == C_BLANK) { \
+ overlay1fb_enable((struct fb_info *) &fbi->overlay1fb); \
+ fbi->overlay1fb.state = C_ENABLE; \
+ } \
+ if (fbi->overlay2fb.state == C_BLANK) { \
+ overlay2fb_enable((struct fb_info *) &fbi->overlay2fb); \
+ fbi->overlay2fb.state = C_ENABLE; \
+ } \
+ if (fbi->cursorfb.state == C_BLANK) { \
+ cursorfb_enable((struct fb_info *) &fbi->cursorfb); \
+ fbi->cursorfb.state = C_ENABLE; \
+ } \
+} while (0)
+
+static int overlay1fb_open(struct fb_info *info, int user)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ int ret = 0;
+
+ if (!atomic_dec_and_test(&fbi->refcount)) {
+ atomic_inc(&fbi->refcount);
+ return -EACCES;
+ }
+
+ /* If basefb is disable, enable fb */
+ if (o1_to_basefb(fbi)->state != C_ENABLE)
+ o1_to_basefb(fbi)->fb.fbops->fb_blank(VESA_NO_BLANKING,
+ (struct fb_info *) o1_to_basefb(fbi));
+
+ /* Initialize the variables in overlay1 framebuffer */
+ fbi->fb.var.xres = fbi->fb.var.yres = 0;
+ fbi->fb.var.bits_per_pixel = 0;
+
+ return ret;
+}
+
+static int overlay1fb_release(struct fb_info *info, int user)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+ /* Disable overlay when released */
+ overlay1fb_blank(1, info);
+
+ atomic_inc(&fbi->refcount);
+
+ return 0;
+}
+
+static int overlay1fb_map_video_memory(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+ if (fbi->map_cpu)
+ dma_free_writecombine(o1_to_basefb(fbi)->dev, fbi->map_size,
+ (void *) fbi->map_cpu, fbi->map_dma);
+ fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+ fbi->map_cpu = dma_alloc_writecombine(o1_to_basefb(fbi)->dev,
+ fbi->map_size, &fbi->map_dma,
+ GFP_KERNEL);
+ if (!fbi->map_cpu)
+ return -ENOMEM;
+
+ /* Prevent initial garbage on screen */
+ memset(fbi->map_cpu, 0, fbi->map_size);
+ fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
+ fbi->fb.fix.smem_start = fbi->screen_dma;
+
+ /* Setup dma descriptor */
+ fbi->dma1 = (struct pxafb_dma_descriptor *)
+ (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
+
+ fbi->dma1->fdadr = (fbi->screen_dma -
+ sizeof(struct pxafb_dma_descriptor));
+ fbi->dma1->fsadr = fbi->screen_dma;
+ fbi->dma1->fidr = 0;
+ fbi->dma1->ldcmd = fbi->fb.fix.smem_len;
+
+ return 0;
+}
+
+static int overlay1fb_enable(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+ unsigned long bpp1;
+ unsigned int lccr5;
+
+ if (!fbi->map_cpu)
+ return -EINVAL;
+
+ switch (fbi->fb.var.bits_per_pixel) {
+ case 16:
+ bpp1 = 0x4;
+ break;
+ case 18:
+ bpp1 = 0x6;
+ break;
+ case 19:
+ bpp1 = 0x8;
+ break;
+ case 24:
+ bpp1 = 0x9;
+ break;
+ case 25:
+ bpp1 = 0xa;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Disable branch/start/end of frame interrupt */
+ lccr5 = lcd_readl(o1_to_basefb(fbi), LCCR5);
+ lcd_writel(o1_to_basefb(fbi), LCCR5,
+ lccr5 | LCCR5_IUM(1) | LCCR5_BSM(1)
+ | LCCR5_EOFM(1) | LCCR5_SOFM(1));
+
+ if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+ lcd_writel(o1_to_basefb(fbi), FDADR1, fbi->dma1->fdadr);
+ else
+ lcd_writel(o1_to_basefb(fbi), DFBR1, fbi->dma1->fdadr | 0x1);
+
+ /* Enable overlay 1 window */
+ lcd_writel(o1_to_basefb(fbi), OVL1C2,
+ (fbi->ypos << 10) | fbi->xpos);;
+ lcd_writel(o1_to_basefb(fbi), OVL1C1,
+ OVL1C1_O1EN | (bpp1 << 20) |
+ ((fbi->fb.var.yres-1)<<10) |
+ (fbi->fb.var.xres-1));
+
+ fbi->state = C_ENABLE;
+
+ return 0;
+}
+
+static int overlay1fb_disable(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ int done;
+ unsigned int ovl1c1;
+
+ if ((fbi->state == C_DISABLE) || (fbi->state == C_BLANK))
+ return 0;
+
+ fbi->state = C_DISABLE;
+
+ /* Clear O1EN */
+ ovl1c1 = lcd_readl(o1_to_basefb(fbi), OVL1C1);
+ lcd_writel(o1_to_basefb(fbi), OVL1C1, ovl1c1 & ~OVL1C1_O1EN);
+
+ lcd_writel(o1_to_basefb(fbi), LCSR1, LCSR1_BS(1));
+ lcd_writel(o1_to_basefb(fbi), DFBR1, 0x3);
+ done = WAIT_FOR_LCD_INTR(o1_to_basefb(fbi), LCSR1, LCSR1_BS(1), 100);
+
+ if (!done) {
+ dev_info(o1_to_basefb(fbi)->dev, "%s: timeout\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+static int overlay1fb_blank(int blank, struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ int err = 0;
+
+ switch (blank) {
+ case 0:
+ err = overlay1fb_enable(info);
+ if (err) {
+ fbi->state = C_DISABLE;
+ set_ctrlr_state(o1_to_basefb(fbi), C_REENABLE);
+ }
+ break;
+ case 1:
+ err = overlay1fb_disable(info);
+ if (err) {
+ fbi->state = C_DISABLE;
+ set_ctrlr_state(o1_to_basefb(fbi), C_REENABLE);
+ }
+ break;
+ }
+
+ return err;
+}
+
+static int overlay1fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ int xpos, ypos;
+
+ /* Must in base frame */
+ xpos = var->nonstd & 0x3ff;
+ ypos = (var->nonstd>>10) & 0x3ff;
+
+ if ((xpos + var->xres) > o1_to_basefb(fbi)->fb.var.xres)
+ return -EINVAL;
+
+ if ((ypos + var->yres) > o1_to_basefb(fbi)->fb.var.yres)
+ return -EINVAL;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ if (var->xres & 0x1) {
+ dev_err(o1_to_basefb(fbi)->dev,
+ "xres should be a multiple of 2 pixels!\n");
+ return -EINVAL;
+ }
+ break;
+ case 18:
+ case 19:
+ if (var->xres & 0x7) {
+ dev_err(o1_to_basefb(fbi)->dev,
+ "xres should be a multiple of 8 pixels!\n");
+ return -EINVAL;
+ }
+ break;
+ }
+
+ fbi->old_var = *var;
+
+ var->activate = FB_ACTIVATE_NOW;
+
+ return 0;
+}
+
+static int overlay1fb_set_par(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ struct fb_var_screeninfo *var = &fbi->fb.var;
+ int nbytes = 0, err = 0, pixels_per_line = 0;
+
+ info->flags &= ~FBINFO_MISC_USEREVENT;
+
+ if (fbi->state == C_BLANK)
+ return 0;
+
+ if (fbi->state == C_DISABLE)
+ goto out1;
+
+ /* Only xpos & ypos change */
+ if ((var->xres == fbi->old_var.xres) &&
+ (var->yres == fbi->old_var.yres) &&
+ (var->bits_per_pixel == fbi->old_var.bits_per_pixel))
+ goto out2;
+
+out1:
+ switch (var->bits_per_pixel) {
+ case 16:
+ /* 2 pixels per line */
+ pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
+ nbytes = 2;
+
+ var->red = def_rgbt_16.red;
+ var->green = def_rgbt_16.green;
+ var->blue = def_rgbt_16.blue;
+ var->transp = def_rgbt_16.transp;
+
+ break;
+ case 18:
+ /* 8 pixels per line */
+ pixels_per_line = (fbi->fb.var.xres + 0x7) & (~0x7);
+ nbytes = 3;
+
+ var->red = def_rgb_18.red;
+ var->green = def_rgb_18.green;
+ var->blue = def_rgb_18.blue;
+ var->transp = def_rgb_18.transp;
+
+ break;
+ case 19:
+ /* 8 pixels per line */
+ pixels_per_line = (fbi->fb.var.xres + 0x7) & (~0x7);
+ nbytes = 3;
+
+ var->red = def_rgbt_19.red;
+ var->green = def_rgbt_19.green;
+ var->blue = def_rgbt_19.blue;
+ var->transp = def_rgbt_19.transp;
+
+ break;
+ case 24:
+ pixels_per_line = fbi->fb.var.xres;
+ nbytes = 4;
+
+ var->red = def_rgbt_24.red;
+ var->green = def_rgbt_24.green;
+ var->blue = def_rgbt_24.blue;
+ var->transp = def_rgbt_24.transp;
+
+ break;
+ case 25:
+ pixels_per_line = fbi->fb.var.xres;
+ nbytes = 4;
+
+ var->red = def_rgbt_25.red;
+ var->green = def_rgbt_25.green;
+ var->blue = def_rgbt_25.blue;
+ var->transp = def_rgbt_25.transp;
+
+ break;
+ }
+
+ fbi->fb.fix.line_length = nbytes * pixels_per_line;
+ fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres;
+
+ err = overlay1fb_map_video_memory(info);
+ if (err)
+ return err;
+
+out2:
+ fbi->xpos = var->nonstd & 0x3ff;
+ fbi->ypos = (var->nonstd>>10) & 0x3ff;
+
+ overlay1fb_enable(info);
+
+ return 0;
+}
+
+static int overlay1fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (off < info->fix.smem_len) {
+ vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
+ return dma_mmap_writecombine(o1_to_basefb(fbi)->dev, vma,
+ fbi->map_cpu, fbi->map_dma,
+ fbi->map_size);
+ }
+ return -EINVAL;
+}
+
+static struct fb_ops overlay1fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = overlay1fb_open,
+ .fb_release = overlay1fb_release,
+ .fb_check_var = overlay1fb_check_var,
+ .fb_set_par = overlay1fb_set_par,
+ .fb_blank = overlay1fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = overlay1fb_mmap,
+};
+
+/*
+ * LCD enhancement : Overlay 2
+ *
+ * Features:
+ * - support planar YCbCr420/YCbCr422/YCbCr444;
+ */
+static int overlay2fb_open(struct fb_info *info, int user)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+ if (!atomic_dec_and_test(&fbi->refcount)) {
+ atomic_inc(&fbi->refcount);
+ return -EACCES;
+ }
+
+ /* If basefb is disable, enable fb */
+ if (o2_to_basefb(fbi)->state != C_ENABLE)
+ o2_to_basefb(fbi)->fb.fbops->fb_blank(VESA_NO_BLANKING,
+ (struct fb_info *) o2_to_basefb(fbi));
+
+ fbi->fb.var.xres = fbi->fb.var.yres = 0;
+
+ return 0;
+}
+
+static int overlay2fb_release(struct fb_info *info, int user)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+ /* Disable overlay when released */
+ overlay2fb_blank(1, info);
+
+ atomic_inc(&fbi->refcount);
+
+ return 0;
+}
+
+static int overlay2fb_map_YUV_memory(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned int ylen, cblen, crlen, aylen, acblen, acrlen;
+ unsigned int yoff, cboff, croff;
+ unsigned int xres, yres;
+ unsigned int nbytes;
+
+ ylen = cblen = crlen = aylen = acblen = acrlen = 0;
+ yoff = cboff = croff = 0;
+
+ if (fbi->map_cpu)
+ dma_free_writecombine(o2_to_basefb(fbi)->dev, fbi->map_size,
+ fbi->map_cpu, fbi->map_dma);
+
+ yres = fbi->fb.var.yres;
+
+ switch (fbi->format) {
+ case 0x4: /* YCbCr 4:2:0 planar */
+ dev_dbg(o2_to_basefb(fbi)->dev, "420 planar\n");
+ /* 16 pixels per line */
+ xres = (fbi->fb.var.xres + 0xf) & (~0xf);
+ fbi->fb.fix.line_length = xres;
+
+ nbytes = xres * yres;
+ ylen = nbytes;
+ cblen = crlen = (nbytes/4);
+
+ break;
+ case 0x3: /* YCbCr 4:2:2 planar */
+ /* 8 pixles per line */
+ dev_dbg(o2_to_basefb(fbi)->dev, "422 planar\n");
+ xres = (fbi->fb.var.xres + 0x7) & (~0x7);
+ fbi->fb.fix.line_length = xres;
+
+ nbytes = xres * yres;
+ ylen = nbytes;
+ cblen = crlen = (nbytes/2);
+
+ break;
+ case 0x2: /* YCbCr 4:4:4 planar */
+ /* 4 pixels per line */
+ dev_dbg(o2_to_basefb(fbi)->dev, "444 planar\n");
+ xres = (fbi->fb.var.xres + 0x3) & (~0x3);
+ fbi->fb.fix.line_length = xres;
+
+ nbytes = xres * yres;
+ ylen = cblen = crlen = nbytes;
+ break;
+ }
+
+ /* 16-bytes alignment for DMA */
+ aylen = (ylen + 0xf) & (~0xf);
+ acblen = (cblen + 0xf) & (~0xf);
+ acrlen = (crlen + 0xf) & (~0xf);
+
+ fbi->fb.fix.smem_len = aylen + acblen + acrlen;
+
+ /* Alloc memory */
+
+ fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+ fbi->map_cpu = dma_alloc_writecombine(o2_to_basefb(fbi)->dev,
+ fbi->map_size, &fbi->map_dma,
+ GFP_KERNEL);
+ if (!fbi->map_cpu)
+ return -ENOMEM;
+
+ /* Prevent initial garbage on screen */
+ memset(fbi->map_cpu, 0, fbi->map_size);
+ fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
+ fbi->fb.fix.smem_start = fbi->screen_dma;
+
+ /* Setup dma for Planar format */
+ fbi->dma2 = (struct pxafb_dma_descriptor *)
+ (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
+ fbi->dma3 = fbi->dma2 - 1;
+ fbi->dma4 = fbi->dma3 - 1;
+
+ /* Offset */
+ yoff = 0;
+ cboff = aylen;
+ croff = cboff + acblen;
+
+ /* Y vector */
+ fbi->dma2->fdadr = (fbi->screen_dma -
+ sizeof(struct pxafb_dma_descriptor));
+ fbi->dma2->fsadr = fbi->screen_dma + yoff;
+ fbi->dma2->fidr = 0;
+ fbi->dma2->ldcmd = ylen;
+
+ /* Cb vector */
+ fbi->dma3->fdadr = (fbi->dma2->fdadr -
+ sizeof(struct pxafb_dma_descriptor));
+ fbi->dma3->fsadr = fbi->screen_dma + cboff;
+ fbi->dma3->fidr = 0;
+ fbi->dma3->ldcmd = cblen;
+
+ /* Cr vector */
+
+ fbi->dma4->fdadr = (fbi->dma3->fdadr -
+ sizeof(struct pxafb_dma_descriptor));
+ fbi->dma4->fsadr = fbi->screen_dma + croff;
+ fbi->dma4->fidr = 0;
+ fbi->dma4->ldcmd = crlen;
+
+ /* Adjust for user */
+ fbi->fb.var.red.length = ylen;
+ fbi->fb.var.red.offset = yoff;
+ fbi->fb.var.green.length = cblen;
+ fbi->fb.var.green.offset = cboff;
+ fbi->fb.var.blue.length = crlen;
+ fbi->fb.var.blue.offset = croff;
+
+ return 0;
+};
+
+static int overlay2fb_map_RGB_memory(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ struct fb_var_screeninfo *var = &fbi->fb.var;
+ int pixels_per_line = 0 , nbytes = 0;
+
+ if (fbi->map_cpu)
+ dma_free_writecombine(o2_to_basefb(fbi)->dev, fbi->map_size,
+ fbi->map_cpu, fbi->map_dma);
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ /* 2 pixels per line */
+ pixels_per_line = (fbi->fb.var.xres + 0x1) & (~0x1);
+ nbytes = 2;
+
+ var->red = def_rgbt_16.red;
+ var->green = def_rgbt_16.green;
+ var->blue = def_rgbt_16.blue;
+ var->transp = def_rgbt_16.transp;
+ break;
+
+ case 18:
+ /* 8 pixels per line */
+ pixels_per_line = (fbi->fb.var.xres + 0x7) & (~0x7);
+ nbytes = 3;
+
+ var->red = def_rgb_18.red;
+ var->green = def_rgb_18.green;
+ var->blue = def_rgb_18.blue;
+ var->transp = def_rgb_18.transp;
+
+ break;
+ case 19:
+ /* 8 pixels per line */
+ pixels_per_line = (fbi->fb.var.xres + 0x7) & (~0x7);
+ nbytes = 3;
+
+ var->red = def_rgbt_19.red;
+ var->green = def_rgbt_19.green;
+ var->blue = def_rgbt_19.blue;
+ var->transp = def_rgbt_19.transp;
+
+ break;
+ case 24:
+ pixels_per_line = fbi->fb.var.xres;
+ nbytes = 4;
+
+ var->red = def_rgbt_24.red;
+ var->green = def_rgbt_24.green;
+ var->blue = def_rgbt_24.blue;
+ var->transp = def_rgbt_24.transp;
+
+ break;
+
+ case 25:
+ pixels_per_line = fbi->fb.var.xres;
+ nbytes = 4;
+
+ var->red = def_rgbt_25.red;
+ var->green = def_rgbt_25.green;
+ var->blue = def_rgbt_25.blue;
+ var->transp = def_rgbt_25.transp;
+
+ break;
+ }
+
+ fbi->fb.fix.line_length = nbytes * pixels_per_line ;
+ fbi->fb.fix.smem_len = fbi->fb.fix.line_length * fbi->fb.var.yres ;
+
+ fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
+ fbi->map_cpu = dma_alloc_writecombine(o2_to_basefb(fbi)->dev,
+ fbi->map_size, &fbi->map_dma,
+ GFP_KERNEL);
+ if (!fbi->map_cpu)
+ return -ENOMEM;
+
+ /* Prevent initial garbage on screen */
+ memset(fbi->map_cpu, 0, fbi->map_size);
+ fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
+ fbi->fb.fix.smem_start = fbi->screen_dma;
+
+ /* Setup dma descriptor */
+ fbi->dma2 = (struct pxafb_dma_descriptor *)
+ (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
+
+ fbi->dma2->fdadr = (fbi->screen_dma -
+ sizeof(struct pxafb_dma_descriptor));
+ fbi->dma2->fsadr = fbi->screen_dma;
+ fbi->dma2->fidr = 0;
+ fbi->dma2->ldcmd = fbi->fb.fix.smem_len;
+
+ return 0;
+}
+
+static int overlay2fb_enable(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned long bpp2;
+ unsigned int xres, yres;
+ unsigned int lccr5;
+
+ if (!fbi->map_cpu)
+ return -EINVAL;
+
+ switch (fbi->fb.var.bits_per_pixel) {
+ case 16:
+ bpp2 = 0x4;
+ break;
+ case 18:
+ bpp2 = 0x6;
+ break;
+ case 19:
+ bpp2 = 0x8;
+ break;
+ case 24:
+ bpp2 = 0x9;
+ break;
+ case 25:
+ bpp2 = 0xa;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Disable branch/start/end of frame interrupt */
+ lccr5 = lcd_readl(o2_to_basefb(fbi), LCCR5);
+ lcd_writel(o2_to_basefb(fbi), LCCR5, lccr5
+ | LCCR5_IUM(4) | LCCR5_IUM(3) | LCCR5_IUM(2)
+ | LCCR5_BSM(4) | LCCR5_BSM(3) | LCCR5_BSM(2)
+ | LCCR5_EOFM(4) | LCCR5_EOFM(3) | LCCR5_EOFM(2)
+ | LCCR5_SOFM(4) | LCCR5_SOFM(3) | LCCR5_SOFM(2));
+
+ if (fbi->format == 0) {
+ /* Overlay2 RGB resolution, RGB and YUV have different
+ * xres value
+ */
+ xres = fbi->fb.var.xres;
+ yres = fbi->fb.var.yres;
+
+ lcd_writel(o2_to_basefb(fbi), OVL2C2,
+ (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos);
+ lcd_writel(o2_to_basefb(fbi), OVL2C1,
+ OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1));
+
+ /* Setup RGB DMA */
+ if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
+ lcd_writel(o2_to_basefb(fbi), FDADR2,
+ fbi->dma2->fdadr);
+ else
+ lcd_writel(o2_to_basefb(fbi), DFBR2,
+ fbi->dma2->fdadr | 0x1);
+ } else {
+ /* Overlay2 YUV resolution */
+ xres = fbi->fb.fix.line_length;
+ yres = fbi->fb.var.yres;
+
+ lcd_writel(o2_to_basefb(fbi), OVL2C2,
+ (fbi->format << 20) | (fbi->ypos << 10) | fbi->xpos);
+ lcd_writel(o2_to_basefb(fbi), OVL2C1,
+ OVL2C1_O2EN | (bpp2 << 20) | ((yres-1)<<10) | (xres-1));
+
+ if (fbi->state == C_DISABLE || fbi->state == C_BLANK) {
+ lcd_writel(o2_to_basefb(fbi), FDADR2,
+ fbi->dma2->fdadr);
+ lcd_writel(o2_to_basefb(fbi), FDADR3,
+ fbi->dma3->fdadr);
+ lcd_writel(o2_to_basefb(fbi), FDADR4,
+ fbi->dma4->fdadr);
+ } else {
+ lcd_writel(o2_to_basefb(fbi), DFBR2,
+ fbi->dma2->fdadr | 0x01);
+ lcd_writel(o2_to_basefb(fbi), DFBR3,
+ fbi->dma3->fdadr | 0x01);
+ lcd_writel(o2_to_basefb(fbi), DFBR4,
+ fbi->dma4->fdadr | 0x01);
+ }
+ }
+
+ fbi->state = C_ENABLE;
+ return 0;
+}
+
+static int overlay2fb_disable(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned int ovl2c1;
+ int done;
+
+ if (fbi->state == C_DISABLE)
+ return 0;
+ if (fbi->state == C_BLANK) {
+ fbi->state = C_DISABLE;
+ return 0;
+ }
+
+ fbi->state = C_DISABLE;
+
+ /* Clear O2EN */
+ ovl2c1 = lcd_readl(o2_to_basefb(fbi), OVL2C1);
+ lcd_writel(o2_to_basefb(fbi), OVL2C1, ovl2c1 & ~OVL2C1_O2EN);
+
+ /* Make overlay2 can't disable/enable correctly sometimes */
+ lcd_writel(o2_to_basefb(fbi), LCSR1, LCSR1_BS(2));
+
+ if (fbi->format == 0)
+ lcd_writel(o2_to_basefb(fbi), DFBR2, 0x3);
+ else {
+ lcd_writel(o2_to_basefb(fbi), DFBR2, 0x3);
+ lcd_writel(o2_to_basefb(fbi), DFBR3, 0x3);
+ lcd_writel(o2_to_basefb(fbi), DFBR4, 0x3);
+ }
+
+ done = WAIT_FOR_LCD_INTR(o2_to_basefb(fbi), LCSR1, LCSR1_BS(2), 100);
+ if (!done) {
+ dev_info(o2_to_basefb(fbi)->dev, "%s: timeout\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+static int overlay2fb_blank(int blank, struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ int err = 0;
+
+ switch (blank) {
+ case 0:
+ err = overlay2fb_enable(info);
+ if (err) {
+ fbi->state = C_DISABLE;
+ set_ctrlr_state(o2_to_basefb(fbi), C_REENABLE);
+ }
+ break;
+ case 1:
+ err = overlay2fb_disable(info);
+ if (err) {
+ fbi->state = C_DISABLE;
+ set_ctrlr_state(o2_to_basefb(fbi), C_REENABLE);
+ }
+ break;
+ }
+
+ return err;
+}
+
+
+static int overlay2fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int xpos, ypos, xres, yres;
+ int format;
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+
+ xres = yres = 0;
+
+ xpos = (var->nonstd & 0x3ff);
+ ypos = (var->nonstd >> 10) & 0x3ff;
+ format = (var->nonstd >> 20) & 0x7;
+
+
+ /* Palnar YCbCr444, YCbCr422, YCbCr420 */
+ if ((format != 0x4) && (format != 0x3) &&
+ (format != 0x2) && (format != 0x0))
+ return -EINVAL;
+
+ /* Dummy pixels */
+ switch (format) {
+ case 0x0: /* RGB */
+ xres = var->xres;
+ break;
+ case 0x2: /* 444 */
+ xres = (var->xres + 0x3) & ~(0x3);
+ break;
+ case 0x3: /* 422 */
+ xres = (var->xres + 0x7) & ~(0x7);
+ break;
+ case 0x4: /* 420 */
+ xres = (var->xres + 0xf) & ~(0xf);
+ break;
+ }
+ yres = var->yres;
+
+ if ((xpos + xres) > o2_to_basefb(fbi)->fb.var.xres)
+ return -EINVAL;
+
+ if ((ypos + yres) > o2_to_basefb(fbi)->fb.var.yres)
+ return -EINVAL;
+
+ fbi->old_var = *var;
+
+ var->activate = FB_ACTIVATE_NOW;
+
+ return 0;
+
+}
+
+
+/*
+ * overlay2fb_set_var()
+ *
+ * var.nonstd is used as YCbCr format.
+ * var.red/green/blue is used as (Y/Cb/Cr) vector
+ */
+
+static int overlay2fb_set_par(struct fb_info *info)
+{
+ unsigned int xpos, ypos;
+ int format, err;
+
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ struct fb_var_screeninfo *var = &fbi->fb.var;
+
+ info->flags &= ~FBINFO_MISC_USEREVENT;
+
+ if (fbi->state == C_BLANK)
+ return 0;
+
+ if (fbi->state == C_DISABLE)
+ goto out1;
+
+ if ((var->xres == fbi->old_var.xres) &&
+ (var->yres == fbi->old_var.yres) &&
+ (var->bits_per_pixel == fbi->old_var.bits_per_pixel) &&
+ (((var->nonstd>>20) & 0x7) == fbi->format))
+ goto out2;
+
+out1:
+ xpos = var->nonstd & 0x3ff;
+ ypos = (var->nonstd>>10) & 0x3ff;
+ format = (var->nonstd>>20) & 0x7;
+
+
+ fbi->format = format;
+ if (fbi->format == 0)
+ err = overlay2fb_map_RGB_memory(info);
+ else
+ err = overlay2fb_map_YUV_memory(info);
+
+ if (err)
+ return err;
+
+out2:
+ /* Position */
+ fbi->xpos = var->nonstd & 0x3ff;
+ fbi->ypos = (var->nonstd>>10) & 0x3ff;
+
+ overlay2fb_enable(info);
+
+ return 0;
+}
+
+static int overlay2fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (off < info->fix.smem_len) {
+ vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
+ return dma_mmap_writecombine(o2_to_basefb(fbi)->dev, vma,
+ fbi->map_cpu, fbi->map_dma,
+ fbi->map_size);
+ }
+ return -EINVAL;
+}
+
+static struct fb_ops overlay2fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = overlay2fb_open,
+ .fb_release = overlay2fb_release,
+ .fb_check_var = overlay2fb_check_var,
+ .fb_set_par = overlay2fb_set_par,
+ .fb_blank = overlay2fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = overlay2fb_mmap,
+};
+
+/* Hardware cursor */
+
+/* Bulverde Cursor Modes */
+struct cursorfb_mode {
+ int xres;
+ int yres;
+ int bpp;
+};
+
+static struct cursorfb_mode cursorfb_modes[] = {
+ { 32, 32, 2},
+ { 32, 32, 2},
+ { 32, 32, 2},
+ { 64, 64, 2},
+ { 64, 64, 2},
+ { 64, 64, 2},
+ {128, 128, 1},
+ {128, 128, 1}
+};
+
+static int cursorfb_enable(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned int ccr, lccr4, lccr5;
+
+ if (!fbi->map_cpu)
+ return -EINVAL;
+
+ ccr = lcd_readl(cu_to_basefb(fbi), CCR);
+ lcd_writel(cu_to_basefb(fbi), CCR, ccr & ~CCR_CEN);
+
+ /* Set palette format
+ *
+ * FIXME: if only cursor uses palette
+ */
+ lccr4 = lcd_readl(cu_to_basefb(fbi), LCCR4);
+ lcd_writel(cu_to_basefb(fbi), LCCR4,
+ (lccr4 & (~(0x3 << 15))) | (0x1 << 15));
+
+ /* Disable branch/start/end of frame interrupt */
+ lccr5 = lcd_readl(cu_to_basefb(fbi), LCCR5);
+ lcd_writel(cu_to_basefb(fbi), LCCR5,
+ lccr5 | LCCR5_IUM(5) | LCCR5_BSM(5)
+ | LCCR5_EOFM(5) | LCCR5_SOFM(5));
+
+ /* Load palette and frame data */
+ if (fbi->state == C_DISABLE) {
+ lcd_writel(cu_to_basefb(fbi), FDADR5,
+ fbi->dma5_pal->fdadr);
+ udelay(1);
+ lcd_writel(cu_to_basefb(fbi), FDADR5,
+ fbi->dma5_frame->fdadr);
+ udelay(1);
+
+ } else {
+ lcd_writel(cu_to_basefb(fbi), DFBR5,
+ fbi->dma5_pal->fdadr | 0x1);
+ udelay(1);
+ lcd_writel(cu_to_basefb(fbi), DFBR5,
+ fbi->dma5_frame->fdadr | 0x1);
+ udelay(1);
+ }
+
+ lcd_writel(cu_to_basefb(fbi), CCR,
+ CCR_CEN | (fbi->ypos << 15) | (fbi->xpos << 5) | (fbi->format));
+
+ fbi->state = C_ENABLE;
+
+ return 0;
+}
+
+static int cursorfb_disable(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ unsigned int ccr;
+ int done, ret = 0;
+
+ fbi->state = C_DISABLE;
+
+ done = WAIT_FOR_LCD_INTR(cu_to_basefb(fbi), LCSR1, LCSR1_BS(5), 100);
+ if (!done)
+ ret = -1;
+
+ ccr = lcd_readl(cu_to_basefb(fbi), CCR);
+ lcd_writel(cu_to_basefb(fbi), CCR, ccr & ~CCR_CEN);
+
+ return ret;
+}
+
+static int cursorfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ u_int val, ret = 1;
+ u_int *pal = fbi->palette_cpu;
+
+ /* 25bit with Transparcy for 16bpp format */
+ if (regno < fbi->palette_size) {
+ val = ((trans << 24) & 0x1000000);
+ val |= ((red << 16) & 0x0ff0000);
+ val |= ((green << 8) & 0x000ff00);
+ val |= ((blue << 0) & 0x00000ff);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int cursorfb_blank(int blank, struct fb_info *info)
+{
+ switch (blank) {
+ case 0:
+ cursorfb_enable(info);
+ break;
+ case 1:
+ cursorfb_disable(info);
+ break;
+ }
+
+ return 0;
+}
+
+static int cursorfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ int xpos, ypos, xres, yres;
+ int mode;
+ struct cursorfb_mode *cursor;
+
+ mode = var->nonstd & 0x7;
+ xpos = (var->nonstd>>5) & 0x3ff;
+ ypos = (var->nonstd>>15) & 0x3ff;
+
+ if (mode > 7 || mode < 0)
+ return -EINVAL;
+
+ cursor = cursorfb_modes + mode;
+
+ xres = cursor->xres;
+ yres = cursor->yres;
+
+ if ((xpos + xres) > cu_to_basefb(fbi)->fb.var.xres)
+ return -EINVAL;
+
+ if ((ypos + yres) > cu_to_basefb(fbi)->fb.var.yres)
+ return -EINVAL;
+
+ return 0;
+
+}
+
+static int cursorfb_set_par(struct fb_info *info)
+{
+ struct overlayfb_info *fbi = (struct overlayfb_info *) info;
+ struct fb_var_screeninfo *var = &fbi->fb.var;
+ struct cursorfb_mode *cursor;
+ int mode, xpos, ypos;
+ int err;
+
+ info->flags &= ~FBINFO_MISC_USEREVENT;
+
+ mode = var->nonstd & 0x7;
+ xpos = (var->nonstd>>5) & 0x3ff;
+ ypos = (var->nonstd>>15) & 0x3ff;
+
+ if (mode != fbi->format) {
+ cursor = cursorfb_modes + mode;
+
+ /* Update "var" info */
+ fbi->fb.var.xres = cursor->xres;
+ fbi->fb.var.yres = cursor->yres;
+ fbi->fb.var.bits_per_pixel = cursor->bpp;
+
+ /* Alloc video memory
+ *
+ * 4k is engouh for 128x128x1 cursor,
+ * - 2k for cursor pixels,
+ * - 2k for palette data, plus 2 dma descriptor
+ */
+ if (!fbi->map_cpu) {
+ fbi->map_size = PAGE_SIZE;
+ fbi->map_cpu = dma_alloc_writecombine(NULL,
+ fbi->map_size, &fbi->map_dma,
+ GFP_KERNEL);
+ if (!fbi->map_cpu)
+ return -ENOMEM;
+ }
+
+ cursor = cursorfb_modes + mode;
+
+ /* Update overlay & fix "info" */
+ fbi->screen_cpu = fbi->map_cpu;
+ fbi->palette_cpu = (u_int *)
+ fbi->map_cpu + (PAGE_SIZE/2);
+ fbi->screen_dma = fbi->map_dma;
+ fbi->palette_dma = fbi->map_dma + (PAGE_SIZE/2);
+
+ fbi->format = mode;
+ fbi->palette_size = 1 << cursor->bpp;
+ fbi->fb.fix.smem_start = fbi->screen_dma;
+ fbi->fb.fix.smem_len = cursor->xres * cursor->yres *
+ cursor->bpp / 8;
+ fbi->fb.fix.line_length = cursor->xres * cursor->bpp / 8 ;
+
+ fbi->dma5_pal = (struct pxafb_dma_descriptor *)
+ (fbi->map_cpu + PAGE_SIZE - 16);
+ fbi->dma5_pal->fdadr = fbi->map_dma + PAGE_SIZE - 16;
+ fbi->dma5_pal->fsadr = fbi->palette_dma;
+ fbi->dma5_pal->fidr = 0;
+ fbi->dma5_pal->ldcmd = (fbi->palette_size << 2) | LDCMD_PAL;
+
+ fbi->dma5_frame = (struct pxafb_dma_descriptor *)
+ (fbi->map_cpu + PAGE_SIZE - 32);
+ fbi->dma5_frame->fdadr = fbi->map_dma + PAGE_SIZE - 32;
+ fbi->dma5_frame->fsadr = fbi->screen_dma;
+ fbi->dma5_frame->fidr = 0;
+ fbi->dma5_frame->ldcmd = fbi->fb.fix.smem_len;
+
+ /* Alloc & set default cmap */
+ err = fb_alloc_cmap(&fbi->fb.cmap, fbi->palette_size, 0);
+ if (err)
+ return err;
+ err = fb_set_cmap(&fbi->fb.cmap, info);
+ if (err)
+ return err;
+ }
+
+ /* Update overlay info */
+ if ((xpos != fbi->xpos) || (ypos != fbi->ypos)) {
+ fbi->xpos = xpos;
+ fbi->ypos = ypos;
+ }
+
+ cursorfb_enable(info);
+ set_ctrlr_state(cu_to_basefb(fbi), C_REENABLE);
+
+ return 0;
+}
+
+static struct fb_ops cursorfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = cursorfb_check_var,
+ .fb_set_par = cursorfb_set_par,
+ .fb_blank = cursorfb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_setcolreg = cursorfb_setcolreg,
+};
+
+static void __init overlay1fb_init_fbinfo(struct overlayfb_info *fbi)
+{
+ memset(fbi, 0, sizeof(struct overlayfb_info));
+
+ atomic_set(&fbi->refcount, 1);
+ strcpy(fbi->fb.fix.id, "overlay1");
+
+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fb.fix.type_aux = 0;
+ fbi->fb.fix.xpanstep = 0;
+ fbi->fb.fix.ypanstep = 0;
+ fbi->fb.fix.ywrapstep = 0;
+ fbi->fb.fix.accel = FB_ACCEL_NONE;
+
+ fbi->fb.var.nonstd = 0;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+ fbi->fb.var.height = -1;
+ fbi->fb.var.width = -1;
+ fbi->fb.var.accel_flags = 0;
+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+ fbi->fb.fbops = &overlay1fb_ops;
+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
+ fbi->fb.node = -1;
+ fbi->fb.pseudo_palette = NULL;
+
+ fbi->xpos = 0;
+ fbi->ypos = 0;
+ fbi->format = -1;
+ fbi->state = C_DISABLE;
+}
+
+static void __init overlay2fb_init_fbinfo(struct overlayfb_info *fbi)
+{
+ memset(fbi, 0, sizeof(struct overlayfb_info));
+
+ atomic_set(&fbi->refcount, 1);
+ strcpy(fbi->fb.fix.id, "overlay2");
+
+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fb.fix.type_aux = 0;
+ fbi->fb.fix.xpanstep = 0;
+ fbi->fb.fix.ypanstep = 0;
+ fbi->fb.fix.ywrapstep = 0;
+ fbi->fb.fix.accel = FB_ACCEL_NONE;
+
+ fbi->fb.var.nonstd = 0;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+ fbi->fb.var.height = -1;
+ fbi->fb.var.width = -1;
+ fbi->fb.var.accel_flags = 0;
+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+ fbi->fb.fbops = &overlay2fb_ops;
+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
+ fbi->fb.node = -1;
+ fbi->fb.pseudo_palette = NULL;
+
+ fbi->xpos = 0;
+ fbi->ypos = 0;
+ fbi->format = -1;
+ fbi->state = C_DISABLE;
+}
+
+static void __init cursorfb_init_fbinfo(struct overlayfb_info *fbi)
+{
+ memset(fbi, 0, sizeof(struct overlayfb_info));
+
+ atomic_set(&fbi->refcount, 1);
+ strcpy(fbi->fb.fix.id, "cursor");
+
+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fb.fix.type_aux = 0;
+ fbi->fb.fix.xpanstep = 0;
+ fbi->fb.fix.ypanstep = 0;
+ fbi->fb.fix.ywrapstep = 0;
+ fbi->fb.fix.accel = FB_ACCEL_NONE;
+
+ fbi->fb.var.nonstd = 0;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+ fbi->fb.var.height = -1;
+ fbi->fb.var.width = -1;
+ fbi->fb.var.accel_flags = 0;
+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+ fbi->fb.fbops = &cursorfb_ops;
+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
+ fbi->fb.node = -1;
+ fbi->fb.pseudo_palette = NULL;
+
+ fbi->xpos = 0;
+ fbi->ypos = 0;
+ fbi->format = -1;
+ fbi->state = C_DISABLE;
+}
+
+
+void pxa_set_overlay_ctrlr_state(struct pxafb_info *fbi, u_int state)
+{
+ switch (state) {
+ case C_DISABLE:
+ DISABLE_OVERLAYS(fbi);
+ break;
+ case C_ENABLE:
+ ENABLE_OVERLAYS(fbi);
+ break;
+ case C_BLANK:
+ BLANK_OVERLAYS(fbi);
+ break;
+ case C_UNBLANK:
+ UNBLANK_OVERLAYS(fbi);
+ break;
+ }
+}
+
+void __init pxafb_overlay_probe(struct device *dev)
+{
+ struct pxafb_info *fbi;
+ int ret;
+
+ dev_dbg(dev, "pxafb_overlay_probe\n");
+
+ fbi = dev_get_drvdata(dev);
+ if (!fbi) {
+ dev_err(dev, "base framebuffer not initialized, "
+ "failed to load overlay driver!\n");
+ return;
+ }
+
+ /* Overlay 1 windows */
+ overlay1fb_init_fbinfo(&fbi->overlay1fb);
+ ret = register_framebuffer(&fbi->overlay1fb.fb);
+ if (ret < 0) {
+ dev_err(dev, "unable to register overlay 1 windows\n");
+ goto error_o1;
+ }
+
+ /* Overlay 2 window */
+ overlay2fb_init_fbinfo(&fbi->overlay2fb);
+ ret = register_framebuffer(&fbi->overlay2fb.fb);
+ if (ret < 0) {
+ dev_err(dev, "unable to register overlay 2 windows\n");
+ goto error_o2;
+ }
+
+ /* Hardware cursor window */
+ cursorfb_init_fbinfo(&fbi->cursorfb);
+ ret = register_framebuffer(&fbi->cursorfb.fb);
+ if (ret < 0) {
+ dev_err(dev, "unable to register hardware cursor windows\n");
+ goto error_cu;
+ }
+
+ fbi->set_overlay_ctrlr_state = pxa_set_overlay_ctrlr_state;
+
+ dev_info(dev, "PXA overlay driver enabled\n");
+
+ return;
+
+error_cu:
+ unregister_framebuffer(&fbi->overlay2fb.fb);
+error_o2:
+ unregister_framebuffer(&fbi->overlay1fb.fb);
+error_o1:
+ dev_info(dev, "PXA overlay driver failed\n");
+
+ return;
+}
+EXPORT_SYMBOL(pxafb_overlay_probe);
--
1.5.4.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] PXA: add configurable consistent memory DMA size.
2008-09-10 8:07 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Rodolfo Giometti
@ 2008-09-10 8:07 ` Rodolfo Giometti
2008-09-13 10:05 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Andrew Morton
1 sibling, 0 replies; 5+ messages in thread
From: Rodolfo Giometti @ 2008-09-10 8:07 UTC (permalink / raw)
To: linux-arm; +Cc: Eric Miao, Russell King, linux-kernel, Rodolfo Giometti
From: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
arch/arm/mach-pxa/include/mach/memory.h | 13 +++++++++++++
drivers/video/Kconfig | 11 +++++++++++
2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-pxa/include/mach/memory.h b/arch/arm/mach-pxa/include/mach/memory.h
index 552eb7f..247c2ef 100644
--- a/arch/arm/mach-pxa/include/mach/memory.h
+++ b/arch/arm/mach-pxa/include/mach/memory.h
@@ -49,4 +49,17 @@ void cmx270_pci_adjust_zones(int node, unsigned long *size,
#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_64M - 1)
#endif
+/* Override the ARM default */
+#ifdef CONFIG_FB_PXA_CONSISTENT_DMA_SIZE
+
+#if (CONFIG_FB_PXA_CONSISTENT_DMA_SIZE == 0)
+#undef CONFIG_FB_PXA_CONSISTENT_DMA_SIZE
+#define CONFIG_FB_PXA_CONSISTENT_DMA_SIZE 2
+#endif
+
+#define CONSISTENT_DMA_SIZE \
+ (((CONFIG_FB_PXA_CONSISTENT_DMA_SIZE + 1) & ~1) * 1024 * 1024)
+
+#endif
+
#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5d5c8c8..6720d78 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1808,6 +1808,17 @@ config FB_PXA_OVERLAY
---help---
Frame buffer overlay driver for PXA27x
+config FB_PXA_CONSISTENT_DMA_SIZE
+ int "Consistent DMA memory size (MB)"
+ depends on FB_PXA
+ range 1 14
+ default 2
+ help
+ Increase the DMA consistent memory size according to your video
+ memory needs, for example if you want to use overlay support.
+ The size must be 2MB aligned.
+ If unsure say 2.
+
config FB_PXA_PARAMETERS
bool "PXA LCD command line parameters"
default n
--
1.5.4.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x.
2008-09-10 8:07 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Rodolfo Giometti
2008-09-10 8:07 ` [PATCH 2/2] PXA: add configurable consistent memory DMA size Rodolfo Giometti
@ 2008-09-13 10:05 ` Andrew Morton
2008-09-13 10:20 ` Russell King - ARM Linux
1 sibling, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2008-09-13 10:05 UTC (permalink / raw)
To: Rodolfo Giometti
Cc: linux-arm, Eric Miao, Russell King, linux-kernel,
Rodolfo Giometti, linux-fbdev-devel
Please cc linux-fbdev-devel@lists.sourceforge.net on fbdev patches.
On Wed, 10 Sep 2008 10:07:35 +0200 Rodolfo Giometti <giometti@enneenne.com> wrote:
> From: Rodolfo Giometti <giometti@linux.it>
>
> Signed-off-by: Rodolfo Giometti <giometti@linux.it>
>
> arch/arm/mach-pxa/include/mach/regs-lcd.h | 39 +
> drivers/video/Kconfig | 6 +
> drivers/video/Makefile | 1 +
> drivers/video/pxafb.c | 75 ++-
> drivers/video/pxafb.h | 74 ++
> drivers/video/pxafb_overlay.c | 1476 +++++++++++++++++++++++++++++
> 6 files changed, 1654 insertions(+), 17 deletions(-)
> create mode 100644 drivers/video/pxafb_overlay.c
Over a thousand lines of code and zero changelog? No indication what
the driver does, what hardware is it for, nothing needs to be
communicated about the implementation, no todo items, no shortcomings?
Really?
The code looks generally OK to my untrained eye. A few things:
>
> ...
>
> +#ifdef CONFIG_FB_PXA_OVERLAY
> +struct overlayfb_info
> +{
Please run scripts/checkpatch.pl across all patches, no exceptions, and
review the result.
>
> ...
>
> +#define o1_to_basefb(d) container_of(d, struct pxafb_info, overlay1fb)
> +#define o2_to_basefb(d) container_of(d, struct pxafb_info, overlay2fb)
> +#define cu_to_basefb(d) container_of(d, struct pxafb_info, cursorfb)
Please convert to typesafe C functions. And use them.
>
> ...
>
> +#define CLEAR_LCD_INTR(reg, intr) do { \
> + reg = (intr); \
> +} while (0)
This fortunately has no callers.
> +#define WAIT_FOR_LCD_INTR(bfi, reg, intr, timeout) ({ \
> + int __done = 0; \
> + int __t = timeout; \
> + while (__t) { \
> + __done = lcd_readl(bfi, reg) & (intr); \
> + if (__done) \
> + break; \
> + mdelay(10); \
> + __t--; \
> + } \
> + if (!__t) \
> + dev_info(bfi->dev, "wait " #intr " timeount"); \
> + __done; \
> +})
afacit this can be implemented as a C function. That would be vastly
preferable.
> +#define DISABLE_OVERLAYS(fbi) do { \
> + if (fbi->overlay1fb.state == C_ENABLE) \
> + overlay1fb_disable((struct fb_info *) &fbi->overlay1fb);\
> + if (fbi->overlay2fb.state == C_ENABLE) \
> + overlay2fb_disable((struct fb_info *) &fbi->overlay2fb);\
> + if (fbi->cursorfb.state == C_ENABLE) \
> + cursorfb_disable((struct fb_info *) &fbi->cursorfb); \
> +} while (0)
> +
> +#define ENABLE_OVERLAYS(fbi) do { \
> + if (fbi->overlay1fb.state == C_DISABLE) \
> + overlay1fb_enable((struct fb_info *) &fbi->overlay1fb); \
> + if (fbi->overlay2fb.state == C_DISABLE) \
> + overlay2fb_enable((struct fb_info *) &fbi->overlay2fb); \
> + if (fbi->cursorfb.state == C_DISABLE) \
> + cursorfb_enable((struct fb_info *) &fbi->cursorfb); \
> +} while (0)
> +
> +#define BLANK_OVERLAYS(fbi) do { \
> + if (fbi->overlay1fb.state == C_ENABLE) { \
> + overlay1fb_disable((struct fb_info *) &fbi->overlay1fb);\
> + fbi->overlay1fb.state = C_BLANK; \
> + } \
> + if (fbi->overlay2fb.state == C_ENABLE) { \
> + overlay2fb_disable((struct fb_info *) &fbi->overlay2fb);\
> + fbi->overlay2fb.state = C_BLANK; \
> + } \
> + if (fbi->cursorfb.state == C_ENABLE) { \
> + cursorfb_disable((struct fb_info *) &fbi->cursorfb); \
> + fbi->cursorfb.state = C_BLANK; \
> + } \
> +} while (0)
> +
> +#define UNBLANK_OVERLAYS(fbi) do { \
> + if (fbi->overlay1fb.state == C_BLANK) { \
> + overlay1fb_enable((struct fb_info *) &fbi->overlay1fb); \
> + fbi->overlay1fb.state = C_ENABLE; \
> + } \
> + if (fbi->overlay2fb.state == C_BLANK) { \
> + overlay2fb_enable((struct fb_info *) &fbi->overlay2fb); \
> + fbi->overlay2fb.state = C_ENABLE; \
> + } \
> + if (fbi->cursorfb.state == C_BLANK) { \
> + cursorfb_enable((struct fb_info *) &fbi->cursorfb); \
> + fbi->cursorfb.state = C_ENABLE; \
> + } \
> +} while (0)
Please switch to C functions.
Please remove all the casts and use container_of(), or helper functions
which use container_of().
> +static int overlay1fb_open(struct fb_info *info, int user)
> +{
> + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
Remove all instances of the above cast and use container_of(), or the
typesafe C-coded helper function which uses container_of().
> + int ret = 0;
> +
> + if (!atomic_dec_and_test(&fbi->refcount)) {
> + atomic_inc(&fbi->refcount);
> + return -EACCES;
> + }
> +
> + /* If basefb is disable, enable fb */
> + if (o1_to_basefb(fbi)->state != C_ENABLE)
> + o1_to_basefb(fbi)->fb.fbops->fb_blank(VESA_NO_BLANKING,
> + (struct fb_info *) o1_to_basefb(fbi));
container_of().
> + /* Initialize the variables in overlay1 framebuffer */
> + fbi->fb.var.xres = fbi->fb.var.yres = 0;
> + fbi->fb.var.bits_per_pixel = 0;
> +
> + return ret;
> +}
> +
>
> ...
>
> +static int overlay1fb_map_video_memory(struct fb_info *info)
> +{
> + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
> +
> + if (fbi->map_cpu)
> + dma_free_writecombine(o1_to_basefb(fbi)->dev, fbi->map_size,
> + (void *) fbi->map_cpu, fbi->map_dma);
> + fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_descriptor));
> + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
> + fbi->map_cpu = dma_alloc_writecombine(o1_to_basefb(fbi)->dev,
> + fbi->map_size, &fbi->map_dma,
> + GFP_KERNEL);
> + if (!fbi->map_cpu)
> + return -ENOMEM;
> +
> + /* Prevent initial garbage on screen */
> + memset(fbi->map_cpu, 0, fbi->map_size);
> + fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
> + fbi->screen_cpu = fbi->map_cpu + fbi->video_offset;
> + fbi->screen_dma = fbi->map_dma + fbi->video_offset;
> +
> + fbi->fb.fix.smem_start = fbi->screen_dma;
> +
> + /* Setup dma descriptor */
> + fbi->dma1 = (struct pxafb_dma_descriptor *)
> + (fbi->screen_cpu - sizeof(struct pxafb_dma_descriptor));
> +
> + fbi->dma1->fdadr = (fbi->screen_dma -
> + sizeof(struct pxafb_dma_descriptor));
> + fbi->dma1->fsadr = fbi->screen_dma;
> + fbi->dma1->fidr = 0;
> + fbi->dma1->ldcmd = fbi->fb.fix.smem_len;
> +
> + return 0;
> +}
The above code is implicitly implementing some memory layout which I
assume is defined by the hardware.
Where would someone go to find out about that layout? Some
documentation reference or a description in a comment would add
maintainability and understandability.
> +static int overlay1fb_enable(struct fb_info *info)
> +{
> + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
> +
> + unsigned long bpp1;
> + unsigned int lccr5;
Avoid random newline between local definitions, please.
> + if (!fbi->map_cpu)
> + return -EINVAL;
> +
> + switch (fbi->fb.var.bits_per_pixel) {
> + case 16:
> + bpp1 = 0x4;
> + break;
> + case 18:
> + bpp1 = 0x6;
> + break;
> + case 19:
> + bpp1 = 0x8;
> + break;
> + case 24:
> + bpp1 = 0x9;
> + break;
> + case 25:
> + bpp1 = 0xa;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + /* Disable branch/start/end of frame interrupt */
> + lccr5 = lcd_readl(o1_to_basefb(fbi), LCCR5);
> + lcd_writel(o1_to_basefb(fbi), LCCR5,
> + lccr5 | LCCR5_IUM(1) | LCCR5_BSM(1)
> + | LCCR5_EOFM(1) | LCCR5_SOFM(1));
> +
> + if (fbi->state == C_DISABLE || fbi->state == C_BLANK)
> + lcd_writel(o1_to_basefb(fbi), FDADR1, fbi->dma1->fdadr);
> + else
> + lcd_writel(o1_to_basefb(fbi), DFBR1, fbi->dma1->fdadr | 0x1);
> +
> + /* Enable overlay 1 window */
> + lcd_writel(o1_to_basefb(fbi), OVL1C2,
> + (fbi->ypos << 10) | fbi->xpos);;
> + lcd_writel(o1_to_basefb(fbi), OVL1C1,
> + OVL1C1_O1EN | (bpp1 << 20) |
> + ((fbi->fb.var.yres-1)<<10) |
> + (fbi->fb.var.xres-1));
> +
> + fbi->state = C_ENABLE;
> +
> + return 0;
> +}
> +
>
> ...
>
> +static int overlay1fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
> +{
> + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
> + unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
>
> + if (off < info->fix.smem_len) {
> + vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
> + return dma_mmap_writecombine(o1_to_basefb(fbi)->dev, vma,
> + fbi->map_cpu, fbi->map_dma,
> + fbi->map_size);
> + }
> + return -EINVAL;
> +}
No need to set VM_IO or VM_RESERVED, etc?
>
> ...
>
> +/*
> + * LCD enhancement : Overlay 2
> + *
> + * Features:
> + * - support planar YCbCr420/YCbCr422/YCbCr444;
> + */
> +static int overlay2fb_open(struct fb_info *info, int user)
> +{
> + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
> +
> + if (!atomic_dec_and_test(&fbi->refcount)) {
> + atomic_inc(&fbi->refcount);
> + return -EACCES;
> + }
Now what's happening here.
- Please add a comment demystifying this. It looks fishy.
- It surely is racy
- It would be non-racy were it to use atomic_dec_not_zero(), but I
suspect we're just covering up bugs here.
> + /* If basefb is disable, enable fb */
> + if (o2_to_basefb(fbi)->state != C_ENABLE)
> + o2_to_basefb(fbi)->fb.fbops->fb_blank(VESA_NO_BLANKING,
> + (struct fb_info *) o2_to_basefb(fbi));
> +
> + fbi->fb.var.xres = fbi->fb.var.yres = 0;
> +
> + return 0;
> +}
> +
> +static int overlay2fb_release(struct fb_info *info, int user)
> +{
> + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
> +
> + /* Disable overlay when released */
> + overlay2fb_blank(1, info);
> +
> + atomic_inc(&fbi->refcount);
Strange to see a refcount _increase_ in a ->release handler!
> + return 0;
> +}
> +
>
> ...
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x.
2008-09-13 10:05 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Andrew Morton
@ 2008-09-13 10:20 ` Russell King - ARM Linux
0 siblings, 0 replies; 5+ messages in thread
From: Russell King - ARM Linux @ 2008-09-13 10:20 UTC (permalink / raw)
To: Andrew Morton
Cc: Rodolfo Giometti, Eric Miao, linux-kernel, Rodolfo Giometti,
linux-fbdev-devel
On Sat, Sep 13, 2008 at 03:05:40AM -0700, Andrew Morton wrote:
> > +static int overlay1fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
> > +{
> > + struct overlayfb_info *fbi = (struct overlayfb_info *) info;
> > + unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
> >
> > + if (off < info->fix.smem_len) {
> > + vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
> > + return dma_mmap_writecombine(o1_to_basefb(fbi)->dev, vma,
> > + fbi->map_cpu, fbi->map_dma,
> > + fbi->map_size);
> > + }
> > + return -EINVAL;
> > +}
>
> No need to set VM_IO or VM_RESERVED, etc?
That's covered by dma_mmap_writecombine -> remap_pfn_range:
vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-09-13 10:21 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-10 8:07 PXA fb overlay support (RESUBMIT 2) Rodolfo Giometti
2008-09-10 8:07 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Rodolfo Giometti
2008-09-10 8:07 ` [PATCH 2/2] PXA: add configurable consistent memory DMA size Rodolfo Giometti
2008-09-13 10:05 ` [PATCH 1/2] pxafb: frame buffer overlay support for PXA27x Andrew Morton
2008-09-13 10:20 ` Russell King - ARM Linux
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox