]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: A whopping FB driver update
authorImre Deak <imre.deak@nokia.com>
Thu, 9 Feb 2006 07:22:46 +0000 (09:22 +0200)
committerJuha Yrjola <juha.yrjola@nokia.com>
Thu, 9 Feb 2006 07:22:46 +0000 (09:22 +0200)
- Support for the Philips LPH8923 LCD panel
- Support for the Epson HWA742 LCD controller

- Support for frame buffer located in SRAM and/or SDRAM
- Support for boot loader initialized LCD controller / frame buffer
  content.

- LCD panels will now register a device in the relevant board-* files
  instead of specifying the LCD type as an OMAP_TAG_LCD. The controller
  type is still specified in OMAP_TAG_LCD.
- A new ATAG OMAP_TAG_FBMEM is used to describe the frame buffer memory
  configuration (SRAM and SDRAM regions)

- Changed the OMAP1 LCD controller driver to export its functions
  through the lcd_ctrl object.
- OMAP1 pixel clock divider will now round up in lcdc.c
- Changed the OMAP1 SoSSI driver to export its functions through the
  lcd_ctrl_extif object.
- OMAP1 SoSSI clock calculation goes through all possible clock
  dividers. Rounding of clock tick values now takes places at each
  timing parameter.

- OMAP2 RFBI clock calculation goes through all possible clock
  dividers. Rounding of clock tick values now takes places at each
  timing parameter.
- OMAP2 pixel clock divider will now round up in dispc.c

Signed-off-by: Imre Deak <imre.deak@nokia.com>
Signed-off-by: Juha Yrjölä <juha.yrjola@nokia.com>
41 files changed:
arch/arm/configs/n770_defconfig
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/io.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/io.c
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/fb.c [new file with mode: 0644]
arch/arm/plat-omap/sram.c
drivers/video/omap/Kconfig
drivers/video/omap/Makefile
drivers/video/omap/debug.h
drivers/video/omap/dispc.c
drivers/video/omap/hwa742.c [new file with mode: 0644]
drivers/video/omap/hwa742.h [new file with mode: 0644]
drivers/video/omap/lcd_h2.c
drivers/video/omap/lcd_h3.c
drivers/video/omap/lcd_h4.c
drivers/video/omap/lcd_inn1510.c
drivers/video/omap/lcd_inn1610.c
drivers/video/omap/lcd_lph8923.c [new file with mode: 0644]
drivers/video/omap/lcd_osk.c
drivers/video/omap/lcd_p2.c
drivers/video/omap/lcd_palmte.c
drivers/video/omap/lcdc.c
drivers/video/omap/lcdc.h [new file with mode: 0644]
drivers/video/omap/omapfb_main.c
drivers/video/omap/rfbi.c
drivers/video/omap/sossi.c
drivers/video/omap/sossi.h [deleted file]
include/asm-arm/arch-omap/board.h
include/asm-arm/arch-omap/lcd_lph8923.h [new file with mode: 0644]
include/asm-arm/arch-omap/omapfb.h
include/asm-arm/arch-omap/sram.h

index c1e2b57eb34c57541a00d8f1b31b449f38b799e0..6a3f7306d303574e9d48411624a4b3329fdd747f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.16-rc2-omap1
-# Wed Feb  8 18:52:38 2006
+# Wed Feb  8 19:07:23 2006
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
@@ -814,10 +814,12 @@ CONFIG_FB=y
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_S1D13XXX is not set
 CONFIG_FB_OMAP=y
-# CONFIG_FB_OMAP_LCDC_INTERNAL is not set
 CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+CONFIG_FB_OMAP_LCDC_HWA742=y
 CONFIG_FB_OMAP_MANUAL_UPDATE=y
-CONFIG_FB_OMAP_DMA_TUNE=y
+CONFIG_FB_OMAP_LCD_LPH8923=y
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
index 4cc6a31521f64ea47fa90ae157573704b401fd68..680e67ed654a1c53aaef631cc48161a6fe35ee88 100644 (file)
@@ -271,12 +271,18 @@ static struct platform_device h2_irda_device = {
        .resource       = h2_irda_resources,
 };
 
+static struct platform_device h2_lcd_device = {
+       .name           = "lcd_h2",
+       .id             = -1,
+};
+
 static struct platform_device *h2_devices[] __initdata = {
        &h2_nor_device,
        &h2_nand_device,
        &h2_smc91x_device,
        &h2_irda_device,
        &h2_kp_device,
+       &h2_lcd_device,
 };
 
 static void __init h2_init_smc91x(void)
@@ -325,7 +331,6 @@ static struct omap_uart_config h2_uart_config __initdata = {
 };
 
 static struct omap_lcd_config h2_lcd_config __initdata = {
-       .panel_name     = "h2",
        .ctrl_name      = "internal",
 };
 
index 29e17c8397e0c261d526088d76b50b4d8da159a3..96528226b30095d923d9cf0f1b0301429d32b40d 100644 (file)
@@ -349,6 +349,11 @@ static struct platform_device h3_irda_device = {
        .resource       = h3_irda_resources,
 };
 
+static struct platform_device h3_lcd_device = {
+       .name           = "lcd_h3",
+       .id             = -1,
+};
+
 static struct platform_device *devices[] __initdata = {
        &nor_device,
        &nand_device,
@@ -356,6 +361,7 @@ static struct platform_device *devices[] __initdata = {
        &intlat_device,
        &h3_irda_device,
        &h3_kp_device,
+       &h3_lcd_device,
 };
 
 static struct omap_usb_config h3_usb_config __initdata = {
@@ -385,7 +391,6 @@ static struct omap_uart_config h3_uart_config __initdata = {
 };
 
 static struct omap_lcd_config h3_lcd_config __initdata = {
-       .panel_name     = "h3",
        .ctrl_name      = "internal",
 };
 
index dde06b5fce47627e4fccbc272f9b70c2629e7344..e90c137a4cf315cbf70ec3959d74090d4554643e 100644 (file)
@@ -169,10 +169,16 @@ static struct platform_device innovator1510_smc91x_device = {
        .resource       = innovator1510_smc91x_resources,
 };
 
+static struct platform_device innovator1510_lcd_device = {
+       .name           = "lcd_inn1510",
+       .id             = -1,
+};
+
 static struct platform_device *innovator1510_devices[] __initdata = {
        &innovator_flash_device,
        &innovator1510_smc91x_device,
        &innovator_kp_device,
+       &innovator1510_lcd_device,
 };
 
 #endif /* CONFIG_ARCH_OMAP15XX */
@@ -199,10 +205,16 @@ static struct platform_device innovator1610_smc91x_device = {
        .resource       = innovator1610_smc91x_resources,
 };
 
+static struct platform_device innovator1610_lcd_device = {
+       .name           = "inn1610_lcd",
+       .id             = -1,
+};
+
 static struct platform_device *innovator1610_devices[] __initdata = {
        &innovator_flash_device,
        &innovator1610_smc91x_device,
        &innovator_kp_device,
+       &innovator1610_lcd_device,
 };
 
 #endif /* CONFIG_ARCH_OMAP16XX */
@@ -248,7 +260,6 @@ static struct omap_usb_config innovator1510_usb_config __initdata = {
 };
 
 static struct omap_lcd_config innovator1510_lcd_config __initdata = {
-       .panel_name     = "inn1510",
        .ctrl_name      = "internal",
 };
 #endif
@@ -270,7 +281,6 @@ static struct omap_usb_config h2_usb_config __initdata = {
 };
 
 static struct omap_lcd_config innovator1610_lcd_config __initdata = {
-       .panel_name     = "inn1610",
        .ctrl_name      = "internal",
 };
 #endif
index 5438de3ea7727db79d1176dfdf2a983832482d34..f56c89120b4a2e9711c595273150a604696e00a9 100644 (file)
@@ -30,6 +30,15 @@ static void __init omap_nokia770_init_irq(void)
        omap_init_irq();
 }
 
+static struct spi_board_info nokia770_spi_board_info[] __initdata = {
+       [0] = {
+               .modalias       = "lcd_lph8923",
+               .bus_num        = 2,
+               .chip_select    = 3,
+               .max_speed_hz   = 12000000,
+       },
+};
+
 static struct platform_device *nokia770_devices[] __initdata = {
 };
 
@@ -70,6 +79,8 @@ static void __init omap_nokia770_init(void)
        nokia770_config[0].data = &nokia770_usb_config;
 
        platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
+       spi_register_board_info(nokia770_spi_board_info,
+                               ARRAY_SIZE(nokia770_spi_board_info));
        omap_board_config = nokia770_config;
        omap_board_config_size = ARRAY_SIZE(nokia770_config);
        omap_serial_init();
index 9d6098b53feeda75a3fd3dec5c3a45bd31914b2f..16e08b476d6232c64c7c29a9bd998397c201b321 100644 (file)
@@ -178,12 +178,18 @@ static struct platform_device osk5912_kp_device = {
        .resource       = osk5912_kp_resources,
 };
 
+static struct platform_device osk5912_lcd_device = {
+       .name           = "lcd_osk",
+       .id             = -1,
+};
+
 static struct platform_device *osk5912_devices[] __initdata = {
        &osk5912_flash_device,
        &osk5912_smc91x_device,
        &osk5912_cf_device,
        &osk5912_mcbsp1_device,
        &osk5912_kp_device,
+       &osk5912_lcd_device,
 };
 
 static void __init osk_init_smc91x(void)
@@ -238,7 +244,6 @@ static struct omap_uart_config osk_uart_config __initdata = {
 };
 
 static struct omap_lcd_config osk_lcd_config __initdata = {
-       .panel_name     = "osk",
        .ctrl_name      = "internal",
 };
 
index e488f723677546059707e70df696eb9321104f76..4bc8a62909b9acc23161bf7041da6360bcc6c268 100644 (file)
@@ -38,6 +38,15 @@ static void __init omap_generic_init_irq(void)
        omap_init_irq();
 }
 
+static struct platform_device palmte_lcd_device = {
+       .name           = "lcd_palmte",
+       .id             = -1,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &palmte_lcd_device,
+};
+
 static struct omap_usb_config palmte_usb_config __initdata = {
        .register_dev   = 1,
        .hmc_mode       = 0,
@@ -55,7 +64,6 @@ static struct omap_mmc_config palmte_mmc_config __initdata = {
 };
 
 static struct omap_lcd_config palmte_lcd_config __initdata = {
-       .panel_name     = "palmte",
        .ctrl_name      = "internal",
 };
 
@@ -69,6 +77,8 @@ static void __init omap_generic_init(void)
 {
        omap_board_config = palmte_config;
        omap_board_config_size = ARRAY_SIZE(palmte_config);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 static void __init omap_generic_map_io(void)
index 1dc2dbfeb452ab1b9a79948782baed534616e109..64b45d8ae357e9e7e3addb767707201672aa6031 100644 (file)
@@ -186,11 +186,17 @@ static struct platform_device kp_device = {
        .resource       = kp_resources,
 };
 
+static struct platform_device lcd_device = {
+       .name           = "lcd_p2",
+       .id             = -1,
+};
+
 static struct platform_device *devices[] __initdata = {
        &nor_device,
        &nand_device,
        &smc91x_device,
        &kp_device,
+       &lcd_device,
 };
 
 #define P2_NAND_RB_GPIO_PIN    62
@@ -205,7 +211,6 @@ static struct omap_uart_config perseus2_uart_config __initdata = {
 };
 
 static struct omap_lcd_config perseus2_lcd_config __initdata = {
-       .panel_name     = "p2",
        .ctrl_name      = "internal",
 };
 
index 26d476d26a5ca65d69c9dc24d6f389cae1b6bf09..be3a2a4ee2b8c6d304b9e34187cb40ac25a11a91 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/io.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
 
 extern int omap1_clk_init(void);
 extern void omap_check_revision(void);
@@ -121,6 +122,7 @@ void __init omap1_map_common_io(void)
 #endif
 
        omap_sram_init();
+       omapfb_reserve_mem();
 }
 
 /*
index c4c5b926dfc4a2bdc1a2ee119cfe1feeda26bbc9..6c6ba172cdf6d7592da3fe42a2b73d0f0e12b514 100644 (file)
@@ -120,9 +120,15 @@ static struct platform_device apollon_smc91x_device = {
        .resource       = apollon_smc91x_resources,
 };
 
+static struct platform_device apollon_lcd_device = {
+       .name           = "apollon_lcd",
+       .id             = -1,
+};
+
 static struct platform_device *apollon_devices[] __initdata = {
        &apollon_onenand_device,
        &apollon_smc91x_device,
+       &apollon_lcd_device,
 };
 
 static inline void __init apollon_init_smc91x(void)
@@ -169,7 +175,6 @@ static struct omap_mmc_config apollon_mmc_config __initdata = {
 };
 
 static struct omap_lcd_config apollon_lcd_config __initdata = {
-       .panel_name     = "apollon",
        .ctrl_name      = "internal",
 };
 
index 85117eecfcdc85f6594dcf451a51ce742735cc71..9e64842f3f11b516fa87d203ed5545894d62fed6 100644 (file)
@@ -250,11 +250,17 @@ static struct platform_device h4_kp_device = {
        },
 };
 
+static struct platform_device h4_lcd_device = {
+       .name           = "lcd_h4",
+       .id             = -1,
+};
+
 static struct platform_device *h4_devices[] __initdata = {
        &h4_smc91x_device,
        &h4_flash_device,
        &h4_irda_device,
        &h4_kp_device,
+       &h4_lcd_device,
 };
 
 static inline void __init h4_init_smc91x(void)
@@ -301,7 +307,6 @@ static struct omap_mmc_config h4_mmc_config __initdata = {
 };
 
 static struct omap_lcd_config h4_lcd_config __initdata = {
-       .panel_name     = "h4",
        .ctrl_name      = "internal",
 };
 
index cfe155e750313cf72b348cb04560eb0dee25ca66..7d5711611f2f413cae141ec31fe9ccea382d234d 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
 
 extern void omap_sram_init(void);
 extern int omap2_clk_init(void);
@@ -59,6 +60,7 @@ void __init omap2_map_common_io(void)
 
        omap2_check_revision();
        omap_sram_init();
+       omapfb_reserve_mem();
 }
 
 void __init omap2_init_common_hw(void)
index c6ab7563c243dba52cf9cd055e7d8cde69229c84..58548616a0b9a903128d5da9d579db7b3a12607a 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
 obj-m :=
 obj-n :=
 obj-  :=
index 756b3d913f9b28abe617e54629a1e24b0689728d..079b67deac0f20fef726ce550739fa4345f5220c 100644 (file)
@@ -416,40 +416,6 @@ static void omap_init_rng(void)
 static inline void omap_init_rng(void) {}
 #endif
 
-#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
-
-static struct omap_lcd_config omap_fb_conf;
-
-static u64 omap_fb_dma_mask = ~(u32)0;
-
-static struct platform_device omap_fb_device = {
-       .name           = "omapfb",
-       .id             = -1,
-       .dev = {
-               .release                = omap_nop_release,
-               .dma_mask               = &omap_fb_dma_mask,
-               .coherent_dma_mask      = ~(u32)0,
-               .platform_data          = &omap_fb_conf,
-       },
-       .num_resources = 0,
-};
-
-static inline void omap_init_fb(void)
-{
-       const struct omap_lcd_config *conf;
-
-       conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
-       if (conf != NULL)
-               omap_fb_conf = *conf;
-       platform_device_register(&omap_fb_device);
-}
-
-#else
-
-static inline void omap_init_fb(void) {}
-
-#endif
-
 /*
  * This gets called after board-specific INIT_MACHINE, and initializes most
  * on-chip peripherals accessible on this board (except for few like USB):
@@ -475,7 +441,6 @@ static int __init omap_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_fb();
        omap_init_i2c();
        omap_init_kp();
        omap_init_mmc();
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
new file mode 100644 (file)
index 0000000..6dd5292
--- /dev/null
@@ -0,0 +1,84 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/sram.h>
+#include <asm/arch/omapfb.h>
+
+#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+
+static struct omapfb_platform_data omapfb_config;
+
+static u64 omap_fb_dma_mask = ~(u32)0;
+
+/* in devices.c */
+extern void omap_nop_release(struct device *dev);
+
+static struct platform_device omap_fb_device = {
+       .name           = "omapfb",
+       .id             = -1,
+       .dev = {
+               .release                = omap_nop_release,
+               .dma_mask               = &omap_fb_dma_mask,
+               .coherent_dma_mask      = ~(u32)0,
+               .platform_data          = &omapfb_config,
+       },
+       .num_resources = 0,
+};
+
+/* called from map_io */
+void omapfb_reserve_mem(void)
+{
+       const struct omap_fbmem_config *fbmem_conf;
+
+       omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
+       omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
+
+       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
+
+       if (fbmem_conf != NULL) {
+               /* indicate that the bootloader already initialized the
+                * fb device, so we'll skip that part in the fb driver
+                */
+               omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
+               omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
+               if (fbmem_conf->fb_sdram_size) {
+                       pr_info("Reserving %u bytes SDRAM for frame buffer\n",
+                               fbmem_conf->fb_sdram_size);
+                       reserve_bootmem(fbmem_conf->fb_sdram_start,
+                                       fbmem_conf->fb_sdram_size);
+               }
+       }
+}
+
+static inline int omap_init_fb(void)
+{
+       const struct omap_lcd_config *conf;
+
+       conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (conf == NULL)
+               return 0;
+
+       omapfb_config.lcd = *conf;
+
+       return platform_device_register(&omap_fb_device);
+}
+
+arch_initcall(omap_init_fb);
+
+#else
+
+void omapfb_reserve_mem(void) {}
+
+#endif
+
+
index b8368b5c73fb96d7f7ebae78c927c86b91e64a5f..b7bf09b1b412c4b6e34a095b163713ba14bd4720 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/sram.h>
+#include <asm/arch/board.h>
 
 #define OMAP1_SRAM_PA          0x20000000
 #define OMAP1_SRAM_VA          0xd0000000
@@ -50,6 +51,9 @@ static unsigned long omap_sram_base;
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
+unsigned long omap_fb_sram_start;
+unsigned long omap_fb_sram_size;
+
 /* Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessable size for all device types is 2k. A GP
  * device allows ARM11 but not other initators for full size. This
@@ -74,6 +78,32 @@ static int is_sram_locked(void)
                return 1; /* assume locked with no PPA or security driver */
 }
 
+void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
+                     unsigned long *start, unsigned long *size)
+{
+       const struct omap_fbmem_config *fbmem_conf;
+
+       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
+       if (fbmem_conf != NULL) {
+               *start = fbmem_conf->fb_sram_start;
+               *size = fbmem_conf->fb_sram_size;
+       } else {
+               *size = 0;
+               *start = 0;
+       }
+
+       if (*size && (
+           *start < start_avail ||
+           *start + *size > start_avail + size_avail)) {
+               printk(KERN_ERR "invalid FB SRAM configuration\n");
+               *start = start_avail;
+               *size = size_avail;
+       }
+
+       if (*size)
+               pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
+}
+
 /*
  * The amount of SRAM depends on the core type.
  * Note that we cannot try to test for SRAM here because writes
@@ -82,12 +112,16 @@ static int is_sram_locked(void)
  */
 void __init omap_detect_sram(void)
 {
+       unsigned long sram_start;
+
        if (cpu_is_omap24xx()) {
                if (is_sram_locked()) {
                        omap_sram_base = OMAP2_SRAM_PUB_VA;
+                       sram_start = OMAP2_SRAM_PUB_PA;
                        omap_sram_size = 0x800; /* 2K */
                } else {
                        omap_sram_base = OMAP2_SRAM_VA;
+                       sram_start = OMAP2_SRAM_PA;
                        if (cpu_is_omap242x())
                                omap_sram_size = 0xa0000; /* 640K */
                        else if (cpu_is_omap243x())
@@ -95,6 +129,7 @@ void __init omap_detect_sram(void)
                }
        } else {
                omap_sram_base = OMAP1_SRAM_VA;
+               sram_start = OMAP1_SRAM_PA;
 
                if (cpu_is_omap730())
                        omap_sram_size = 0x32000;       /* 200K */
@@ -110,6 +145,12 @@ void __init omap_detect_sram(void)
                        omap_sram_size = 0x4000;
                }
        }
+       get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
+                        omap_sram_size - SRAM_BOOTLOADER_SZ,
+                        &omap_fb_sram_start, &omap_fb_sram_size);
+       if (omap_fb_sram_size)
+               omap_sram_size -= sram_start + omap_sram_size -
+                                 omap_fb_sram_start;
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 }
 
index 3bf5df736ba64d638d65d94ac68eeaafa89ceb6d..6411c95095cdd459a3721dacd4f23c6678c7e5ef 100644 (file)
@@ -4,13 +4,6 @@ config FB_OMAP
         help
           Frame buffer driver for OMAP based boards.
 
-config FB_OMAP_LCDC_INTERNAL
-       bool "Internal LCD controller support"
-       depends on FB_OMAP
-       help
-         Say Y here, if you want to have support for the internal OMAP
-         LCD controller. If unsure, say Y.
-
 config FB_OMAP_LCDC_EXTERNAL
        bool "External LCD controller support"
        depends on FB_OMAP
@@ -18,6 +11,13 @@ config FB_OMAP_LCDC_EXTERNAL
          Say Y here, if you want to have support for boards with an
          external LCD controller connected to the SoSSI/RFBI interface. 
 
+config FB_OMAP_LCDC_HWA742
+       bool "Epson HWA742 LCD controller support"
+       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+       help
+         Say Y here if you want to have support for the external
+         Epson HWA742 LCD controller.
+
 config FB_OMAP_MANUAL_UPDATE
        bool "Default to manual update mode"
        depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
@@ -27,6 +27,21 @@ config FB_OMAP_MANUAL_UPDATE
           the frame buffer content and thus a reload of the image data to
          the external frame buffer is required. If unsure, say N.
 
+config FB_OMAP_LCD_LPH8923
+       bool "Philips LPH8923 LCD support"
+       depends on FB_OMAP
+       help
+         Say Y here if you want to have support for the Philips
+         LPH8923 LCD.
+
+config FB_OMAP_BOOTLOADER_INIT
+       bool "Check bootloader initializaion"
+       depends on FB_OMAP
+       help
+         Say Y here if you want to enable checking if the bootloader has
+         already initialized the display controller. In this case the
+         driver will skip the initialization.
+
 config FB_OMAP_DMA_TUNE
         bool "Set DMA SDRAM access priority high"
         depends on FB_OMAP && ARCH_OMAP1
@@ -37,3 +52,4 @@ config FB_OMAP_DMA_TUNE
           answer yes. Answer no if you have a dedicated video
           memory, or don't use any of the accelerated features.
 
+
index 3b6350cd06208ae83197f9415c817ef233a9807b..725ea29c6713592902a5810cfb275388cb8e8eb6 100644 (file)
@@ -6,13 +6,14 @@ obj-$(CONFIG_FB_OMAP) += omapfb.o
 
 objs-yy := omapfb_main.o
 
+objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
 objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
 
-objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_INTERNAL) += lcdc.o
-
 objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
 objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
 
+objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
+
 objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
 objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
 objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o
@@ -23,5 +24,7 @@ objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
 objs-y$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o
 objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
 
+objs-y$(CONFIG_FB_OMAP_LCD_LPH8923) += lcd_lph8923.o
+
 omapfb-objs := $(objs-yy)
 
index 835f28b6418073008ee74a18a367170db9b8b7d4..a280412aeb94a7b0284eb2724395e0b9f22596bc 100644 (file)
@@ -24,8 +24,6 @@
 #ifndef __OMAPFB_DEBUG_H
 #define __OMAPFB_DEBUG_H
 
-#include <asm/io.h>
-
 #ifdef OMAPFB_DBG
 
 #define DBGPRINT(level, fmt, ...) if (level <= OMAPFB_DBG) do { \
 #define DBGENTER(level) DBGPRINT(level, "Enter\n")
 #define DBGLEAVE(level)        DBGPRINT(level, "Leave\n")
 
-static inline void dump_dma_regs(int lch)
-{
-#ifdef CONFIG_ARCH_OMAP1
-#define _R(x) __REG16(OMAP_DMA_##x(lch))
-
-       DBGPRINT(4, "\nCSDP  :%#06x CCR      :%#06x CSSA_U  :%#06x "
-                   "\nCDSA_L:%#06x CDSA_U   :%#06x CEN     :%#06x "
-                   "\nCFN   :%#06x CSFI     :%#06x CSEI    :%#06x "
-                   "\nCSAC  :%#06x CICR     :%#06x CSR     :%04x "
-                   "\nCSSA_L:%#06x CDAC     :%#06x CDEI    :%#06x "
-                   "\nCDFI  :%#06x COLOR_L  :%#06x COLOR_U :%#06x "
-                   "\nCCR2  :%#06x CLNK_CTRL:%#06x LCH_CTRL:%#06x\n",
-                   _R(CSDP), _R(CCR), _R(CSSA_U),
-                   _R(CDSA_L), _R(CDSA_U), _R(CEN),
-                   _R(CFN), _R(CSFI), _R(CSEI),
-                   _R(CSAC), _R(CICR), 0, /* _R(CSR), */
-                   _R(CSSA_L), _R(CDAC), _R(CDEI),
-                   _R(CDFI), _R(COLOR_L), _R(COLOR_U),
-                   _R(CCR2), _R(CLNK_CTRL), _R(LCH_CTRL));
-#undef _R
-#endif
-}
-
-#define DUMP_DMA_REGS(lch) dump_dma_regs(lch)
-
 #else  /* OMAPFB_DBG */
 
 #define DBGPRINT(level, format, ...)
 #define DBGENTER(level)
 #define DBGLEAVE(level)
-#define DUMP_DMA_REGS(lch)
 
 #endif /* OMAPFB_DBG */
 
index 3ccbcd00fec906712f0938c299b666fc2303c68f..3185282887fbf785d9aa3db01c1c6aa79b0d88e1 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
 #include <linux/clk.h>
 
 #include <asm/io.h>
 
+#include <asm/arch/sram.h>
 #include <asm/arch/omapfb.h>
+#include <asm/arch/board.h>
 
 #include "dispc.h"
 
-/* #define OMAPFB_DBG  2 */
+/* #define OMAPFB_DBG  1 */
 
 #include "debug.h"
 
                                             DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
                                             DISPC_IRQ_SYNC_LOST)
 
+#define RFBI_CONTROL                   0x48050040
+
 #define MAX_PALETTE_SIZE               (256 * 16)
 
 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
 
 static struct {
        u32             base;
-       void            *vram_virt;
-       dma_addr_t      vram_phys;
-       int             vram_size;
+
+       dma_addr_t      fb_sram_paddr;
+       u32             fb_sram_size;
+       int             fb_sram_lines;
+
+       dma_addr_t      fb_sdram_paddr;
+       void            *fb_sdram_vaddr;
+       u32             fb_sdram_size;
+       int             fb_sdram_lines;
+
+       dma_addr_t      palette_paddr;
+       void            *palette_vaddr;
+
+       void            *fb_kern_vaddr;
+
+       int             multiplane_head;
 
        int             ext_mode;
+       int             fbmem_allocated;
 
        unsigned long   enabled_irqs;
        void            (*irq_callback)(void *);
@@ -152,8 +171,6 @@ static struct {
        struct clk      *dss_ick, *dss1_fck;
        struct clk      *dss_54m_fck;
 
-       int             active_plane_mask;
-
        enum omapfb_update_mode update_mode;
        struct omapfb_device    *fbdev;
 } dispc;
@@ -182,6 +199,11 @@ static void enable_rfbi_mode(int enable)
        l |= 1 << 15;
        l |= enable ? 0 : (1 << 16);
        dispc_write_reg(DISPC_CONTROL, l);
+
+       /* Set bypass mode in RFBI module */
+       l = __raw_readl(io_p2v(RFBI_CONTROL));
+       l |= enable ? 0 : (1 << 1);
+       __raw_writel(l, io_p2v(RFBI_CONTROL));
 }
 
 static void set_lcd_data_lines(int data_lines)
@@ -267,8 +289,8 @@ void omap_dispc_enable_digit_out(int enable)
 }
 EXPORT_SYMBOL(omap_dispc_enable_digit_out);
 
-static int omap_dispc_setup_plane(int plane, int channel_out,
-                                 unsigned long offset, int screen_width,
+static inline int _setup_plane(int plane, int channel_out,
+                                 u32 paddr, int screen_width,
                                  int pos_x, int pos_y, int width, int height,
                                  int color_mode)
 {
@@ -291,7 +313,10 @@ static int omap_dispc_setup_plane(int plane, int channel_out,
        int bpp;
        u32 l;
 
-       DBGENTER(1);
+       DBGPRINT(2, "plane %d channel %d paddr %u scr_width %d pos_x %d pos_y %d "
+                   "width %d height %d color_mode %d\n",
+                   plane, channel_out, paddr, screen_width, pos_x, pos_y,
+                   width, height, color_mode);
 
        switch (plane) {
        case OMAPFB_PLANE_GFX:
@@ -352,10 +377,7 @@ static int omap_dispc_setup_plane(int plane, int channel_out,
 
        dispc_write_reg(at_reg[plane], l);
 
-
-       dispc_write_reg(ba_reg[plane],
-                      dispc.vram_phys + PAGE_ALIGN(MAX_PALETTE_SIZE) + offset);
-
+       dispc_write_reg(ba_reg[plane], paddr);
        MOD_REG_FLD(ps_reg[plane],
                    FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
 
@@ -364,6 +386,52 @@ static int omap_dispc_setup_plane(int plane, int channel_out,
 
        dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
 
+       return height * screen_width * bpp / 8;
+}
+
+static int omap_dispc_setup_plane(int plane, int channel_out,
+                                 unsigned long offset, int screen_width,
+                                 int pos_x, int pos_y, int width, int height,
+                                 int color_mode)
+{
+       int yspan;
+       u32 paddr;
+       int mp_head = -1;
+       int r;
+
+       if (offset > dispc.fb_sram_size + dispc.fb_sdram_size)
+               return -EINVAL;
+
+       if (offset < dispc.fb_sram_size) {
+               paddr = dispc.fb_sram_paddr + offset;
+               yspan = min_t(int, height, dispc.fb_sram_lines);
+               if (yspan) {
+                       if ((r = _setup_plane(plane, channel_out, paddr,
+                                       screen_width, pos_x, pos_y,
+                                       width, height, color_mode)) < 0)
+                               return r;
+                       offset += r;
+                       height -= yspan;
+                       pos_y += yspan;
+                       mp_head = plane;
+                       if (++plane > 2)
+                               plane = OMAPFB_PLANE_GFX;
+               }
+       }
+       if (height) {
+               offset -= dispc.fb_sram_size;
+               paddr = dispc.fb_sdram_paddr + offset;
+               yspan = min_t(int, height, dispc.fb_sdram_lines);
+               if (yspan) {
+                       if ((r = _setup_plane(plane, channel_out, paddr,
+                                       screen_width, pos_x, pos_y,
+                                       width, height, color_mode)) < 0)
+                               return r;
+                       if (mp_head != -1)
+                               dispc.multiplane_head = mp_head;
+               }
+       }
+
        return 0;
 }
 
@@ -372,11 +440,16 @@ static int omap_dispc_enable_plane(int plane, int enable)
        const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
                                DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
                                DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
-       DBGENTER(1);
+       DBGENTER(2);
 
        if ((unsigned int)plane > 2)
                return -EINVAL;
        MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
+       if (plane == dispc.multiplane_head) {
+               if (++plane > 2)
+                       plane = OMAPFB_PLANE_GFX;
+               MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
+       }
 
        return 0;
 }
@@ -435,6 +508,7 @@ static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
        if (mode != dispc.update_mode) {
                switch (mode) {
                case OMAPFB_AUTO_UPDATE:
+               case OMAPFB_MANUAL_UPDATE:
                        omap_dispc_enable_lcd_out(1);
                        dispc.update_mode = mode;
                        break;
@@ -470,7 +544,7 @@ static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
        pck = max(1, pck);
        fck = clk_get_rate(dispc.dss1_fck);
        lck = fck;
-       *pck_div = lck / pck;
+       *pck_div = (lck + pck - 1) / pck;
        if (is_tft)
                *pck_div = max(2, *pck_div);
        else
@@ -489,6 +563,14 @@ static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
        }
 }
 
+static void set_lcd_tft_mode(int enable)
+{
+       u32 mask;
+
+       mask = 1 << 3;
+       MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
+}
+
 static void set_lcd_timings(void)
 {
        u32 l;
@@ -499,10 +581,6 @@ static void set_lcd_timings(void)
 
        DBGENTER(1);
 
-       /* TFT dither, TFT/STN */
-       l = (1 << 7) | (1 << 3);
-       MOD_REG_FLD(DISPC_CONTROL, l, is_tft ? l : 0);
-
        l = dispc_read_reg(DISPC_TIMING_H);
        l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
        l |= ( max(1, (min(64,  panel->hsw))) - 1 ) << 0;
@@ -588,7 +666,7 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev, struct pt_regs *re
 
        if (stat & DISPC_IRQ_MASK_ERROR) {
                if (jabber++ < 5) {
-                       pr_err("irq error status %04x\n", stat);
+                       pr_err("irq error status %04x\n", stat & 0x7fff);
                } else {
                        pr_err("disable irq\n");
                        dispc_write_reg(DISPC_IRQENABLE, 0);
@@ -684,8 +762,191 @@ static void omap_dispc_resume(void)
        DBGLEAVE(1);
 }
 
-/* Called when used in bypass mode */
-static int alloc_vram(int req_size)
+
+static int omap_dispc_update_window(struct omapfb_update_window *win,
+                                void (*complete_callback)(void *arg),
+                                void *complete_callback_data)
+{
+       return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
+}
+
+/* Greatest common divisor */
+static int calc_gcd(int a, int b)
+{
+       int tmp;
+
+       if (a < b) {
+               tmp = a;
+               a = b;
+               b = tmp;
+       }
+       for (;;) {
+               tmp = a % b;
+               if (tmp != 0) {
+                       a = b;
+                       b = tmp;
+               } else
+                       break;
+       }
+
+       return b;
+}
+
+/* Least common multiple */
+static int calc_lcm(int a, int b)
+{
+       return a * b / calc_gcd(a, b);
+}
+
+static void omap_dispc_get_vram_layout(unsigned long *size, void **virt,
+                                       dma_addr_t *phys)
+{
+       *size = dispc.fb_sram_size + dispc.fb_sdram_size;
+       *virt = dispc.fb_kern_vaddr;
+       /* Physical vram might not be contiguous. No one except own mmap
+        * should use this addr.
+        */
+       *phys = 0;
+}
+
+static int omap_dispc_mmap_user(struct vm_area_struct *vma)
+{
+       unsigned long len;
+       unsigned long offset;
+       unsigned long vaddr;
+       int r;
+
+       DBGPRINT(1, "vm_pgoff 0x%08lx vm_start 0x%08lx vm_end 0x%08lx\n",
+                       vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+               return -EINVAL;
+       offset = vma->vm_pgoff << PAGE_SHIFT;
+
+       if (offset >= dispc.fb_sram_size + dispc.fb_sdram_size)
+               return -EINVAL;
+
+       len = vma->vm_end - vma->vm_start;
+       if (offset + len > dispc.fb_sram_size + dispc.fb_sdram_size)
+               return -EINVAL;
+
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+       vma->vm_flags |= VM_PFNMAP;
+
+       vaddr = vma->vm_start;
+
+       if (dispc.fb_sram_size) {
+               if (offset < dispc.fb_sram_size) {
+                       int chunk = min_t(int, dispc.fb_sram_size - offset, len);
+                       DBGPRINT(1, "map sram va %08lx pa %08lx size %d\n",
+                                vaddr, dispc.fb_sram_paddr + offset, chunk);
+                       r = io_remap_pfn_range(vma, vaddr,
+                                          (dispc.fb_sram_paddr +
+                                          offset) >> PAGE_SHIFT, chunk,
+                                          vma->vm_page_prot);
+                       if (r == -EINVAL)
+                               return r;
+                       if (r < 0)
+                               return -EAGAIN;
+
+                       vaddr += chunk;
+                       len -= chunk;
+                       offset = 0;
+               } else
+                       offset -= dispc.fb_sram_size;
+       }
+
+       if (len) {
+               DBGPRINT(1, "map sdram va %08lx pa %08lx size %ld\n",
+                                vaddr, dispc.fb_sdram_paddr + offset, len);
+               BUG_ON(offset > dispc.fb_sdram_size ||
+                       offset + len > dispc.fb_sdram_size ||
+                       vma->vm_end - vaddr != len);
+               r = io_remap_pfn_range(vma, vaddr, (dispc.fb_sdram_paddr +
+                                  offset) >> PAGE_SHIFT, len,
+                                  vma->vm_page_prot);
+               /* no teardown of the previous mapping here.
+                * do_mmap_pgoff will take core of that. */
+               if (r == -EINVAL)
+                       return r;
+               if (r < 0)
+                       return -EAGAIN;
+       }
+
+       return 0;
+}
+
+static int mmap_kern(void)
+{
+       struct vm_struct        *kvma;
+       struct vm_area_struct   vma;
+       pgprot_t                pgprot;
+       unsigned long           vaddr;
+
+       DBGENTER(1);
+
+       kvma = get_vm_area(dispc.fb_sram_size + dispc.fb_sdram_size, VM_IOREMAP);
+       if (kvma == NULL) {
+               pr_err("can't get kernel vm area\n");
+               return -ENOMEM;
+       }
+       vma.vm_mm = &init_mm;
+
+       dispc.fb_kern_vaddr = kvma->addr;
+       vaddr = (unsigned long)kvma->addr;
+
+       pgprot = pgprot_writecombine(pgprot_kernel);
+       if (dispc.fb_sram_size) {
+               vma.vm_start = vaddr;
+               vma.vm_end = vaddr + dispc.fb_sram_size;
+               if (io_remap_pfn_range(&vma, vaddr,
+                                  dispc.fb_sram_paddr >> PAGE_SHIFT,
+                                  dispc.fb_sram_size, pgprot) < 0) {
+                       pr_err("kernel mmap for FBMEM failed\n");
+                       return -EAGAIN;
+               }
+               vaddr += dispc.fb_sram_size;
+       }
+       if (dispc.fb_sdram_size) {
+               vma.vm_start = vaddr;
+               vma.vm_end = vaddr + dispc.fb_sdram_size;
+               if (io_remap_pfn_range(&vma, vaddr,
+                                  dispc.fb_sdram_paddr >> PAGE_SHIFT,
+                                  dispc.fb_sdram_size, pgprot) < 0) {
+                       pr_err("kernel mmap for FBMEM failed\n");
+                       return -EAGAIN;
+               }
+       }
+
+       DBGLEAVE(1);
+
+       return 0;
+}
+
+static void unmap_kern(void)
+{
+       vunmap(dispc.fb_kern_vaddr);
+}
+
+static int alloc_palette_ram(void)
+{
+       dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+               MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
+       if (dispc.palette_vaddr == NULL) {
+               pr_err("failed to alloc palette memory\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void free_palette_ram(void)
+{
+       dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
+                       dispc.palette_vaddr, dispc.palette_paddr);
+}
+
+static int alloc_fbmem(int req_size)
 {
        int frame_size;
        struct lcd_panel *panel = dispc.fbdev->panel;
@@ -693,11 +954,11 @@ static int alloc_vram(int req_size)
        frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
        if (req_size > frame_size)
                frame_size = req_size;
-       dispc.vram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
-       dispc.vram_virt = dma_alloc_writecombine(dispc.fbdev->dev,
-                       dispc.vram_size, &dispc.vram_phys, GFP_KERNEL);
+       dispc.fb_sdram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
+       dispc.fb_kern_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+                       dispc.fb_sdram_size, &dispc.fb_sdram_paddr, GFP_KERNEL);
 
-       if (dispc.vram_virt == 0) {
+       if (dispc.fb_kern_vaddr == 0) {
                pr_err("unable to allocate fb DMA memory\n");
                return -ENOMEM;
        }
@@ -705,18 +966,75 @@ static int alloc_vram(int req_size)
        return 0;
 }
 
-static void free_vram(void)
+static void free_fbmem(void)
 {
-       dma_free_writecombine(dispc.fbdev->dev, dispc.vram_size,
-                             dispc.vram_virt, dispc.vram_phys);
+       dma_free_writecombine(dispc.fbdev->dev, dispc.fb_sdram_size,
+                             dispc.fb_kern_vaddr, dispc.fb_sdram_paddr);
 }
 
-static void omap_dispc_get_vram_layout(unsigned long *size, void **virt,
-                                       dma_addr_t *phys)
+static int setup_fbmem(int req_size)
 {
-       *size = dispc.vram_size - PAGE_ALIGN(MAX_PALETTE_SIZE);
-       *virt = (u8 *)dispc.vram_virt + PAGE_ALIGN(MAX_PALETTE_SIZE);
-       *phys = dispc.vram_phys + PAGE_ALIGN(MAX_PALETTE_SIZE);
+       struct lcd_panel *panel = dispc.fbdev->panel;
+       struct omapfb_platform_data *conf;
+       unsigned long size_align;
+       int line_size;
+       int frame_size;
+       int lines;
+       int r;
+
+       conf = dispc.fbdev->dev->platform_data;
+
+       if (conf->fbmem.fb_sram_size + conf->fbmem.fb_sdram_size == 0) {
+               if ((r = alloc_fbmem(req_size)) < 0)
+                       return r;
+               dispc.fbmem_allocated = 1;
+               dispc.fb_sdram_lines = panel->y_res;
+               return 0;
+       }
+
+       dispc.fb_sram_paddr = conf->fbmem.fb_sram_start;
+       dispc.fb_sram_size = conf->fbmem.fb_sram_size;
+       dispc.fb_sdram_paddr = conf->fbmem.fb_sdram_start;
+       dispc.fb_sdram_size = conf->fbmem.fb_sdram_size;
+
+       line_size = panel->x_res * panel->bpp / 8;
+       frame_size = PAGE_ALIGN(line_size * panel->y_res);
+
+       size_align = calc_lcm(line_size, PAGE_SIZE);
+
+       if (dispc.fb_sram_size + dispc.fb_sdram_size < frame_size ||
+           (dispc.fb_sdram_size && (dispc.fb_sram_size % size_align))) {
+               pr_err("Invalid FB memory configuration\n");
+               return -EINVAL;
+       }
+
+       if (dispc.fb_sram_size + dispc.fb_sdram_size < req_size) {
+               pr_err("%d vram was requested, but only %u is available\n",
+                       req_size, dispc.fb_sram_size + dispc.fb_sdram_size);
+       }
+
+       lines = dispc.fb_sram_size / line_size;
+       lines = min_t(int, panel->y_res, lines);
+       dispc.fb_sram_lines = lines;
+       lines = panel->y_res - lines;
+       dispc.fb_sdram_lines = lines;
+
+       if ((r = mmap_kern()) < 0)
+               return r;
+
+       DBGPRINT(1, "fb_sram %08x size %08x fb_sdram %08x size %08x\n",
+                dispc.fb_sram_paddr, dispc.fb_sram_size,
+                dispc.fb_sdram_paddr, dispc.fb_sdram_size);
+
+       return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+       if (dispc.fbmem_allocated)
+               free_fbmem();
+       else
+               unmap_kern();
 }
 
 static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
@@ -726,6 +1044,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        u32 l;
        struct lcd_panel *panel = fbdev->panel;
        int tmo = 10000;
+       int skip_init = 0;
 
        DBGENTER(1);
 
@@ -735,39 +1054,50 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        dispc.fbdev = fbdev;
        dispc.ext_mode = ext_mode;
 
+       dispc.multiplane_head = -1;
+
+       if (fbdev->dev->platform_data == NULL) {
+               pr_err("missing FB configuration\n");
+               return -ENOENT;
+       }
+
+       init_completion(&dispc.frame_done);
+
        if ((r = get_dss_clocks()) < 0)
-               goto fail0;
+               return r;
 
        enable_lcd_clocks(1);
-       /* Reset monitoring works only w/ the 54M clk */
-       enable_digit_clocks(1);
 
        l = dispc_read_reg(DISPC_REVISION);
        pr_info(MODULE_NAME ": version %d.%d\n", l >> 4 & 0x0f, l & 0x0f);
 
-       /* Soft reset */
-       MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
-
-       while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
-               if (!--tmo) {
-                       pr_err("soft reset failed\n");
-                       r = -ENODEV;
-                       enable_digit_clocks(0);
-                       goto fail1;
-               }
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+       l = dispc_read_reg(DISPC_CONTROL);
+       /* LCD enabled ? */
+       if (l & 1) {
+               pr_info(MODULE_NAME ": skipping hardware initialization\n");
+               skip_init = 1;
        }
+#endif
 
-       enable_digit_clocks(0);
+       if (!skip_init) {
+               /* Reset monitoring works only w/ the 54M clk */
+               enable_digit_clocks(1);
 
-       if (!ext_mode && (r = alloc_vram(req_vram_size)) < 0)
-               goto fail1;
+               /* Soft reset */
+               MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
 
-       /* Set logic clock to the fck for now */
-       MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1);
+               while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
+                       if (!--tmo) {
+                               pr_err("soft reset failed\n");
+                               r = -ENODEV;
+                               enable_digit_clocks(0);
+                               goto fail1;
+                       }
+               }
 
-       setup_plane_fifo(0);
-       setup_plane_fifo(1);
-       setup_plane_fifo(2);
+               enable_digit_clocks(0);
+       }
 
        l = dispc_read_reg(DISPC_IRQSTATUS);
        dispc_write_reg(l, DISPC_IRQSTATUS);
@@ -778,38 +1108,60 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
                           0, MODULE_NAME, NULL)) < 0) {
                pr_err("can't get DSS IRQ\n");
-               goto fail2;
+               goto fail1;
        }
 
-       set_lcd_data_lines(panel->data_lines);
-       set_load_mode(DISPC_LOAD_FRAME_ONLY);
+       /* L3 firewall setting: enable access to OCM RAM */
+       __raw_writel(0x402000b0, io_p2v(0x680050a0));
 
-       if (!ext_mode) {
-               omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
-               set_lcd_timings();
+       if ((r = alloc_palette_ram()) < 0)
+               goto fail2;
+
+       if ((r = setup_fbmem(req_vram_size)) < 0)
+               goto fail3;
+
+       if (!skip_init) {
+               memset(dispc.fb_kern_vaddr, 0,
+                       dispc.fb_sram_size + dispc.fb_sdram_size);
+
+               /* Set logic clock to fck, pixel clock to fck/2 for now */
+               MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
+               MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
+
+               setup_plane_fifo(0);
+               setup_plane_fifo(1);
+               setup_plane_fifo(2);
+
+               set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
+               set_lcd_data_lines(panel->data_lines);
+               set_load_mode(DISPC_LOAD_FRAME_ONLY);
+
+               if (!ext_mode) {
+                       omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
+                       set_lcd_timings();
+               }
+               enable_rfbi_mode(ext_mode);
        }
-       enable_rfbi_mode(ext_mode);
 
-       DBGLEAVE(1);
        return 0;
+fail3:
+       free_palette_ram();
 fail2:
-       if (ext_mode)
-               free_vram();
+       free_irq(INT_24XX_DSS_IRQ, NULL);
 fail1:
        enable_lcd_clocks(0);
        put_dss_clocks();
-fail0:
-       DBGLEAVE(1);
-        return r;
+
+       return r;
 }
 
 static void omap_dispc_cleanup(void)
 {
+       cleanup_fbmem();
+       free_palette_ram();
        free_irq(INT_24XX_DSS_IRQ, NULL);
        enable_lcd_clocks(0);
        put_dss_clocks();
-       if (dispc.ext_mode)
-               free_vram();
 }
 
 static unsigned long omap_dispc_get_caps(void)
@@ -822,10 +1174,11 @@ struct lcd_ctrl omap2_int_ctrl = {
        .init                   = omap_dispc_init,
        .cleanup                = omap_dispc_cleanup,
        .get_vram_layout        = omap_dispc_get_vram_layout,
+       .mmap                   = omap_dispc_mmap_user,
        .get_caps               = omap_dispc_get_caps,
        .set_update_mode        = omap_dispc_set_update_mode,
        .get_update_mode        = omap_dispc_get_update_mode,
-       .update_window          = NULL,
+       .update_window          = omap_dispc_update_window,
        .suspend                = omap_dispc_suspend,
        .resume                 = omap_dispc_resume,
        .setup_plane            = omap_dispc_setup_plane,
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
new file mode 100644 (file)
index 0000000..899573f
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+ * File: drivers/video/omap/hwa742.c
+ *
+ * Epson HWA742 LCD controller driver
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Authors:     Juha Yrjölä   <juha.yrjola@nokia.com>
+ *             Imre Deak     <imre.deak@nokia.com>
+ * YUV support: Jussi Laako   <jussi.laako@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+/* #define OMAPFB_DBG 1 */
+
+#include "hwa742.h"
+#include "debug.h"
+
+#define MODULE_NAME                    "omapfb-hwa742"
+
+#define HWA742_REV_CODE_REG       0x0
+#define HWA742_CONFIG_REG         0x2
+#define HWA742_PLL_DIV_REG        0x4
+#define HWA742_PLL_0_REG          0x6
+#define HWA742_PLL_1_REG          0x8
+#define HWA742_PLL_2_REG          0xa
+#define HWA742_PLL_3_REG          0xc
+#define HWA742_PLL_4_REG          0xe
+#define HWA742_CLK_SRC_REG        0x12
+#define HWA742_PANEL_TYPE_REG     0x14
+#define HWA742_H_DISP_REG         0x16
+#define HWA742_H_NDP_REG          0x18
+#define HWA742_V_DISP_1_REG       0x1a
+#define HWA742_V_DISP_2_REG       0x1c
+#define HWA742_V_NDP_REG          0x1e
+#define HWA742_HS_W_REG           0x20
+#define HWA742_HP_S_REG           0x22
+#define HWA742_VS_W_REG           0x24
+#define HWA742_VP_S_REG           0x26
+#define HWA742_PCLK_POL_REG       0x28
+#define HWA742_INPUT_MODE_REG     0x2a
+#define HWA742_TRANSL_MODE_REG1   0x2e
+#define HWA742_DISP_MODE_REG      0x34
+#define HWA742_WINDOW_TYPE        0x36
+#define HWA742_WINDOW_X_START_0   0x38
+#define HWA742_WINDOW_X_START_1   0x3a
+#define HWA742_WINDOW_Y_START_0   0x3c
+#define HWA742_WINDOW_Y_START_1   0x3e
+#define HWA742_WINDOW_X_END_0     0x40
+#define HWA742_WINDOW_X_END_1     0x42
+#define HWA742_WINDOW_Y_END_0     0x44
+#define HWA742_WINDOW_Y_END_1     0x46
+#define HWA742_MEMORY_WRITE_LSB   0x48
+#define HWA742_MEMORY_WRITE_MSB   0x49
+#define HWA742_MEMORY_READ_0      0x4a
+#define HWA742_MEMORY_READ_1      0x4c
+#define HWA742_MEMORY_READ_2      0x4e
+#define HWA742_POWER_SAVE         0x56
+#define HWA742_NDP_CTRL           0x58
+
+#define HWA742_AUTO_UPDATE_TIME                (HZ / 20)
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+/* Reserve 4 request slots for requests in irq context */
+#define REQ_POOL_SIZE                  24
+#define IRQ_REQ_POOL_SIZE              4
+
+struct update_param {
+       int     x, y, width, height;
+       int     color_mode;
+       int     flags;
+};
+
+#define REQ_FROM_IRQ_POOL 0x01
+
+#define REQ_COMPLETE   0
+#define REQ_PENDING    1
+
+struct hwa742_request {
+       struct list_head entry;
+       unsigned int     flags;
+
+       int              (*handler)(struct hwa742_request *req);
+       void             (*complete)(void *data);
+       void             *complete_data;
+
+       union {
+               struct update_param     update;
+               struct completion       *sync;
+       } par;
+};
+
+struct hwa742_struct {
+       enum omapfb_update_mode update_mode;
+       enum omapfb_update_mode update_mode_before_suspend;
+
+       struct timer_list       auto_update_timer;
+       int                     stop_auto_update;
+       struct omapfb_update_window     auto_update_window;
+
+       struct hwa742_request   req_pool[REQ_POOL_SIZE];
+       struct list_head        pending_req_list;
+       struct list_head        free_req_list;
+       struct semaphore        req_sema;
+       spinlock_t              req_lock;
+
+       struct clk              *sys_ck;
+       struct extif_timings    reg_timings, lut_timings;
+
+       int                     prev_color_mode;
+       int                     prev_flags;
+       int                     window_type;
+
+       u32                     max_transmit_size;
+       u32                     extif_clk_period;
+
+       struct omapfb_device    *fbdev;
+       struct lcd_ctrl_extif   *extif;
+       struct lcd_ctrl         *int_ctrl;
+} hwa742;
+
+static u8 hwa742_read_reg(u8 reg)
+{
+       u8 data;
+
+       hwa742.extif->set_bits_per_cycle(8);
+       hwa742.extif->write_command(&reg, 1);
+       hwa742.extif->read_data(&data, 1);
+
+       return data;
+}
+
+static void hwa742_write_reg(u8 reg, u8 data)
+{
+       hwa742.extif->set_bits_per_cycle(8);
+       hwa742.extif->write_command(&reg, 1);
+       hwa742.extif->write_data(&data, 1);
+}
+
+void hwa742_read_id(int *rev_code, int *config)
+{
+       *rev_code = hwa742_read_reg(HWA742_REV_CODE_REG);
+       *config = hwa742_read_reg(HWA742_CONFIG_REG);
+}
+EXPORT_SYMBOL(hwa742_read_id);
+
+static void set_window_regs(int x_start, int y_start, int x_end, int y_end)
+{
+       u8 tmp[8];
+       u8 cmd;
+
+       x_end--;
+       y_end--;
+       tmp[0] = x_start;
+       tmp[1] = x_start >> 8;
+       tmp[2] = y_start;
+       tmp[3] = y_start >> 8;
+       tmp[4] = x_end;
+       tmp[5] = x_end >> 8;
+       tmp[6] = y_end;
+       tmp[7] = y_end >> 8;
+
+       hwa742.extif->set_bits_per_cycle(8);
+       cmd = HWA742_WINDOW_X_START_0;
+
+       hwa742.extif->write_command(&cmd, 1);
+
+       hwa742.extif->write_data(tmp, 8);
+}
+
+static void set_format_regs(int conv, int transl, int flags)
+{
+       if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
+               hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01);
+               DBGPRINT(2, "hwa742: enabled pixel doubling\n");
+       } else {
+               hwa742.window_type = (hwa742.window_type & 0xfc);
+               DBGPRINT(2, "hwa742: disabled pixel doubling\n");
+       }
+
+       hwa742_write_reg(HWA742_INPUT_MODE_REG, conv);
+       hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl);
+       hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type);
+}
+
+static inline struct hwa742_request *alloc_req(void)
+{
+       unsigned long flags;
+       struct hwa742_request *req;
+       int req_flags = 0;
+
+       if (!in_interrupt())
+               down(&hwa742.req_sema);
+       else
+               req_flags = REQ_FROM_IRQ_POOL;
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+       BUG_ON(list_empty(&hwa742.free_req_list));
+       req = list_entry(hwa742.free_req_list.next,
+                        struct hwa742_request, entry);
+       list_del(&req->entry);
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+       INIT_LIST_HEAD(&req->entry);
+       req->flags = req_flags;
+
+       return req;
+}
+
+static inline void free_req(struct hwa742_request *req)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+
+       list_del(&req->entry);
+       list_add(&req->entry, &hwa742.free_req_list);
+       if (!(req->flags & REQ_FROM_IRQ_POOL))
+               up(&hwa742.req_sema);
+
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+}
+
+static void process_pending_requests(void)
+{
+       unsigned long flags;
+
+       DBGENTER(2);
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+
+       while (!list_empty(&hwa742.pending_req_list)) {
+               struct hwa742_request *req;
+               void (*complete)(void *);
+               void *complete_data;
+
+               req = list_entry(hwa742.pending_req_list.next,
+                                struct hwa742_request, entry);
+               spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+               if (req->handler(req) == REQ_PENDING)
+                       return;
+
+               complete = req->complete;
+               complete_data = req->complete_data;
+               free_req(req);
+
+               if (complete)
+                       complete(complete_data);
+
+               spin_lock_irqsave(&hwa742.req_lock, flags);
+       }
+
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+       DBGLEAVE(2);
+}
+
+static void submit_req_list(struct list_head *head)
+{
+       unsigned long flags;
+       int process = 1;
+
+       DBGENTER(2);
+
+       spin_lock_irqsave(&hwa742.req_lock, flags);
+       if (likely(!list_empty(&hwa742.pending_req_list)))
+               process = 0;
+       list_splice_init(head, hwa742.pending_req_list.prev);
+       spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+       if (process)
+               process_pending_requests();
+
+       DBGLEAVE(2);
+}
+
+static void request_complete(void *data)
+{
+       struct hwa742_request   *req = (struct hwa742_request *)data;
+       void                    (*complete)(void *);
+       void                    *complete_data;
+
+       complete = req->complete;
+       complete_data = req->complete_data;
+
+       free_req(req);
+
+       if (complete)
+               complete(complete_data);
+
+       process_pending_requests();
+}
+
+static int send_frame_handler(struct hwa742_request *req)
+{
+       struct update_param *par = &req->par.update;
+       int x = par->x;
+       int y = par->y;
+       int w = par->width;
+       int h = par->height;
+       int bpp;
+       int conv, transl;
+       unsigned long offset;
+       int color_mode = par->color_mode;
+       int flags = par->flags;
+       int scr_width = 800;
+
+       DBGPRINT(2, "x %d y %d w %d h %d scr_width %d color_mode %d flags %d\n",
+               x, y, w, h, scr_width, color_mode, flags);
+
+       switch (color_mode) {
+       case OMAPFB_COLOR_YUV422:
+               bpp = 16;
+               conv = 0x08;
+               transl = 0x25;
+               break;
+       case OMAPFB_COLOR_YUV420:
+               bpp = 12;
+               conv = 0x09;
+               transl = 0x25;
+               break;
+       case OMAPFB_COLOR_RGB565:
+               bpp = 16;
+               conv = 0x01;
+               transl = 0x05;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (hwa742.prev_flags != flags ||
+           hwa742.prev_color_mode != color_mode) {
+               set_format_regs(conv, transl, flags);
+               hwa742.prev_color_mode = color_mode;
+               hwa742.prev_flags = flags;
+       }
+
+       set_window_regs(x, y, x + w, y + h);
+
+       offset = (scr_width * y + x) * bpp / 8;
+
+       hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX,
+                       OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h,
+                       color_mode);
+
+       hwa742.extif->set_bits_per_cycle(16);
+
+       hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
+       hwa742.extif->transfer_area(w, h, request_complete, req);
+
+       return REQ_PENDING;
+}
+
+static void send_frame_complete(void *data)
+{
+       hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0);
+}
+
+#define ADD_PREQ(_x, _y, _w, _h) do {          \
+       req = alloc_req();                      \
+       req->handler    = send_frame_handler;   \
+       req->complete   = send_frame_complete;  \
+       req->par.update.x = _x;                 \
+       req->par.update.y = _y;                 \
+       req->par.update.width  = _w;            \
+       req->par.update.height = _h;            \
+       req->par.update.color_mode = color_mode;\
+       req->par.update.flags     = flags;      \
+       list_add_tail(&req->entry, req_head);   \
+} while(0)
+
+static void create_req_list(struct omapfb_update_window *win,
+                           struct list_head *req_head)
+{
+       struct hwa742_request *req;
+       int x = win->x;
+       int y = win->y;
+       int width = win->width;
+       int height = win->height;
+       int color_mode;
+       int flags;
+
+       flags = win->format & OMAPFB_FORMAT_FLAG_DOUBLE;
+       color_mode = win->format & OMAPFB_FORMAT_MASK;
+
+       if (x & 1) {
+               ADD_PREQ(x, y, 1, height);
+               width--;
+               x++;
+       }
+       if (width & ~1) {
+               unsigned int xspan = width & ~1;
+               unsigned int ystart = y;
+               unsigned int yspan = height;
+
+               if (xspan * height * 2 > hwa742.max_transmit_size) {
+                       yspan = hwa742.max_transmit_size / (xspan * 2);
+                       ADD_PREQ(x, ystart, xspan, yspan);
+                       ystart += yspan;
+                       yspan = height - yspan;
+               }
+
+               ADD_PREQ(x, ystart, xspan, yspan);
+               x += xspan;
+               width -= xspan;
+       }
+       if (width)
+               ADD_PREQ(x, y, 1, height);
+}
+
+static void auto_update_complete(void *data)
+{
+       DBGENTER(2);
+
+       if (!hwa742.stop_auto_update)
+               mod_timer(&hwa742.auto_update_timer,
+                         jiffies + HWA742_AUTO_UPDATE_TIME);
+
+       DBGLEAVE(2);
+}
+
+static void hwa742_update_window_auto(unsigned long arg)
+{
+       LIST_HEAD(req_list);
+       struct hwa742_request *last;
+
+       DBGENTER(2);
+
+       create_req_list(&hwa742.auto_update_window, &req_list);
+       last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+       last->complete = auto_update_complete;
+       last->complete_data = NULL;
+
+       submit_req_list(&req_list);
+
+       DBGLEAVE(2);
+}
+
+int hwa742_update_window_async(struct omapfb_update_window *win,
+                                void (*complete_callback)(void *arg),
+                                void *complete_callback_data)
+{
+       LIST_HEAD(req_list);
+       struct hwa742_request *last;
+       int r = 0;
+
+       DBGENTER(2);
+
+       if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {
+               r = -EINVAL;
+               goto out;
+       }
+       if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) {
+               r = -EINVAL;
+               goto out;
+       }
+
+       create_req_list(win, &req_list);
+       last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+       last->complete = complete_callback;
+       last->complete_data = (void *)complete_callback_data;
+
+       submit_req_list(&req_list);
+
+out:
+       DBGLEAVE(2);
+       return r;
+}
+EXPORT_SYMBOL(hwa742_update_window_async);
+
+static int hwa742_setup_plane(int plane, int channel_out,
+                                 unsigned long offset, int screen_width,
+                                 int pos_x, int pos_y, int width, int height,
+                                 int color_mode)
+{
+       if (plane != OMAPFB_PLANE_GFX ||
+           channel_out != OMAPFB_CHANNEL_OUT_LCD)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int hwa742_enable_plane(int plane, int enable)
+{
+       if (plane != 0)
+               return -EINVAL;
+
+       hwa742.int_ctrl->enable_plane(plane, enable);
+
+       return 0;
+}
+
+static int sync_handler(struct hwa742_request *req)
+{
+       complete(req->par.sync);
+       return REQ_COMPLETE;
+}
+
+static void hwa742_sync(void)
+{
+       LIST_HEAD(req_list);
+       struct hwa742_request *req;
+       struct completion comp;
+
+       DBGENTER(2);
+
+       req = alloc_req();
+
+       req->handler = sync_handler;
+       req->complete = NULL;
+       init_completion(&comp);
+       req->par.sync = &comp;
+
+       list_add(&req->entry, &req_list);
+       submit_req_list(&req_list);
+
+       wait_for_completion(&comp);
+
+       DBGLEAVE(2);
+}
+
+static struct notifier_block *hwa742_client_list;
+
+int hwa742_register_client(struct hwa742_notifier_block *hwa742_nb,
+                           hwa742_notifier_callback_t callback,
+                           void *callback_data)
+{
+       int r;
+
+       DBGPRINT(1, "update_mode %d\n", hwa742.update_mode);
+       hwa742_nb->nb.notifier_call = (int (*)(struct notifier_block *,
+                                       unsigned long, void *))callback;
+       hwa742_nb->data = callback_data;
+       r = notifier_chain_register(&hwa742_client_list, &hwa742_nb->nb);
+       if (r)
+               return r;
+       if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) {
+               DBGPRINT(1, "calling client list\n");
+               notifier_call_chain(&hwa742_client_list,
+                                   HWA742_EVENT_READY,
+                                   hwa742.fbdev);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(hwa742_register_client);
+
+int hwa742_unregister_client(struct hwa742_notifier_block *hwa742_nb)
+{
+       return notifier_chain_unregister(&hwa742_client_list,
+                                        &hwa742_nb->nb);
+}
+EXPORT_SYMBOL(hwa742_unregister_client);
+
+static int hwa742_set_update_mode(enum omapfb_update_mode mode)
+{
+       int r = 0;
+
+       DBGENTER(1);
+
+       if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE &&
+           mode != OMAPFB_UPDATE_DISABLED) {
+               r = -EINVAL;
+               goto out;
+       }
+
+       if (mode == hwa742.update_mode)
+               goto out;
+
+       printk(KERN_INFO "hwa742: setting update mode to %s\n",
+                       mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
+                       (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
+
+       switch (hwa742.update_mode) {
+       case OMAPFB_MANUAL_UPDATE:
+               notifier_call_chain(&hwa742_client_list,
+                                   HWA742_EVENT_DISABLED,
+                                   hwa742.fbdev);
+               break;
+       case OMAPFB_AUTO_UPDATE:
+               hwa742.stop_auto_update = 1;
+               del_timer_sync(&hwa742.auto_update_timer);
+               break;
+       case OMAPFB_UPDATE_DISABLED:
+               break;
+       }
+
+       hwa742.update_mode = mode;
+       hwa742_sync();
+       hwa742.stop_auto_update = 0;
+
+       switch (mode) {
+       case OMAPFB_MANUAL_UPDATE:
+               notifier_call_chain(&hwa742_client_list,
+                                   HWA742_EVENT_READY,
+                                   hwa742.fbdev);
+               break;
+       case OMAPFB_AUTO_UPDATE:
+               hwa742_update_window_auto(0);
+               break;
+       case OMAPFB_UPDATE_DISABLED:
+               break;
+       }
+out:
+
+       DBGLEAVE(1);
+       return r;
+}
+
+static enum omapfb_update_mode hwa742_get_update_mode(void)
+{
+       return hwa742.update_mode;
+}
+
+static unsigned long round_to_extif_ticks(unsigned long ps, int div)
+{
+       int bus_tick = hwa742.extif_clk_period * div;
+       return (ps + bus_tick - 1) / bus_tick * bus_tick;
+}
+
+static int calc_reg_timing(unsigned long sysclk, int div)
+{
+       struct extif_timings *t;
+       unsigned long systim;
+
+       /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+        * AccessTime 2 ns + 12.2 ns (regs),
+        * WEOffTime = WEOnTime + 1 ns,
+        * REOffTime = REOnTime + 16 ns (regs),
+        * CSOffTime = REOffTime + 1 ns
+        * ReadCycle = 2ns + 2*SYSCLK  (regs),
+        * WriteCycle = 2*SYSCLK + 2 ns,
+        * CSPulseWidth = 10 ns */
+       systim = 1000000000 / (sysclk / 1000);
+       DBGPRINT(1, "HWA742 systim %lu ps extif_clk_period %u ps"
+                 "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+       t = &hwa742.reg_timings;
+       memset(t, 0, sizeof(*t));
+       t->clk_div = div;
+       t->cs_on_time = 0;
+       t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div);
+       t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+       t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div);
+       t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+       t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+       if (t->we_cycle_time < t->we_off_time)
+               t->we_cycle_time = t->we_off_time;
+       t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+       if (t->re_cycle_time < t->re_off_time)
+               t->re_cycle_time = t->re_off_time;
+       t->cs_pulse_width = 0;
+
+       DBGPRINT(1, "[reg]cson %d csoff %d reon %d reoff %d\n",
+                t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+       DBGPRINT(1, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
+                t->we_on_time, t->we_off_time, t->re_cycle_time,
+                t->we_cycle_time);
+       DBGPRINT(1, "[reg]rdaccess %d cspulse %d\n",
+                t->access_time, t->cs_pulse_width);
+
+       return hwa742.extif->convert_timings(t);
+}
+
+static int calc_lut_timing(unsigned long sysclk, int div)
+{
+       struct extif_timings *t;
+       unsigned long systim;
+
+       /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+        * AccessTime 2 ns + 4 * SYSCLK + 26 (lut),
+        * WEOffTime = WEOnTime + 1 ns,
+        * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut),
+        * CSOffTime = REOffTime + 1 ns
+        * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut),
+        * WriteCycle = 2*SYSCLK + 2 ns,
+        * CSPulseWidth = 10 ns
+        */
+       systim = 1000000000 / (sysclk / 1000);
+       DBGPRINT(1, "HWA742 systim %lu ps extif_clk_period %u ps"
+                 "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+       t = &hwa742.lut_timings;
+       memset(t, 0, sizeof(*t));
+
+       t->clk_div = div;
+
+       t->cs_on_time = 0;
+       t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+       t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+                                             26000, div);
+       t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+       t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+                                             26000, div);
+       t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+       t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+       if (t->we_cycle_time < t->we_off_time)
+               t->we_cycle_time = t->we_off_time;
+       t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div);
+       if (t->re_cycle_time < t->re_off_time)
+               t->re_cycle_time = t->re_off_time;
+       t->cs_pulse_width = 0;
+
+       DBGPRINT(1, "[lut]cson %d csoff %d reon %d reoff %d\n",
+                t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+       DBGPRINT(1, "[lut]weon %d weoff %d recyc %d wecyc %d\n",
+                t->we_on_time, t->we_off_time, t->re_cycle_time,
+                t->we_cycle_time);
+       DBGPRINT(1, "[lut]rdaccess %d cspulse %d\n",
+                t->access_time, t->cs_pulse_width);
+
+       return hwa742.extif->convert_timings(t);
+}
+
+static int calc_extif_timings(unsigned long sysclk)
+{
+       int max_clk_div;
+       int div;
+
+       hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div);
+       for (div = 1; div < max_clk_div; div++) {
+               if (calc_reg_timing(sysclk, div) == 0)
+                       break;
+       }
+       if (div == max_clk_div)
+               goto err;
+
+       for (div = 1; div < max_clk_div; div++) {
+               if (calc_lut_timing(sysclk, div) == 0)
+                       break;
+       }
+
+       if (div < max_clk_div)
+               return 0;
+
+err:
+       pr_err("can't setup timings\n");
+       return -1;
+}
+
+static unsigned long hwa742_get_caps(void)
+{
+       return OMAPFB_CAPS_MANUAL_UPDATE;
+}
+
+static void hwa742_suspend(void)
+{
+       hwa742.update_mode_before_suspend = hwa742.update_mode;
+       hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+       /* Enable sleep mode */
+       hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1);
+       clk_disable(hwa742.sys_ck);
+}
+
+static void hwa742_resume(void)
+{
+       if (clk_enable(hwa742.sys_ck) != 0)
+               pr_err("failed to enable SYS clock\n");
+       /* Disable sleep mode */
+       hwa742_write_reg(HWA742_POWER_SAVE, 0);
+       while (1) {
+               /* Loop until PLL output is stabilized */
+               if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7))
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(msecs_to_jiffies(5));
+       }
+       hwa742_set_update_mode(hwa742.update_mode_before_suspend);
+}
+
+struct lcd_ctrl hwa742_ctrl;
+
+static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, int req_vram_size)
+{
+       int r = 0, i;
+       u8 rev, conf;
+       unsigned long sysfreq;
+       int div, nd;
+
+       DBGENTER(1);
+
+       hwa742.sys_ck = clk_get(0, "bclk");
+       if (IS_ERR(hwa742.sys_ck)) {
+               pr_err("can't get SYS clock\n");
+               return PTR_ERR(hwa742.sys_ck);
+       }
+
+       if ((r = clk_enable(hwa742.sys_ck)) != 0) {
+               pr_err("can't enable SYS clock\n");
+               clk_put(hwa742.sys_ck);
+               return r;
+       }
+
+       BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
+
+       hwa742.fbdev = fbdev;
+       hwa742.extif = fbdev->ext_if;
+       hwa742.int_ctrl = fbdev->int_ctrl;
+
+       spin_lock_init(&hwa742.req_lock);
+
+       if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram_size)) < 0)
+               goto err1;
+
+       if ((r = hwa742.extif->init()) < 0)
+               goto err2;
+
+       hwa742_ctrl.get_vram_layout = hwa742.int_ctrl->get_vram_layout;
+       hwa742_ctrl.mmap = hwa742.int_ctrl->mmap;
+
+       sysfreq = clk_get_rate(hwa742.sys_ck);
+       if ((r = calc_extif_timings(sysfreq)) < 0)
+               goto err3;
+       hwa742.extif->set_timings(&hwa742.reg_timings);
+
+       div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1;
+
+       nd = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1;
+
+       if ((r = calc_extif_timings(sysfreq / div * nd)) < 0)
+               goto err3;
+       hwa742.extif->set_timings(&hwa742.reg_timings);
+
+       rev = hwa742_read_reg(HWA742_REV_CODE_REG);
+       if ((rev & 0xfc) != 0x80) {
+               pr_err("invalid revision %02x\n", rev);
+               r = -ENODEV;
+               goto err3;
+       }
+
+       conf = hwa742_read_reg(HWA742_CONFIG_REG);
+       pr_info(MODULE_NAME ": Epson HWA742 LCD controller rev. %d "
+                       "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+
+       if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) {
+               pr_err("controller not initialized by the bootloader\n");
+               r = -ENODEV;
+               goto err2;
+       }
+
+       hwa742.max_transmit_size = hwa742.extif->max_transmit_size;
+
+       hwa742.update_mode = OMAPFB_UPDATE_DISABLED;
+
+       hwa742.auto_update_window.x = 0;
+       hwa742.auto_update_window.y = 0;
+       hwa742.auto_update_window.width = fbdev->panel->x_res;
+       hwa742.auto_update_window.height = fbdev->panel->y_res;
+       hwa742.auto_update_window.format = 0;
+
+       init_timer(&hwa742.auto_update_timer);
+       hwa742.auto_update_timer.function = hwa742_update_window_auto;
+       hwa742.auto_update_timer.data = 0;
+
+       hwa742.prev_color_mode = -1;
+       hwa742.prev_flags = 0;
+
+       hwa742.fbdev = fbdev;
+
+       INIT_LIST_HEAD(&hwa742.free_req_list);
+       INIT_LIST_HEAD(&hwa742.pending_req_list);
+       for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++)
+               list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list);
+       BUG_ON(i <= IRQ_REQ_POOL_SIZE);
+       sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE);
+
+       return 0;
+err3:
+       hwa742.extif->cleanup();
+err2:
+       hwa742.int_ctrl->cleanup();
+err1:
+       clk_disable(hwa742.sys_ck);
+       clk_put(hwa742.sys_ck);
+       return r;
+}
+
+static void hwa742_cleanup(void)
+{
+       hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+       hwa742.extif->cleanup();
+       hwa742.int_ctrl->cleanup();
+       clk_disable(hwa742.sys_ck);
+       clk_put(hwa742.sys_ck);
+}
+
+struct lcd_ctrl hwa742_ctrl = {
+       .name                   = "hwa742",
+       .init                   = hwa742_init,
+       .cleanup                = hwa742_cleanup,
+       .get_caps               = hwa742_get_caps,
+       .set_update_mode        = hwa742_set_update_mode,
+       .get_update_mode        = hwa742_get_update_mode,
+       .setup_plane            = hwa742_setup_plane,
+       .enable_plane           = hwa742_enable_plane,
+       .update_window          = hwa742_update_window_async,
+       .sync                   = hwa742_sync,
+       .suspend                = hwa742_suspend,
+       .resume                 = hwa742_resume,
+};
+
diff --git a/drivers/video/omap/hwa742.h b/drivers/video/omap/hwa742.h
new file mode 100644 (file)
index 0000000..7bbe63b
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __HWA742_H
+#define __HWA742_H
+
+#include <linux/fb.h>
+
+#include <asm/arch/omapfb.h>
+
+#define HWA742_EVENT_READY     1
+#define HWA742_EVENT_DISABLED  2
+
+struct hwa742_notifier_block {
+       struct notifier_block   nb;
+       void                    *data;
+};
+
+typedef int (*hwa742_notifier_callback_t)(struct hwa742_notifier_block *,
+                                          unsigned long event,
+                                          struct omapfb_device *fbdev);
+
+extern void hwa742_read_id(int *rev_code, int *config);
+extern int hwa742_register_client(struct hwa742_notifier_block *hwa742_nb,
+                                  hwa742_notifier_callback_t callback,
+                                  void *callback_data);
+extern int hwa742_unregister_client(struct hwa742_notifier_block *hwa742_nb);
+extern int hwa742_update_window_async(struct omapfb_update_window *win,
+                                       void (*complete_callback)(void *arg),
+                                       void *complete_callback_data);
+
+#endif
index 1021739b342984dc05197105a3ac037b6a191573..128ba247c4a981e84001abe50f1e49a566502acb 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/arch/mux.h>
 #include <asm/arch/omapfb.h>
@@ -131,3 +132,52 @@ struct lcd_panel h2_panel = {
        .get_caps       = h2_panel_get_caps,
 };
 
+static int h2_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&h2_panel);
+       return 0;
+}
+
+static int h2_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int h2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int h2_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver h2_panel_driver = {
+       .probe          = h2_panel_probe,
+       .remove         = h2_panel_remove,
+       .suspend        = h2_panel_suspend,
+       .resume         = h2_panel_resume,
+       .driver         = {
+               .name   = "lcd_h2",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h2_panel_drv_init(void)
+{
+       return platform_driver_register(&h2_panel_driver);
+}
+
+static void h2_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h2_panel_driver);
+}
+
+module_init(h2_panel_drv_init);
+module_exit(h2_panel_drv_cleanup);
+
index f6e8e62020d1ed9ab3e4f14954c1dee0bd029e1c..21c9e3ee8bb2c3a0a3588efd63c13a21b999593d 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/arch/gpio.h>
 #include <asm/arch/tps65010.h>
@@ -110,3 +111,52 @@ struct lcd_panel h3_panel = {
        .get_caps       = h3_panel_get_caps,
 };
 
+static int h3_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&h3_panel);
+       return 0;
+}
+
+static int h3_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int h3_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver h3_panel_driver = {
+       .probe          = h3_panel_probe,
+       .remove         = h3_panel_remove,
+       .suspend        = h3_panel_suspend,
+       .resume         = h3_panel_resume,
+       .driver         = {
+               .name   = "lcd_h3",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h3_panel_drv_init(void)
+{
+       return platform_driver_register(&h3_panel_driver);
+}
+
+static void h3_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h3_panel_driver);
+}
+
+module_init(h3_panel_drv_init);
+module_exit(h3_panel_drv_cleanup);
+
index 48172477dba7e657f7a430236b9ca46d64402f31..ab7782a2fac71ac40c3f968ab6ffd7648151438e 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/arch/omapfb.h>
 
@@ -84,3 +85,52 @@ struct lcd_panel h4_panel = {
        .get_caps       = h4_panel_get_caps,
 };
 
+static int h4_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&h4_panel);
+       return 0;
+}
+
+static int h4_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int h4_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver h4_panel_driver = {
+       .probe          = h4_panel_probe,
+       .remove         = h4_panel_remove,
+       .suspend        = h4_panel_suspend,
+       .resume         = h4_panel_resume,
+       .driver         = {
+               .name   = "lcd_h4",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h4_panel_drv_init(void)
+{
+       return platform_driver_register(&h4_panel_driver);
+}
+
+static void h4_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h4_panel_driver);
+}
+
+module_init(h4_panel_drv_init);
+module_exit(h4_panel_drv_cleanup);
+
index d6ae2f6533c39baf8a5c352c15dceed900297c77..31988d1b574221b0a94d5ee2d4fc4b56cce6cad7 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 
@@ -93,3 +94,52 @@ struct lcd_panel innovator1510_panel = {
        .get_caps       = innovator1510_panel_get_caps,
 };
 
+static int innovator1510_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&innovator1510_panel);
+       return 0;
+}
+
+static int innovator1510_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int innovator1510_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int innovator1510_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver innovator1510_panel_driver = {
+       .probe          = innovator1510_panel_probe,
+       .remove         = innovator1510_panel_remove,
+       .suspend        = innovator1510_panel_suspend,
+       .resume         = innovator1510_panel_resume,
+       .driver         = {
+               .name   = "lcd_inn1510",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int innovator1510_panel_drv_init(void)
+{
+       return platform_driver_register(&innovator1510_panel_driver);
+}
+
+static void innovator1510_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&innovator1510_panel_driver);
+}
+
+module_init(innovator1510_panel_drv_init);
+module_exit(innovator1510_panel_drv_cleanup);
+
index bf71485e4274227f73572923cc0d6ba3c3cc2d1e..9a03fce0effcfe065cf787c709d4e6898023efd1 100644 (file)
@@ -121,3 +121,52 @@ struct lcd_panel innovator1610_panel = {
        .get_caps       = innovator1610_panel_get_caps,
 };
 
+static int innovator1610_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&innovator1610_panel);
+       return 0;
+}
+
+static int innovator1610_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int innovator1610_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int innovator1610_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver innovator1610_panel_driver = {
+       .probe          = innovator1610_panel_probe,
+       .remove         = innovator1610_panel_remove,
+       .suspend        = innovator1610_panel_suspend,
+       .resume         = innovator1610_panel_resume,
+       .driver         = {
+               .name   = "lcd_inn1610",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int innovator1610_panel_drv_init(void)
+{
+       return platform_driver_register(&innovator1610_panel_driver);
+}
+
+static void innovator1610_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&innovator1610_panel_driver);
+}
+
+module_init(innovator1610_panel_drv_init);
+module_exit(innovator1610_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_lph8923.c b/drivers/video/omap/lcd_lph8923.c
new file mode 100644 (file)
index 0000000..ff33116
--- /dev/null
@@ -0,0 +1,483 @@
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/lcd_lph8923.h>
+
+#include <linux/spi/spi.h>
+#include <asm/arch/mcspi.h>
+
+#include "../../cbus/tahvo.h"
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
+#define LPH8923_MODULE_NAME            "lcd_lph8923"
+
+#define LPH8923_VER_BUGGY              1
+#define LPH8923_VER_NON_BUGGY          3
+
+struct {
+       int             enabled;
+       int             version;
+
+       u8              display_id[3];
+       unsigned int    saved_bklight_level;
+       unsigned long   hw_guard_end;           /* next value of jiffies
+                                                  when we can issue the
+                                                  next sleep in/out command */
+       unsigned long   hw_guard_wait;          /* max guard time in jiffies */
+       struct omapfb_device *fbdev;
+       struct spi_device *spi;
+} lph8923;
+
+#define LPH8923_CMD_READ_DISP_ID       0x04
+#define LPH8923_CMD_READ_RED           0x06
+#define LPH8923_CMD_READ_GREEN         0x07
+#define LPH8923_CMD_READ_BLUE          0x08
+#define LPH8923_CMD_READ_DISP_STATUS   0x09
+#define LPH8923_CMD_SLEEP_IN           0x10
+#define LPH8923_CMD_SLEEP_OUT          0x11
+#define LPH8923_CMD_DISP_OFF           0x28
+#define LPH8923_CMD_DISP_ON            0x29
+
+static struct lcd_panel lph8923_panel;
+
+#define LPH8923_SPEED_HZ       12000000
+
+static int lph8923_spi_probe(struct spi_device *spi)
+{
+       DBGENTER(1);
+
+       spi->dev.power.power_state = PMSG_ON;
+       spi->mode = SPI_MODE_0;
+       spi->bits_per_word = 9;
+       spi_setup(spi);
+
+       DBGPRINT(1, "spi %p\n", spi);
+       lph8923.spi = spi;
+
+       omapfb_register_panel(&lph8923_panel);
+
+       return 0;
+}
+
+static int lph8923_spi_remove(struct spi_device *spi)
+{
+       DBGENTER(1);
+
+       lph8923.spi = NULL;
+
+       return 0;
+}
+
+static struct spi_driver lph8923_spi_driver = {
+       .driver = {
+               .name   = LPH8923_MODULE_NAME,
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = lph8923_spi_probe,
+       .remove = __devexit_p(lph8923_spi_remove),
+};
+
+static int lph8923_drv_init(void)
+{
+       spi_register_driver(&lph8923_spi_driver);
+
+       return 0;
+}
+module_init(lph8923_drv_init);
+
+static void lph8923_drv_cleanup(void)
+{
+       spi_unregister_driver(&lph8923_spi_driver);
+}
+module_exit(lph8923_drv_cleanup);
+
+static void set_spi_data_width(int width)
+{
+       if (lph8923.spi->bits_per_word != width) {
+               lph8923.spi->bits_per_word = width;
+               spi_setup(lph8923.spi);
+       }
+}
+
+static void lph8923_read(int cmd, u8 *buf, int len)
+{
+       struct spi_message      m;
+       struct spi_transfer     t;
+       u16                     w;
+
+       BUG_ON(lph8923.spi == NULL);
+
+       spi_message_init(&m);
+       m.spi = lph8923.spi;
+
+       if (len > 1) {
+               cmd <<= 1;
+               set_spi_data_width(10);
+       } else
+               set_spi_data_width(9);
+
+       w               = cmd;
+       t.cs_change     = len ? 1 : 0;
+       t.tx_buf        = &w;
+       t.rx_buf        = NULL;
+       t.len           = 2;
+
+       spi_message_add_tail(&t, &m);
+
+       spi_sync(m.spi, &m);
+
+       if (!len)
+               return;
+
+       spi_message_init(&m);
+       m.spi = lph8923.spi;
+
+       t.cs_change     = 0;
+       t.tx_buf        = NULL;
+       t.rx_buf        = buf;
+       t.len           = len;
+
+       set_spi_data_width(8);
+
+       spi_message_add_tail(&t, &m);
+
+       spi_sync(m.spi, &m);
+}
+
+static void lph8923_write(int cmd, const u8 *buf, int len)
+{
+       struct spi_message      m;
+       struct spi_transfer     t;
+       u16                     w;
+       int                     i;
+
+       BUG_ON(lph8923.spi == NULL);
+
+       spi_message_init(&m);
+       m.spi = lph8923.spi;
+
+       if (len > 1) {
+               cmd <<= 1;
+               set_spi_data_width(10);
+       } else {
+               set_spi_data_width(9);
+       }
+
+       t.cs_change     = 0;
+       w               = cmd;
+       t.tx_buf        = &w;
+       t.rx_buf        = NULL;
+       t.len           = 2;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(m.spi, &m);
+
+       if (!len)
+               return;
+
+       set_spi_data_width(9);
+
+       t.tx_buf = &w;
+       for (i = 0; i < len; i++) {
+               u16 w;
+
+               spi_message_init(&m);
+               m.spi = lph8923.spi;
+               spi_message_add_tail(&t, &m);
+               w = buf[i] | (1 << 8);
+               spi_sync(m.spi, &m);
+       }
+}
+
+static inline void lph8923_cmd(int cmd)
+{
+       lph8923_write(cmd, NULL, 0);
+}
+
+struct cmd_data {
+       u8 cmd;
+       u8 len;
+       const u8 *data;
+} __attribute__ ((packed));;
+
+static const struct cmd_data init_cmds_buggy_lph8923[] = {
+       { 0xb0, 1, "\x08" },
+       { 0xb1, 2, "\x0b\x1c" },
+       { 0xb2, 4, "\x00\x00\x00\x00" },
+       { 0xb3, 4, "\x00\x00\x00\x00" },
+       { 0xb4, 1, "\x87" },
+       { 0xb5, 4, "\x37\x07\x37\x07" },
+       { 0xb6, 2, "\x64\x24" },
+       { 0xb7, 1, "\x90" },
+       { 0xb8, 3, "\x10\x11\x20" },
+       { 0xb9, 2, "\x31\x02" },
+       { 0xba, 3, "\x04\xa3\x9d" },
+       { 0xbb, 4, "\x15\xb2\x8c\x00" },
+       { 0xc2, 3, "\x02\x00\x00" },
+};
+
+static const struct cmd_data init_cmds_non_buggy_lph8923[] = {
+       { 0xc2, 3, "\x02\x00\x00" },
+};
+
+static inline void lph8923_set_16bit_mode(void)
+{
+       lph8923_write(0x3a, "\x50", 1);
+}
+
+static void lph8923_send_init_string(void)
+{
+       int c;
+       const struct cmd_data *cd;
+
+       switch (lph8923.version) {
+       case LPH8923_VER_BUGGY:
+               c = sizeof(init_cmds_buggy_lph8923)/sizeof(init_cmds_buggy_lph8923[0]);
+               cd = init_cmds_buggy_lph8923;
+               break;
+       case LPH8923_VER_NON_BUGGY:
+       default:
+               c = sizeof(init_cmds_non_buggy_lph8923)/sizeof(init_cmds_non_buggy_lph8923[0]);
+               cd = init_cmds_non_buggy_lph8923;
+               break;
+       }
+       while (c--) {
+               lph8923_write(cd->cmd, cd->data, cd->len);
+               cd++;
+       }
+       lph8923_set_16bit_mode();
+}
+
+static void hw_guard_start(int guard_msec)
+{
+       lph8923.hw_guard_wait = msecs_to_jiffies(guard_msec);
+       lph8923.hw_guard_end = jiffies + lph8923.hw_guard_wait;
+}
+
+static void hw_guard_wait(void)
+{
+       unsigned long wait = lph8923.hw_guard_end - jiffies;
+
+       if ((long)wait > 0 && wait <= lph8923.hw_guard_wait) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(wait);
+       }
+}
+
+static void lph8923_set_sleep_mode(int on)
+{
+       int cmd, sleep_time = 5;
+
+       if (on)
+               cmd = LPH8923_CMD_SLEEP_IN;
+       else
+               cmd = LPH8923_CMD_SLEEP_OUT;
+       hw_guard_wait();
+       lph8923_cmd(cmd);
+       hw_guard_start(120);
+       /* When we enable the panel, it seems we _have_ to sleep
+        * 120 ms before sending the init string */
+       if (!on)
+               sleep_time = 120;
+       msleep(sleep_time);
+}
+
+static void lph8923_set_display_state(int enabled)
+{
+       int cmd = enabled ? LPH8923_CMD_DISP_ON : LPH8923_CMD_DISP_OFF;
+
+       lph8923_cmd(cmd);
+}
+
+static void lph8923_detect(void)
+{
+       lph8923_read(LPH8923_CMD_READ_DISP_ID, lph8923.display_id, 3);
+       printk(KERN_INFO "Moscow display id: %02x%02x%02x\n",
+               lph8923.display_id[0], lph8923.display_id[1],
+               lph8923.display_id[2]);
+
+       if (lph8923.display_id[0] == 0x45) {
+               lph8923.version = LPH8923_VER_NON_BUGGY;
+               printk(KERN_INFO "Non-buggy Moscow detected\n");
+               return;
+       } else {
+               lph8923.version = LPH8923_VER_BUGGY;
+               printk(KERN_INFO "Buggy Moscow detected\n");
+       }
+}
+
+static int lph8923_enabled(void)
+{
+       u32 disp_status;
+       int enabled;
+
+       lph8923_read(LPH8923_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+       disp_status = __be32_to_cpu(disp_status);
+       enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+       DBGPRINT(1, ": panel %senabled by bootloader (status 0x%04x)\n",
+               enabled ? "" : "not ", disp_status);
+       return enabled;
+}
+
+static int lph8923_panel_init(struct omapfb_device *fbdev)
+{
+       lph8923.fbdev = fbdev;
+
+       lph8923.enabled = 1;
+       lph8923_detect();
+       if (lph8923.version == LPH8923_VER_NON_BUGGY)
+               lph8923.enabled = lph8923_enabled();
+       else
+               /* We can't be sure, but assume the bootloader
+               * enabled it already */
+               lph8923.enabled = 1;
+
+       return 0;
+}
+
+static void lph8923_panel_cleanup(void)
+{
+}
+
+static int lph8923_panel_set_bklight_level(unsigned int level)
+{
+       if (level > 0xf)
+               return -EINVAL;
+       if (!lph8923.enabled) {
+               lph8923.saved_bklight_level = level;
+               return 0;
+       }
+       level = level * tahvo_get_max_backlight_level() / 0x0f;
+       tahvo_set_backlight_level(level);
+
+       return 0;
+}
+
+static unsigned int lph8923_panel_get_bklight_level(void)
+{
+       return tahvo_get_backlight_level() * 0x0f /
+               tahvo_get_max_backlight_level();
+}
+
+static unsigned int lph8923_panel_get_bklight_max(void)
+{
+       return 0x0f;
+}
+
+static int lph8923_panel_enable(void)
+{
+       if (lph8923.enabled)
+               return 0;
+
+       lph8923_set_sleep_mode(0);
+       lph8923.enabled = 1;
+       lph8923_send_init_string();
+       lph8923_set_display_state(1);
+       lph8923_panel_set_bklight_level(lph8923.saved_bklight_level);
+
+       return 0;
+}
+
+static void lph8923_panel_disable(void)
+{
+       if (!lph8923.enabled)
+               return;
+       lph8923.saved_bklight_level = lph8923_panel_get_bklight_level();
+       lph8923_panel_set_bklight_level(0);
+       lph8923_set_display_state(0);
+       lph8923_set_sleep_mode(1);
+       lph8923.enabled = 0;
+}
+
+static unsigned long lph8923_panel_get_caps(void)
+{
+       return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+static u16 read_first_pixel(void)
+{
+       u8 b;
+       u16 pixel;
+
+       lph8923_read(LPH8923_CMD_READ_RED, &b, 1);
+       pixel = (b >> 1) << 11;
+       lph8923_read(LPH8923_CMD_READ_GREEN, &b, 1);
+       pixel |= b << 5;
+       lph8923_read(LPH8923_CMD_READ_BLUE, &b, 1);
+       pixel |= (b >> 1);
+
+       return pixel;
+}
+
+static int lph8923_panel_test(int test_num)
+{
+       static const u16 test_values[4] = {
+               0x0000, 0xffff, 0xaaaa, 0x5555,
+       };
+       int i;
+
+       if (test_num != LCD_LPH8923_TEST_RGB_LINES)
+               return LCD_LPH8923_TEST_INVALID;
+
+       for (i = 0; i < ARRAY_SIZE(test_values); i++) {
+               int delay;
+               unsigned long tmo;
+
+               omapfb_write_first_pixel(lph8923.fbdev, test_values[i]);
+               tmo = jiffies + msecs_to_jiffies(100);
+               delay = msecs_to_jiffies(25);
+               while (1) {
+                       u16 pixel;
+
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(delay);
+                       pixel = read_first_pixel();
+                       if (pixel == test_values[i])
+                               break;
+                       if (time_after(jiffies, tmo)) {
+                               printk(KERN_ERR "Moscow RGB I/F test failed: "
+                                      "expecting %04x, got %04x\n",
+                                      test_values[i], pixel);
+                               return LCD_LPH8923_TEST_FAILED;
+                       }
+                       delay = msecs_to_jiffies(10);
+               }
+       }
+
+       return 0;
+}
+
+static struct lcd_panel lph8923_panel = {
+       .name           = "lph8923",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 800,
+       .y_res          = 480,
+       .pixel_clock    = 21940,
+       .hsw            = 50,
+       .hfp            = 20,
+       .hbp            = 15,
+       .vsw            = 2,
+       .vfp            = 1,
+       .vbp            = 3,
+
+       .init           = lph8923_panel_init,
+       .cleanup        = lph8923_panel_cleanup,
+       .enable         = lph8923_panel_enable,
+       .disable        = lph8923_panel_disable,
+       .get_caps       = lph8923_panel_get_caps,
+       .set_bklight_level= lph8923_panel_set_bklight_level,
+       .get_bklight_level= lph8923_panel_get_bklight_level,
+       .get_bklight_max= lph8923_panel_get_bklight_max,
+       .run_test       = lph8923_panel_test,
+};
index 54808d60feaae9f33f6882464b90609bb3f9c46e..5751ec6d3258ff368a5fc9526025f3292900837c 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
@@ -113,3 +114,52 @@ struct lcd_panel osk_panel = {
        .get_caps       = osk_panel_get_caps,
 };
 
+static int osk_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&osk_panel);
+       return 0;
+}
+
+static int osk_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int osk_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver osk_panel_driver = {
+       .probe          = osk_panel_probe,
+       .remove         = osk_panel_remove,
+       .suspend        = osk_panel_suspend,
+       .resume         = osk_panel_resume,
+       .driver         = {
+               .name   = "lcd_osk",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int osk_panel_drv_init(void)
+{
+       return platform_driver_register(&osk_panel_driver);
+}
+
+static void osk_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&osk_panel_driver);
+}
+
+module_init(osk_panel_drv_init);
+module_exit(osk_panel_drv_cleanup);
+
index 5a3e2dbf79089f24f63dd7b9c9a36b8396c52d29..3f03dca42a6ce4c49d0425a726dd004484fcec75 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
 
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
@@ -305,3 +306,52 @@ struct lcd_panel p2_panel = {
        .get_caps       = p2_panel_get_caps,
 };
 
+static int p2_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&p2_panel);
+       return 0;
+}
+
+static int p2_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int p2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int p2_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver p2_panel_driver = {
+       .probe          = p2_panel_probe,
+       .remove         = p2_panel_remove,
+       .suspend        = p2_panel_suspend,
+       .resume         = p2_panel_resume,
+       .driver         = {
+               .name   = "lcd_p2",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int p2_panel_drv_init(void)
+{
+       return platform_driver_register(&p2_panel_driver);
+}
+
+static void p2_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&p2_panel_driver);
+}
+
+module_init(p2_panel_drv_init);
+module_exit(p2_panel_drv_cleanup);
+
index 0f84b631b359031fa60122b1774af80188423903..5cf3851f4e20b2a713ec9b90ddc83719270de021 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 
@@ -89,3 +90,52 @@ struct lcd_panel palmte_panel = {
        .get_caps       = palmte_panel_get_caps,
 };
 
+static int palmte_panel_probe(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       omapfb_register_panel(&palmte_panel);
+       return 0;
+}
+
+static int palmte_panel_remove(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+static int palmte_panel_resume(struct platform_device *pdev)
+{
+       DBGENTER(1);
+       return 0;
+}
+
+struct platform_driver palmte_panel_driver = {
+       .probe          = palmte_panel_probe,
+       .remove         = palmte_panel_remove,
+       .suspend        = palmte_panel_suspend,
+       .resume         = palmte_panel_resume,
+       .driver         = {
+               .name   = "lcd_palmte",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int palmte_panel_drv_init(void)
+{
+       return platform_driver_register(&palmte_panel_driver);
+}
+
+static void palmte_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&palmte_panel_driver);
+}
+
+module_init(palmte_panel_drv_init);
+module_exit(palmte_panel_drv_cleanup);
+
index 25c376dc7ea04c30f63bb6188079f1c530217b07..bfe94784cbf6952eb497e21ee1bbd0ae3dd0b428 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mm.h>
 #include <linux/fb.h>
 #include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
 #include <linux/clk.h>
 
 #include <asm/arch/dma.h>
@@ -37,7 +38,7 @@
 
 #include <asm/mach-types.h>
 
-/* #define OMAPFB_DBG 2 */
+/* #define OMAPFB_DBG 1 */
 
 #include "debug.h"
 
@@ -87,13 +88,17 @@ enum lcdc_load_mode {
 
 static struct omap_lcd_controller {
        enum omapfb_update_mode update_mode;
+       int                     ext_mode;
 
        unsigned long           frame_offset;
        int                     screen_width;
+       int                     xres;
+       int                     yres;
 
        enum omapfb_color_format        color_mode;
        int                     bpp;
-       int                     palette_org;
+       void                    *palette_virt;
+       dma_addr_t              palette_phys;
        int                     palette_code;
        int                     palette_size;
 
@@ -103,6 +108,10 @@ static struct omap_lcd_controller {
        struct clk              *lcd_ck;
        struct omapfb_device    *fbdev;
 
+       void                    (*dma_callback)(void *data);
+       void                    *dma_callback_data;
+
+       int                     fbmem_allocated;
        dma_addr_t              vram_phys;
        void                    *vram_virt;
        unsigned long           vram_size;
@@ -207,18 +216,21 @@ static void setup_lcd_dma(void)
                OMAP_DMA_DATA_TYPE_S32,
        };
        struct fb_var_screeninfo *var = &omap_lcdc.fbdev->fb_info->var;
-       struct lcd_panel *panel = omap_lcdc.fbdev->panel;
        unsigned long   src;
        int             esize, xelem, yelem;
 
-       src = omap_lcdc.vram_phys + PAGE_ALIGN(MAX_PALETTE_SIZE) +
-               omap_lcdc.frame_offset;
+       src = omap_lcdc.vram_phys + omap_lcdc.frame_offset;
 
        switch (var->rotate) {
        case 0:
-               esize = omap_lcdc.fbdev->mirror || (src & 3) ? 2 : 4;
-               xelem = panel->x_res * omap_lcdc.bpp / 8 / esize;
-               yelem = panel->y_res;
+               if (omap_lcdc.fbdev->mirror || (src & 3) ||
+                   omap_lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
+                   (omap_lcdc.xres & 1))
+                       esize = 2;
+               else
+                       esize = 4;
+               xelem = omap_lcdc.xres * omap_lcdc.bpp / 8 / esize;
+               yelem = omap_lcdc.yres;
                break;
        case 90:
        case 180:
@@ -227,21 +239,27 @@ static void setup_lcd_dma(void)
                        BUG();
                }
                esize = 2;
-               xelem = panel->y_res * omap_lcdc.bpp / 16;
-               yelem = panel->x_res;
+               xelem = omap_lcdc.yres * omap_lcdc.bpp / 16;
+               yelem = omap_lcdc.xres;
                break;
        default:
                BUG();
                return;
        }
-       DBGPRINT(1, "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
+       DBGPRINT(2, "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
                 src, esize, xelem, yelem);
        omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
-       omap_set_lcd_dma_single_transfer(0);
        if (!cpu_is_omap15xx()) {
+               int bpp = omap_lcdc.bpp;
+
+               /* YUV support is only for external mode when we have the
+                * YUV window embedded in a 16bpp frame buffer.
+                */
+               if (omap_lcdc.color_mode == OMAPFB_COLOR_YUV420)
+                       bpp = 16;
                /* Set virtual xres elem size */
                omap_set_lcd_dma_b1_vxres(
-                       omap_lcdc.screen_width * omap_lcdc.bpp / 8 / esize);
+                       omap_lcdc.screen_width * bpp / 8 / esize);
                /* Setup transformations */
                omap_set_lcd_dma_b1_rotation(var->rotate);
                omap_set_lcd_dma_b1_mirror(omap_lcdc.fbdev->mirror);
@@ -305,7 +323,7 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
        struct lcd_panel *panel = omap_lcdc.fbdev->panel;
        int rot_x, rot_y;
 
-       DBGENTER(1);
+       DBGENTER(2);
 
        if (var->rotate == 0) {
                rot_x = panel->x_res;
@@ -315,7 +333,7 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
                rot_y = panel->x_res;
        }
        if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
-           width != rot_x || height != rot_y) {
+           width > rot_x || height > rot_y) {
                DBGPRINT(1, "invalid plane params plane %d pos_x %d "
                        "pos_y %d w %d h %d\n", plane, pos_x, pos_y,
                        width, height);
@@ -323,6 +341,8 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
        }
 
        omap_lcdc.frame_offset = offset;
+       omap_lcdc.xres = width;
+       omap_lcdc.yres = height;
        omap_lcdc.screen_width = screen_width;
        omap_lcdc.color_mode = color_mode;
 
@@ -337,6 +357,18 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
                omap_lcdc.palette_code = 0x4000;
                omap_lcdc.palette_size = 32;
                break;
+       case OMAPFB_COLOR_YUV420:
+               if (omap_lcdc.ext_mode) {
+                       omap_lcdc.bpp = 12;
+                       break;
+               }
+               /* fallthrough */
+       case OMAPFB_COLOR_YUV422:
+               if (omap_lcdc.ext_mode) {
+                       omap_lcdc.bpp = 16;
+                       break;
+               }
+               /* fallthrough */
        default:
                /* FIXME: other BPPs.
                 * bpp1: code  0,     size 256
@@ -348,8 +380,10 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
                return -1;
        }
 
-       omap_lcdc.palette_org = PAGE_ALIGN(MAX_PALETTE_SIZE) -
-                                       omap_lcdc.palette_size;
+       if (omap_lcdc.ext_mode) {
+               setup_lcd_dma();
+               return 0;
+       }
 
        if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
                disable_controller();
@@ -358,14 +392,17 @@ static int omap_lcdc_setup_plane(int plane, int channel_out,
                enable_controller();
        }
 
-       DBGLEAVE(1);
+       DBGLEAVE(2);
 
        return 0;
 }
 
 static int omap_lcdc_enable_plane(int plane, int enable)
 {
-       if (plane != 0 || enable != 1)
+       DBGPRINT(2, "plane %d enable %d update_mode %d ext_mode %d\n",
+               plane, enable, omap_lcdc.update_mode,
+               omap_lcdc.ext_mode);
+       if (plane != OMAPFB_PLANE_GFX)
                return -EINVAL;
 
        return 0;
@@ -381,12 +418,12 @@ static void load_palette(void)
 
        DBGENTER(1);
 
-       palette = (u16 *)((u8 *)omap_lcdc.vram_virt + omap_lcdc.palette_org);
+       palette = (u16 *)omap_lcdc.palette_virt;
 
        *(u16 *)palette &= 0x0fff;
        *(u16 *)palette |= omap_lcdc.palette_code;
 
-       omap_set_lcd_dma_b1(omap_lcdc.vram_phys + omap_lcdc.palette_org,
+       omap_set_lcd_dma_b1(omap_lcdc.palette_phys,
                omap_lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
 
        omap_set_lcd_dma_single_transfer(1);
@@ -403,16 +440,45 @@ static void load_palette(void)
        disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
        omap_stop_lcd_dma();
 
+       omap_set_lcd_dma_single_transfer(omap_lcdc.ext_mode);
+
        DBGLEAVE(1);
 }
 
+/* Used only in internal controller mode */
+static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
+                              u16 transp, int update_hw_pal)
+{
+       u16 *palette;
+
+       if (omap_lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
+               return -EINVAL;
+
+       palette = (u16 *)omap_lcdc.palette_virt;
+
+       palette[regno] &= ~0x0fff;
+       palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
+                          (blue >> 12);
+
+       if (update_hw_pal) {
+               disable_controller();
+               omap_stop_lcd_dma();
+               load_palette();
+               setup_lcd_dma();
+               set_load_mode(OMAP_LCDC_LOAD_FRAME);
+               enable_controller();
+       }
+
+       return 0;
+}
+
 static void calc_ck_div(int is_tft, int pck, int *pck_div)
 {
        unsigned long lck;
 
        pck = max(1, pck);
        lck = clk_get_rate(omap_lcdc.lcd_ck);
-       *pck_div = lck / pck;
+       *pck_div = (lck + pck - 1) / pck;
        if (is_tft)
                *pck_div = max(2, *pck_div);
        else
@@ -486,7 +552,9 @@ static void inline setup_regs(void)
 }
 
 /* Configure the LCD controller, download the color palette and start a looped
- * DMA transfer of the frame image data. */
+ * DMA transfer of the frame image data. Called only in internal
+ * controller mode.
+ */
 static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
 {
        int r = 0;
@@ -527,6 +595,7 @@ static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
        return omap_lcdc.update_mode;
 }
 
+/* PM code called only in internal controller mode */
 static void omap_lcdc_suspend(void)
 {
        if (omap_lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
@@ -547,12 +616,184 @@ static void omap_lcdc_resume(void)
        }
 }
 
+static unsigned long omap_lcdc_get_caps(void)
+{
+       return 0;
+}
+
 static void omap_lcdc_get_vram_layout(unsigned long *size, void **virt,
                                        dma_addr_t *phys)
 {
-       *size = omap_lcdc.vram_size - PAGE_ALIGN(MAX_PALETTE_SIZE);
-       *virt = (u8 *)omap_lcdc.vram_virt + PAGE_ALIGN(MAX_PALETTE_SIZE);
-       *phys = omap_lcdc.vram_phys + PAGE_ALIGN(MAX_PALETTE_SIZE);
+       *size = omap_lcdc.vram_size;
+       *virt = (u8 *)omap_lcdc.vram_virt;
+       *phys = omap_lcdc.vram_phys;
+}
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
+{
+       BUG_ON(callback == NULL);
+
+       if (omap_lcdc.dma_callback)
+               return -EBUSY;
+       else {
+               omap_lcdc.dma_callback = callback;
+               omap_lcdc.dma_callback_data = data;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
+
+void omap_lcdc_free_dma_callback(void)
+{
+       omap_lcdc.dma_callback = NULL;
+}
+EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
+
+static void lcdc_dma_handler(u16 status, void *data)
+{
+       DBGENTER(2);
+       if (omap_lcdc.dma_callback)
+               omap_lcdc.dma_callback(omap_lcdc.dma_callback_data);
+}
+
+static int mmap_kern(void)
+{
+       struct vm_struct        *kvma;
+       struct vm_area_struct   vma;
+       pgprot_t                pgprot;
+       unsigned long           vaddr;
+
+       DBGENTER(1);
+
+       kvma = get_vm_area(omap_lcdc.vram_size, VM_IOREMAP);
+       if (kvma == NULL) {
+               pr_err("can't get kernel vm area\n");
+               return -ENOMEM;
+       }
+       vma.vm_mm = &init_mm;
+
+       vaddr = (unsigned long)kvma->addr;
+       vma.vm_start = vaddr;
+       vma.vm_end = vaddr + omap_lcdc.vram_size;
+
+       pgprot = pgprot_writecombine(pgprot_kernel);
+       if (io_remap_pfn_range(&vma, vaddr,
+                          omap_lcdc.vram_phys >> PAGE_SHIFT,
+                          omap_lcdc.vram_size, pgprot) < 0) {
+               pr_err("kernel mmap for FB memory failed\n");
+               return -EAGAIN;
+       }
+
+       omap_lcdc.vram_virt = (void *)vaddr;
+
+       DBGLEAVE(1);
+
+       return 0;
+}
+
+static void unmap_kern(void)
+{
+       vunmap(omap_lcdc.vram_virt);
+}
+
+static int alloc_palette_ram(void)
+{
+       omap_lcdc.palette_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
+               MAX_PALETTE_SIZE, &omap_lcdc.palette_phys, GFP_KERNEL);
+       if (omap_lcdc.palette_virt == NULL) {
+               pr_err("failed to alloc palette memory\n");
+               return -ENOMEM;
+       }
+       memset(omap_lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
+
+       return 0;
+}
+
+static void free_palette_ram(void)
+{
+       dma_free_writecombine(omap_lcdc.fbdev->dev, MAX_PALETTE_SIZE,
+                       omap_lcdc.palette_virt, omap_lcdc.palette_phys);
+}
+
+static int alloc_fbmem(int req_size)
+{
+       int frame_size;
+       struct lcd_panel *panel = omap_lcdc.fbdev->panel;
+
+       frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
+       if (req_size > frame_size)
+               frame_size = req_size;
+       omap_lcdc.vram_size = frame_size;
+       omap_lcdc.vram_virt = dma_alloc_writecombine(omap_lcdc.fbdev->dev,
+                       omap_lcdc.vram_size, &omap_lcdc.vram_phys, GFP_KERNEL);
+
+       if (omap_lcdc.vram_virt == NULL) {
+               pr_err("unable to allocate FB DMA memory\n");
+               return -ENOMEM;
+       }
+
+       memset(omap_lcdc.vram_virt, 0, omap_lcdc.vram_size);
+
+       return 0;
+}
+
+static void free_fbmem(void)
+{
+       dma_free_writecombine(omap_lcdc.fbdev->dev, omap_lcdc.vram_size,
+                             omap_lcdc.vram_virt, omap_lcdc.vram_phys);
+}
+
+static int setup_fbmem(int req_size)
+{
+       struct lcd_panel *panel = omap_lcdc.fbdev->panel;
+       struct omapfb_platform_data *conf;
+       int frame_size;
+       int r;
+
+       conf = omap_lcdc.fbdev->dev->platform_data;
+
+       if (conf->fbmem.fb_sram_size) {
+               pr_err("can't use FB SRAM in OMAP1\n");
+               return -EINVAL;
+       }
+
+       if (conf->fbmem.fb_sdram_size == 0) {
+               omap_lcdc.fbmem_allocated = 1;
+               if ((r = alloc_fbmem(req_size)) < 0)
+                       return r;
+               return 0;
+       }
+
+       frame_size = PAGE_ALIGN(panel->x_res * panel->bpp / 8 * panel->y_res);
+
+       if (conf->fbmem.fb_sdram_size < frame_size) {
+               pr_err("invalid FB memory configuration\n");
+               return -EINVAL;
+       }
+
+       if (conf->fbmem.fb_sdram_size < req_size) {
+               pr_err("%d vram was requested, but only %u is available\n",
+                       req_size, conf->fbmem.fb_sdram_size);
+       }
+
+       omap_lcdc.vram_phys = conf->fbmem.fb_sdram_start;
+       omap_lcdc.vram_size = conf->fbmem.fb_sdram_size;
+
+       if ((r = mmap_kern()) < 0)
+               return r;
+
+       DBGPRINT(1, "vram at %08x size %08lx mapped to 0x%p\n",
+                omap_lcdc.vram_phys, omap_lcdc.vram_size, omap_lcdc.vram_virt);
+
+       return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+       if (omap_lcdc.fbmem_allocated)
+               free_fbmem();
+       else
+               unmap_kern();
 }
 
 static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
@@ -562,14 +803,13 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
        u32 l;
        int rate;
        struct clk *tc_ck;
-       struct lcd_panel *panel = fbdev->panel;
-       int frame_size;
 
        DBGENTER(1);
 
        omap_lcdc.irq_mask = 0;
 
        omap_lcdc.fbdev = fbdev;
+       omap_lcdc.ext_mode = ext_mode;
 
        pr_info(MODULE_NAME ": init\n");
 
@@ -612,27 +852,29 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
                goto fail2;
        }
 
-       r = omap_request_lcd_dma(NULL, NULL);
+       r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
        if (r) {
                pr_err("unable to get LCD DMA\n");
                goto fail3;
        }
 
-       frame_size = panel->x_res * panel->bpp * panel->y_res / 8;
-       if (req_vram_size > frame_size)
-               frame_size = req_vram_size;
-       omap_lcdc.vram_size = PAGE_ALIGN(MAX_PALETTE_SIZE) + frame_size;
-       omap_lcdc.vram_virt = dma_alloc_writecombine(fbdev->dev,
-                       omap_lcdc.vram_size, &omap_lcdc.vram_phys, GFP_KERNEL);
+       omap_set_lcd_dma_single_transfer(ext_mode);
+       omap_set_lcd_dma_ext_controller(ext_mode);
+
+       if (!ext_mode)
+               if ((r = alloc_palette_ram()) < 0)
+                       goto fail4;
+
+       req_vram_size = 1024 * 1024;
+       if ((r = setup_fbmem(req_vram_size)) < 0)
+               goto fail5;
 
-       if (omap_lcdc.vram_virt == NULL) {
-               pr_err("unable to allocate fb DMA memory\n");
-               r = -ENOMEM;
-               goto fail4;
-       }
 
        DBGLEAVE(1);
        return 0;
+fail5:
+       if (!ext_mode)
+               free_palette_ram();
 fail4:
        omap_free_lcd_dma();
 fail3:
@@ -648,46 +890,15 @@ fail0:
 
 static void omap_lcdc_cleanup(void)
 {
-       dma_free_writecombine(omap_lcdc.fbdev->dev, omap_lcdc.vram_size,
-                             omap_lcdc.vram_virt, omap_lcdc.vram_phys);
+       if (!omap_lcdc.ext_mode)
+               free_palette_ram();
+       cleanup_fbmem();
        omap_free_lcd_dma();
        free_irq(OMAP_LCDC_IRQ, omap_lcdc.fbdev);
        clk_disable(omap_lcdc.lcd_ck);
        clk_put(omap_lcdc.lcd_ck);
 }
 
-static unsigned long omap_lcdc_get_caps(void)
-{
-       return 0;
-}
-
-static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
-                              u16 transp, int update_hw_pal)
-{
-       u16 *palette;
-
-       if (omap_lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
-               return -EINVAL;
-
-       palette = (u16 *)((u8*)omap_lcdc.vram_virt +
-                       PAGE_ALIGN(MAX_PALETTE_SIZE) - omap_lcdc.palette_size);
-
-       palette[regno] &= ~0x0fff;
-       palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
-                          (blue >> 12);
-
-       if (update_hw_pal) {
-               disable_controller();
-               omap_stop_lcd_dma();
-               load_palette();
-               setup_lcd_dma();
-               set_load_mode(OMAP_LCDC_LOAD_FRAME);
-               enable_controller();
-       }
-
-       return 0;
-}
-
 struct lcd_ctrl omap1_int_ctrl = {
        .name                   = "internal",
        .init                   = omap_lcdc_init,
diff --git a/drivers/video/omap/lcdc.h b/drivers/video/omap/lcdc.h
new file mode 100644 (file)
index 0000000..adb731e
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef LCDC_H
+#define LCDC_H
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
+void omap_lcdc_free_dma_callback(void);
+
+#endif
index fd4b5c7b8edf920bfb3ee80c49bdf0a775acb80e..fac072188eb0a50385f8c58da47f47bb78c880af 100644 (file)
@@ -80,64 +80,20 @@ static struct caps_table_struct {
  * LCD panel
  * ---------------------------------------------------------------------------
  */
-extern struct lcd_panel h4_panel;
-extern struct lcd_panel h3_panel;
-extern struct lcd_panel h2_panel;
-extern struct lcd_panel p2_panel;
-extern struct lcd_panel osk_panel;
-extern struct lcd_panel palmte_panel;
-extern struct lcd_panel innovator1610_panel;
-extern struct lcd_panel innovator1510_panel;
-extern struct lcd_panel lph8923_panel;
-extern struct lcd_panel apollon_panel;
-
-static struct lcd_panel *panels[] = {
-#ifdef CONFIG_MACH_OMAP_H2
-       &h2_panel,
-#endif
-#ifdef CONFIG_MACH_OMAP_H3
-       &h3_panel,
-#endif
-#ifdef CONFIG_MACH_OMAP_H4
-       &h4_panel,
-#endif
-#ifdef CONFIG_MACH_OMAP_PERSEUS2
-       &p2_panel,
-#endif
-#ifdef CONFIG_MACH_OMAP_OSK
-       &osk_panel,
-#endif
-#ifdef CONFIG_MACH_OMAP_PALMTE
-       &palmte_panel,
-#endif
-
-#ifdef CONFIG_MACH_OMAP_INNOVATOR
-
-#ifdef CONFIG_ARCH_OMAP15XX
-       &innovator1510_panel,
-#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-       &innovator1610_panel,
-#endif
-
-#endif
-#ifdef CONFIG_MACH_OMAP_APOLLON
-       &apollon_panel,
-#endif
-};
-
 extern struct lcd_ctrl omap1_int_ctrl;
 extern struct lcd_ctrl omap2_int_ctrl;
 extern struct lcd_ctrl hwa742_ctrl;
 extern struct lcd_ctrl blizzard_ctrl;
 
 static struct lcd_ctrl *ctrls[] = {
-#ifdef CONFIG_FB_OMAP_LCDC_INTERNAL
 #ifdef CONFIG_ARCH_OMAP1
        &omap1_int_ctrl,
 #else
        &omap2_int_ctrl,
 #endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_HWA742
+       &hwa742_ctrl,
 #endif
 };
 
@@ -192,7 +148,6 @@ static int ctrl_init(struct omapfb_device *fbdev)
 
        fbdev->ctrl->get_vram_layout(&fbdev->vram_size, &fbdev->vram_virt_base,
                                     &fbdev->vram_phys_base);
-       memset((void *)fbdev->vram_virt_base, 0, fbdev->vram_size);
 
        DBGPRINT(1, "vram_phys %08x vram_virt %p vram_size=%lu\n",
                 fbdev->vram_phys_base, fbdev->vram_virt_base,
@@ -339,12 +294,24 @@ static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
        return 0;
 }
 
+static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct omapfb_device *fbdev = info->par;
+       int r;
+
+       omapfb_rqueue_lock(fbdev);
+       r = fbdev->ctrl->mmap(vma);
+       omapfb_rqueue_unlock(fbdev);
+
+       return r;
+}
 
 static void omapfb_update_full_screen(struct omapfb_device *fbdev);
 
 static int omapfb_blank(int blank, struct fb_info *fbi)
 {
        struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par;
+       int do_update = 0;
        int r = 0;
 
        DBGENTER(1);
@@ -359,7 +326,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                        fbdev->state = OMAPFB_ACTIVE;
                        if (fbdev->ctrl->get_update_mode() ==
                                        OMAPFB_MANUAL_UPDATE)
-                               omapfb_update_full_screen(fbdev);
+                               do_update = 1;
                }
                break;
        case VESA_POWERDOWN:
@@ -375,6 +342,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
        }
        omapfb_rqueue_unlock(fbdev);
 
+       if (do_update)
+               omapfb_update_full_screen(fbdev);
+
        DBGLEAVE(1);
        return r;
 }
@@ -763,8 +733,6 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
        } p;
        int r = 0;
 
-       DBGENTER(2);
-
        BUG_ON(!ops);
        DBGPRINT(2, "cmd=%010x\n", cmd);
        switch (cmd)
@@ -792,6 +760,15 @@ static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
                                        (enum omapfb_update_mode __user *)arg))
                        r = -EFAULT;
                break;
+       case OMAPFB_UPDATE_WINDOW_OLD:
+               if (copy_from_user(&p.update_window, (void __user *)arg,
+                                  sizeof(struct omapfb_update_window_old)))
+                       r = -EFAULT;
+               else {
+                       p.update_window.format = 0;
+                       r = omapfb_update_win(fbdev, &p.update_window);
+               }
+               break;
        case OMAPFB_UPDATE_WINDOW:
                if (copy_from_user(&p.update_window, (void __user *)arg,
                                   sizeof(p.update_window)))
@@ -1134,45 +1111,21 @@ static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
        }
 }
 
-static int omapfb_find_panel(struct omapfb_device *fbdev)
-{
-       const struct omap_lcd_config *conf;
-       char name[17];
-       int i;
-
-       conf = (struct omap_lcd_config *)fbdev->dev->platform_data;
-       fbdev->panel = NULL;
-       if (conf == NULL)
-               return -1;
-
-       strncpy(name, conf->panel_name, sizeof(name) - 1);
-       name[sizeof(name) - 1] = 0;
-       for (i = 0; i < ARRAY_SIZE(panels); i++) {
-               if (strcmp(panels[i]->name, name) == 0) {
-                       fbdev->panel = panels[i];
-                       break;
-               }
-       }
-
-       if (fbdev->panel == NULL)
-               return -1;
-
-       return 0;
-}
-
 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
 {
-       struct omap_lcd_config *conf;
+       struct omapfb_platform_data *conf;
        char name[17];
        int i;
 
-       conf = (struct omap_lcd_config *)fbdev->dev->platform_data;
+       conf = (struct omapfb_platform_data *)fbdev->dev->platform_data;
 
        fbdev->ctrl = NULL;
-       if (conf == NULL)
+       if (conf == NULL) {
+               DBGPRINT(1, "omap_lcd_config not found\n");
                return -1;
+       }
 
-       strncpy(name, conf->ctrl_name, sizeof(name) - 1);
+       strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
        name[sizeof(name) - 1] = '\0';
 
        if (strcmp(name, "internal") == 0) {
@@ -1181,14 +1134,17 @@ static int omapfb_find_ctrl(struct omapfb_device *fbdev)
        }
 
        for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
+               DBGPRINT(1, "ctrl %s\n", ctrls[i]->name);
                if (strcmp(ctrls[i]->name, name) == 0) {
                        fbdev->ctrl = ctrls[i];
                        break;
                }
        }
 
-       if (fbdev->ctrl == NULL)
+       if (fbdev->ctrl == NULL) {
+               DBGPRINT(1, "ctrl %s not supported\n", name);
                return -1;
+       }
 
        return 0;
 }
@@ -1218,13 +1174,12 @@ static void check_required_callbacks(struct omapfb_device *fbdev)
  *      start LCD frame transfer
  *   7. register system fb_info structure
  */
-static int omapfb_probe(struct platform_device *pdev)
+static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel)
 {
        struct omapfb_device    *fbdev = NULL;
        struct fb_info          *fbi;
        int                     init_state;
        unsigned long           phz, hhz, vhz;
-       struct lcd_panel        *panel;
        int                     r = 0;
 
        DBGENTER(1);
@@ -1248,14 +1203,13 @@ static int omapfb_probe(struct platform_device *pdev)
        fbdev = (struct omapfb_device *)fbi->par;
        fbdev->fb_info = fbi;
        fbdev->dev = &pdev->dev;
+       fbdev->panel = panel;
        platform_set_drvdata(pdev, fbdev);
 
        init_MUTEX(&fbdev->rqueue_sema);
 
 #ifdef CONFIG_ARCH_OMAP1
-#ifdef CONFIG_FB_OMAP_LCDC_INTERNAL
        fbdev->int_ctrl = &omap1_int_ctrl;
-#endif
 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
        fbdev->ext_if = &sossi_extif;
 #endif
@@ -1271,15 +1225,6 @@ static int omapfb_probe(struct platform_device *pdev)
                goto cleanup;
        }
 
-       if (omapfb_find_panel(fbdev) < 0) {
-               pr_err("LCD panel not found, board not supported\n");
-               r = -ENODEV;
-               goto cleanup;
-       }
-
-       check_required_callbacks(fbdev);
-
-
        pr_info(MODULE_NAME ": configured for panel %s\n", fbdev->panel->name);
 
        r = fbdev->panel->init(fbdev);
@@ -1292,6 +1237,14 @@ static int omapfb_probe(struct platform_device *pdev)
                goto cleanup;
        init_state++;
 
+       /* We depend on doing this after ctrl_init, since it can redefine
+        * member functions.
+        */
+       if (fbdev->ctrl->mmap)
+               omapfb_ops.fb_mmap = omapfb_mmap;
+
+       check_required_callbacks(fbdev);
+
        r = fbinfo_init(fbdev);
        if (r)
                goto cleanup;
@@ -1308,7 +1261,8 @@ static int omapfb_probe(struct platform_device *pdev)
                goto cleanup;
        }
 
-       omapfb_enable_plane(fbdev, 0, 1);
+       if (!manual_update)
+               omapfb_enable_plane(fbdev, OMAPFB_PLANE_GFX, 1);
 
        omapfb_set_update_mode(fbdev, manual_update ?
                                   OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
@@ -1352,6 +1306,30 @@ cleanup:
        return r;
 }
 
+static struct platform_device  *fbdev_pdev;
+static struct lcd_panel                *fbdev_panel;
+
+static int omapfb_probe(struct platform_device *pdev)
+{
+       BUG_ON(fbdev_pdev != NULL);
+
+       DBGENTER(1);
+       fbdev_pdev = pdev;
+       if (fbdev_panel != NULL)
+               omapfb_do_probe(fbdev_pdev, fbdev_panel);
+       return 0;
+}
+
+void omapfb_register_panel(struct lcd_panel *panel)
+{
+       BUG_ON(fbdev_panel != NULL);
+
+       DBGENTER(1);
+       fbdev_panel = panel;
+       if (fbdev_pdev != NULL)
+               omapfb_do_probe(fbdev_pdev, fbdev_panel);
+}
+
 /* Called when the device is being detached from the driver */
 static int omapfb_remove(struct platform_device *pdev)
 {
index d4e959acd6865898911cd489f8f3a446f5ea2ff6..82415f50a6961d2fb5ff0b438f998a4f60356a3e 100644 (file)
 
 #include "dispc.h"
 
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
+
 #define MODULE_NAME "omapfb-rfbi"
 
 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
@@ -68,8 +72,11 @@ static struct {
        void            (*lcdc_callback)(void *data);
        void            *lcdc_callback_data;
        unsigned long   l4_khz;
+       int             bits_per_cycle;
 } rfbi;
 
+struct lcd_ctrl_extif rfbi_extif;
+
 static inline void rfbi_write_reg(int idx, u32 val)
 {
        __raw_writel(val, rfbi.base + idx);
@@ -80,25 +87,18 @@ static inline u32 rfbi_read_reg(int idx)
        return __raw_readl(rfbi.base + idx);
 }
 
-static int ns_to_l4_ticks(int time)
-{
-       unsigned long tick_ps;
-       int ret;
-
-       /* Calculate in picosecs to yield more exact results */
-       tick_ps = 1000000000 / (rfbi.l4_khz);
-
-       ret = (time * 1000 + tick_ps - 1) / tick_ps;
-
-       return ret * 2;
-}
-
 #ifdef OMAPFB_DBG
-static void print_timings(void)
+static void rfbi_print_timings(void)
 {
        u32 l;
+       u32 time;
 
-       DBGPRINT(1, "Tick time %lu ps\n", 1000000000 / rfbi.l4_khz);
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       time = 1000000000 / rfbi.l4_khz;
+       if (l & (1 << 4))
+               time *= 2;
+
+       DBGPRINT(1, "Tick time %u ps\n", time);
        l = rfbi_read_reg(RFBI_ONOFF_TIME0);
        DBGPRINT(1, "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
               "REONTIME %d, REOFFTIME %d\n",
@@ -109,55 +109,181 @@ static void print_timings(void)
               "ACCESSTIME %d\n",
               (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, (l >> 22) & 0x3f);
 }
+#else
+static void rfbi_print_timings(void) {}
 #endif
 
 static void rfbi_set_timings(const struct extif_timings *t)
 {
        u32 l;
-       int on, off;
-
-       on = ns_to_l4_ticks(t->cs_on_time) & 0x0f;
-       l = on;
-       off = ns_to_l4_ticks(t->cs_off_time) & 0x3f;
-       if (off <= on)
-               off = on + 2;
-       l |= off << 4;
-
-       on = ns_to_l4_ticks(t->we_on_time) & 0x0f;
-       l |= on << 10;
-       off = ns_to_l4_ticks(t->we_off_time) & 0x3f;
-       if (off <= on)
-               off = on + 2;
-       l |= off << 14;
-
-       l |= (ns_to_l4_ticks(t->re_on_time) & 0x0f) << 20;
-       l |= (ns_to_l4_ticks(t->re_off_time) & 0x3f) << 24;
-       rfbi_write_reg(RFBI_ONOFF_TIME0, l);
-
-       l = ns_to_l4_ticks(t->we_cycle_time) & 0x3f;
-       l |= (ns_to_l4_ticks(t->re_cycle_time) & 0x3f) << 6;
-       l |= (ns_to_l4_ticks(t->cs_pulse_width) & 0x3f) << 12;
-       l |= (ns_to_l4_ticks(t->access_time) & 0x3f) << 22;
-       rfbi_write_reg(RFBI_CYCLE_TIME0, l);
+
+       BUG_ON(!t->converted);
+
+       rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]);
+       rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]);
+
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       l &= ~(1 << 4);
+       l |= (t->tim[2] ? 1 : 0) << 4;
+       rfbi_write_reg(RFBI_CONFIG0, l);
+
+       rfbi_print_timings();
+}
+
+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+       *clk_period = 1000000000 / rfbi.l4_khz;
+       *max_clk_div = 2;
+}
+
+static int ps_to_rfbi_ticks(int time, int div)
+{
+       unsigned long tick_ps;
+       int ret;
+
+       /* Calculate in picosecs to yield more exact results */
+       tick_ps = 1000000000 / (rfbi.l4_khz) * div;
+
+       ret = (time + tick_ps - 1) / tick_ps;
+
+       return ret;
 }
 
-static void rfbi_write_command(u32 cmd)
+static int rfbi_convert_timings(struct extif_timings *t)
 {
-       rfbi_write_reg(RFBI_CMD, cmd);
+       u32 l;
+       int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
+       int actim, recyc, wecyc;
+       int div = t->clk_div;
+
+       if (div <= 0 || div > 2)
+               return -1;
+
+       /* Make sure that after conversion it still holds that:
+        * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
+        * csoff > cson, csoff >= max(weoff, reoff), actim > reon
+        */
+       weon = ps_to_rfbi_ticks(t->we_on_time, div);
+       weoff = ps_to_rfbi_ticks(t->we_off_time, div);
+       if (weoff <= weon)
+               weoff = weon + 1;
+       if (weon > 0x0f)
+               return -1;
+       if (weoff > 0x3f)
+               return -1;
+
+       reon = ps_to_rfbi_ticks(t->re_on_time, div);
+       reoff = ps_to_rfbi_ticks(t->re_off_time, div);
+       if (reoff <= reon)
+               reoff = reon + 1;
+       if (reon > 0x0f)
+               return -1;
+       if (reoff > 0x3f)
+               return -1;
+
+       cson = ps_to_rfbi_ticks(t->cs_on_time, div);
+       csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
+       if (csoff <= cson)
+               csoff = cson + 1;
+       if (csoff < max(weoff, reoff))
+               csoff = max(weoff, reoff);
+       if (cson > 0x0f)
+               return -1;
+       if (csoff > 0x3f)
+               return -1;
+
+       l =  cson;
+       l |= csoff << 4;
+       l |= weon  << 10;
+       l |= weoff << 14;
+       l |= reon  << 20;
+       l |= reoff << 24;
+
+       t->tim[0] = l;
+
+       actim = ps_to_rfbi_ticks(t->access_time, div);
+       if (actim <= reon)
+               actim = reon + 1;
+       if (actim > 0x3f)
+               return -1;
+
+       wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
+       if (wecyc < weoff)
+               wecyc = weoff;
+       if (wecyc > 0x3f)
+               return -1;
+
+       recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
+       if (recyc < reoff)
+               recyc = reoff;
+       if (recyc > 0x3f)
+               return -1;
+
+       cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
+       if (cs_pulse > 0x3f)
+               return -1;
+
+       l =  wecyc;
+       l |= recyc    << 6;
+       l |= cs_pulse << 12;
+       l |= actim    << 22;
+
+       t->tim[1] = l;
+
+       t->tim[2] = div - 1;
+
+       t->converted = 1;
+
+       return 0;
 }
 
-static u32 rfbi_read_data(void)
+static void rfbi_write_command(const void *buf, unsigned int len)
 {
-       u32 val;
+       if (rfbi.bits_per_cycle == 16) {
+               const u16 *w = buf;
+               BUG_ON(len & 1);
+               for (; len; len -= 2)
+                       rfbi_write_reg(RFBI_CMD, *w++);
+       } else {
+               const u8 *b = buf;
+               BUG_ON(rfbi.bits_per_cycle != 8);
+               for (; len; len--)
+                       rfbi_write_reg(RFBI_CMD, *b++);
+       }
+}
 
-       rfbi_write_reg(RFBI_READ, 0);
-       val = rfbi_read_reg(RFBI_READ);
-       return val;
+static void rfbi_read_data(void *buf, unsigned int len)
+{
+       if (rfbi.bits_per_cycle == 16) {
+               u16 *w = buf;
+               BUG_ON(len & ~1);
+               for (; len; len -= 2) {
+                       rfbi_write_reg(RFBI_READ, 0);
+                       *w++ = rfbi_read_reg(RFBI_READ);
+               }
+       } else {
+               u8 *b = buf;
+               BUG_ON(rfbi.bits_per_cycle != 8);
+               for (; len; len--) {
+                       rfbi_write_reg(RFBI_READ, 0);
+                       *b++ = rfbi_read_reg(RFBI_READ);
+               }
+       }
 }
 
-static void rfbi_write_data(u32 val)
+static void rfbi_write_data(const void *buf, unsigned int len)
 {
-       rfbi_write_reg(RFBI_PARAM, val);
+       if (rfbi.bits_per_cycle == 16) {
+               const u16 *w = buf;
+               BUG_ON(len & 1);
+               for (; len; len -= 2)
+                       rfbi_write_reg(RFBI_PARAM, *w++);
+       } else {
+               const u8 *b = buf;
+               BUG_ON(rfbi.bits_per_cycle != 8);
+               for (; len; len--)
+                       rfbi_write_reg(RFBI_PARAM, *b++);
+       }
 }
 
 static void rfbi_transfer_area(int width, int height,
@@ -195,13 +321,32 @@ static void rfbi_dma_callback(void *data)
        rfbi.lcdc_callback(rfbi.lcdc_callback_data);
 }
 
+static void rfbi_set_bits_per_cycle(int bpc)
+{
+       u32 l;
+
+       l = rfbi_read_reg(RFBI_CONFIG0);
+       l &= ~(0x03 << 0);
+       switch (bpc)
+       {
+       case 8:
+               break;
+       case 16:
+               l |= 3;
+               break;
+       default:
+               BUG();
+       }
+       rfbi_write_reg(RFBI_CONFIG0, l);
+       rfbi.bits_per_cycle = bpc;
+}
+
 static int rfbi_init(void)
 {
        u32 l;
        int r;
        struct clk *dss_ick;
 
-       memset(&rfbi, 0, sizeof(rfbi));
        rfbi.base = io_p2v(RFBI_BASE);
 
        l = rfbi_read_reg(RFBI_REVISION);
@@ -212,6 +357,7 @@ static int rfbi_init(void)
                pr_err("can't get dss_ick\n");
                return PTR_ERR(dss_ick);
        }
+
        rfbi.l4_khz = clk_get_rate(dss_ick) / 1000;
        clk_put(dss_ick);
 
@@ -229,13 +375,10 @@ static int rfbi_init(void)
        l |= (0 << 9) | (1 << 20) | (1 << 21);
        rfbi_write_reg(RFBI_CONFIG0, l);
 
-       l = 0x10;
-       rfbi_write_reg(RFBI_DATA_CYCLE1_0, l);
-       rfbi_write_reg(RFBI_DATA_CYCLE2_0, l);
-       rfbi_write_reg(RFBI_DATA_CYCLE3_0, l);
+       rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010);
 
        l = rfbi_read_reg(RFBI_CONTROL);
-       /* Select CS0 */
+       /* Select CS0, clear bypass mode */
        l = (0x01 << 2);
        rfbi_write_reg(RFBI_CONTROL, l);
 
@@ -255,10 +398,14 @@ static void rfbi_cleanup(void)
 struct lcd_ctrl_extif rfbi_extif = {
        .init                   = rfbi_init,
        .cleanup                = rfbi_cleanup,
+       .get_clk_info           = rfbi_get_clk_info,
+       .set_bits_per_cycle     = rfbi_set_bits_per_cycle,
+       .convert_timings        = rfbi_convert_timings,
        .set_timings            = rfbi_set_timings,
        .write_command          = rfbi_write_command,
        .read_data              = rfbi_read_data,
        .write_data             = rfbi_write_data,
        .transfer_area          = rfbi_transfer_area,
+       .max_transmit_size      = (u32)~0,
 };
 
index ba26512a504af6e3f2da4fcef63b602c1c26bfb7..986f639f58895b1c038c665bebdce7b19d8d2966 100644 (file)
 
 #include <asm/io.h>
 
-#include "sossi.h"
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include "lcdc.h"
+
+/* #define OMAPFB_DBG 1 */
+
+#include "debug.h"
 
 #define MODULE_NAME            "omapfb-sossi"
 
 #define DMA_LCD_CTRL      0xfffee3c4
 #define DMA_LCD_LCH_CTRL  0xfffee3ea
 
+#define RD_ACCESS              0
+#define WR_ACCESS              1
+
+#define SOSSI_MAX_XMIT_BYTES   (512 * 1024)
+
 #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
 
-static int sossi_base = IO_ADDRESS(OMAP_SOSSI_BASE);
+static struct sossi {
+       int             base;
+       unsigned long   dpll_khz;
+       int             bus_pick_width;
+       void            (*lcdc_callback)(void *data);
+       void            *lcdc_callback_data;
+       /* timing for read and write access */
+       int             clk_div;
+       u8              clk_tw0[2];
+       u8              clk_tw1[2];
+       /* if last_access is the same as current we don't have to change
+        * the timings
+        */
+       int             last_access;
+} sossi;
+
+struct lcd_ctrl_extif sossi_extif;
 
 static inline u32 sossi_read_reg(int reg)
 {
-        return readl(sossi_base + reg);
+        return readl(sossi.base + reg);
 }
 
 static inline u16 sossi_read_reg16(int reg)
 {
-        return readw(sossi_base + reg);
+        return readw(sossi.base + reg);
 }
 
 static inline u8 sossi_read_reg8(int reg)
 {
-        return readb(sossi_base + reg);
+        return readb(sossi.base + reg);
 }
 
 static inline void sossi_write_reg(int reg, u32 value)
 {
-        writel(value, sossi_base + reg);
+        writel(value, sossi.base + reg);
 }
 
 static inline void sossi_write_reg16(int reg, u16 value)
 {
-        writew(value, sossi_base + reg);
+        writew(value, sossi.base + reg);
 }
 
 static inline void sossi_write_reg8(int reg, u8 value)
 {
-        writeb(value, sossi_base + reg);
+        writeb(value, sossi.base + reg);
 }
 
 static void sossi_set_bits(int reg, u32 bits)
@@ -96,14 +124,26 @@ static void sossi_clear_bits(int reg, u32 bits)
 #define CONF_SOSSI_RESET_R      (1 << 23)
 #define CONF_MOD_SOSSI_CLK_EN_R (1 << 16)
 
-static struct clk *dpll_clk;
+static void sossi_dma_callback(void *data);
 
-int sossi_init(void)
+static int sossi_init(void)
 {
        u32 l, k;
+       struct clk *dpll_clk;
+       int r;
+
+       sossi.base = IO_ADDRESS(OMAP_SOSSI_BASE);
 
        dpll_clk = clk_get(NULL, "ck_dpll1");
-       BUG_ON(dpll_clk == NULL);
+       if (IS_ERR(dpll_clk)) {
+               pr_err("can't get dpll1 clock\n");
+               return PTR_ERR(dpll_clk);
+       }
+
+       sossi.dpll_khz = clk_get_rate(dpll_clk) / 1000;
+       clk_put(dpll_clk);
+
+       sossi_extif.max_transmit_size = SOSSI_MAX_XMIT_BYTES;
 
        /* Reset and enable the SoSSI module */
        l = omap_readl(MOD_CONF_CTRL_1);
@@ -134,6 +174,12 @@ int sossi_init(void)
                pr_err("Invalid SoSSI sync pattern: %08x, %08x\n", l, k);
                return -ENODEV;
        }
+
+       if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
+               pr_err("can't get LCDC IRQ\n");
+               return r;
+       }
+
        l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
        l = sossi_read_reg(SOSSI_ID_REG);
        pr_info(KERN_INFO MODULE_NAME ": version %d.%d initialized\n",
@@ -147,89 +193,201 @@ int sossi_init(void)
        return 0;
 }
 
-static unsigned long get_sossi_clk_rate(int div)
+static void sossi_cleanup(void)
 {
-       return (clk_get_rate(dpll_clk)) / div;
+       omap_lcdc_free_dma_callback();
 }
 
-static unsigned long get_sossi_clk_period(int div)
+#define KHZ_TO_PS(x)   (1000000000 / (x))
+
+static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
 {
-       /* In picoseconds */
-       return 1000000000 / (get_sossi_clk_rate(div) / 1000);
+       *clk_period = KHZ_TO_PS(sossi.dpll_khz);
+       *max_clk_div = 8;
 }
 
-static int ns_to_sossi_ticks(int time, int div)
+static u32 ps_to_sossi_ticks(u32 ps, int div)
 {
-       unsigned long tick_ps;
+       u32 clk_period = KHZ_TO_PS(sossi.dpll_khz) * div;
+       return (clk_period + ps - 1) / clk_period;
+}
+
+static int calc_rd_timings(struct extif_timings *t)
+{
+       u32 tw0, tw1;
+       int reon, reoff, recyc, actim;
+       int div = t->clk_div;
+
+       /* Make sure that after conversion it still holds that:
+        * reoff > reon, recyc >= reoff, actim > reon
+        */
+       reon = ps_to_sossi_ticks(t->re_on_time, div);
+       /* reon will be exactly one sossi tick */
+       if (reon > 1)
+               return -1;
+
+       reoff = ps_to_sossi_ticks(t->re_off_time, div);
+
+       if (reoff <= reon)
+               reoff = reon + 1;
 
-       /* Calculate in picosecs to yield more exact results */
-       tick_ps = get_sossi_clk_period(div);
+       tw0 = reoff - reon;
+       if (tw0 > 0x10)
+               return -1;
+
+       recyc = ps_to_sossi_ticks(t->re_cycle_time, div);
+       if (recyc <= reoff)
+               recyc = reoff + 1;
+
+       tw1 = recyc - reoff;
+       if (tw1 > 0x40)
+               return -1;
+
+       actim = ps_to_sossi_ticks(t->access_time, div);
+       if (actim < reoff)
+               actim++;
+       /* access time (data hold time) will be exactly one sossi
+        * tick
+        */
+       if (actim - reoff > 1)
+               return -1;
 
-       return (time * 1000 + tick_ps - 1) / tick_ps;
+       t->tim[0] = tw0 - 1;
+       t->tim[1] = tw1 - 1;
+
+       return 0;
 }
 
-static int set_timings(int div, int tw0, int tw1)
+static int calc_wr_timings(struct extif_timings *t)
 {
-       u32 l;
+       u32 tw0, tw1;
+       int weon, weoff, wecyc;
+       int div = t->clk_div;
+
+       /* Make sure that after conversion it still holds that:
+        * weoff > weon, wecyc >= weoff
+        */
+       weon = ps_to_sossi_ticks(t->we_on_time, div);
+       /* weon will be exactly one sossi tick */
+       if (weon > 1)
+               return -1;
+
+       weoff = ps_to_sossi_ticks(t->we_off_time, div);
+       if (weoff <= weon)
+               weoff = weon + 1;
+       tw0 = weoff - weon;
+       if (tw0 > 0x10)
+               return -1;
+
+       wecyc = ps_to_sossi_ticks(t->we_cycle_time, div);
+       if (wecyc <= weoff)
+               wecyc = weoff + 1;
 
-       if (tw1 * 1000 > 64 * get_sossi_clk_period(div))
+       tw1 = wecyc - weoff;
+       if (tw1 > 0x40)
                return -1;
-       if (tw0 * 1000 > 16 * get_sossi_clk_period(div))
+
+       t->tim[2] = tw0 - 1;
+       t->tim[3] = tw1 - 1;
+
+       return 0;
+}
+
+static int sossi_convert_timings(struct extif_timings *t)
+{
+       int r = 0;
+       int div = t->clk_div;
+
+       t->converted = 0;
+
+       if (div <= 0 || div > 8)
                return -1;
 
+       /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */
+       if ((r = calc_rd_timings(t)) < 0)
+               return r;
+
+       if ((r = calc_wr_timings(t)) < 0)
+               return r;
+
+       t->tim[4] = div - 1;
+
+       t->converted = 1;
+
+       return 0;
+}
+
+static void sossi_set_timings(const struct extif_timings *t)
+{
+       BUG_ON(!t->converted);
+
+       sossi.clk_tw0[RD_ACCESS] = t->tim[0];
+       sossi.clk_tw1[RD_ACCESS] = t->tim[1];
+
+       sossi.clk_tw0[WR_ACCESS] = t->tim[2];
+       sossi.clk_tw1[WR_ACCESS] = t->tim[3];
+
+       sossi.clk_div = t->tim[4];
+}
+
+static void _set_timing(int div, int tw0, int tw1)
+{
+       u32 l;
+
+       DBGPRINT(2, "Using TW0 = %d, TW1 = %d, div = %d\n",
+                tw0 + 1, tw1 + 1, div + 1);
+
        l = omap_readl(MOD_CONF_CTRL_1);
        l &= ~(7 << 17);
-       l |= (div - 1) << 17;
+       l |= div << 17;
        omap_writel(l, MOD_CONF_CTRL_1);
 
-       tw0 = ns_to_sossi_ticks(tw0, div) - 1;
-       tw1 = ns_to_sossi_ticks(tw1, div) - 1;
-       if (tw0 < 0)
-               tw0 = 0;
-       if (tw1 < 0)
-               tw1 = 0;
-#if 0
-       printk("Using TW0 = %d, TW1 = %d, div = %d, period = %d ps\n",
-              tw0, tw1, div, get_sossi_clk_period(div));
-#endif
        l = sossi_read_reg(SOSSI_INIT1_REG);
        l &= ~((0x0f << 20) | (0x3f << 24));
-       l |= ((tw0 & 0x0f) << 20) | ((tw1 & 0x3f) << 24);
+       l |= (tw0 << 20) | (tw1 << 24);
        sossi_write_reg(SOSSI_INIT1_REG, l);
-
-       return 0;
 }
 
-static struct sossi {
-       int bus_pick_width;
-} sossi;
-
-void sossi_set_timings(int min_time, int min_tw0, int min_tw1)
+static inline void set_timing(int access)
 {
-       int div;
-
-       for (div = 1; div <= 8; div++) {
-               if (min_time * 1000 > get_sossi_clk_period(div))
-                       continue;
-               if (set_timings(div, min_tw0, min_tw1) == 0)
-                       break;
-       }
-       if (div == 9) {
-               pr_err("DPLL frequency too high for SoSSI\n");
-               BUG();
+       if (access != sossi.last_access) {
+               sossi.last_access = access;
+               _set_timing(sossi.clk_div,
+                           sossi.clk_tw0[access], sossi.clk_tw1[access]);
        }
 }
 
-void sossi_set_xfer_params(int bus_pick_count, int bus_pick_width)
+static void sossi_set_bits_per_cycle(int bpc)
 {
        u32 l;
-
+       int bus_pick_count, bus_pick_width;
+
+       DBGPRINT(2, "bits_per_cycle %d\n", bpc);
+       /* We set explicitly the the bus_pick_count as well, although
+        * with remapping/reordering disabled it will be calculated by HW
+        * as (32 / bus_pick_width).
+        */
+       switch (bpc) {
+       case 8:
+               bus_pick_count = 4;
+               bus_pick_width = 8;
+               break;
+       case 16:
+               bus_pick_count = 2;
+               bus_pick_width = 16;
+               break;
+       default:
+               BUG();
+               return;
+       }
+       l = sossi_read_reg(SOSSI_INIT3_REG);
        sossi.bus_pick_width = bus_pick_width;
-       l = ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
+       l &= ~0x3ff;
+       l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
        sossi_write_reg(SOSSI_INIT3_REG, l);
 }
 
-void sossi_start_transfer(void)
+static void sossi_start_transfer(void)
 {
        /* WE */
        sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
@@ -238,7 +396,7 @@ void sossi_start_transfer(void)
        /* FIXME: locking? */
 }
 
-void sossi_stop_transfer(void)
+static void sossi_stop_transfer(void)
 {
        /* WE */
        sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
@@ -247,6 +405,12 @@ void sossi_stop_transfer(void)
        /* FIXME: locking? */
 }
 
+static void wait_end_of_write(void)
+{
+       /* Before reading we must check if some writings are going on */
+       while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
+}
+
 static void send_data(const void *data, unsigned int len)
 {
        while (len >= 4) {
@@ -268,65 +432,71 @@ static void send_data(const void *data, unsigned int len)
 
 static void set_cycles(unsigned int len)
 {
-       int nr_cycles = len / (sossi.bus_pick_width / 8);
+       unsigned long nr_cycles = len / (sossi.bus_pick_width / 8);
+
+       BUG_ON((nr_cycles - 1) & ~0x3ffff);
 
        sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff);
        sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
 }
 
-void sossi_send_cmd(const void *data, unsigned int len)
+static void sossi_write_command(const void *data, unsigned int len)
 {
+       set_timing(WR_ACCESS);
+       /* CMD#/DATA */
        sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
        set_cycles(len);
+       sossi_start_transfer();
        send_data(data, len);
+       sossi_stop_transfer();
+       wait_end_of_write();
 }
 
-void sossi_send_data(const void *data, unsigned int len)
+static void sossi_write_data(const void *data, unsigned int len)
 {
+       set_timing(WR_ACCESS);
+       /* CMD#/DATA */
        sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
        set_cycles(len);
+       sossi_start_transfer();
        send_data(data, len);
+       sossi_stop_transfer();
+       wait_end_of_write();
 }
 
-void sossi_prepare_dma_transfer(unsigned int count)
+static void sossi_transfer_area(int width, int height,
+                               void (callback)(void *data), void *data)
 {
-       sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
-       set_cycles(count);
-}
+       BUG_ON(callback == NULL);
 
-void sossi_send_data_const32(u32 data, unsigned int count)
-{
+       sossi.lcdc_callback = callback;
+       sossi.lcdc_callback_data = data;
+
+       set_timing(WR_ACCESS);
+       /* CMD#/DATA */
        sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
-       set_cycles(count * 4);
-       while (count > 0) {
-               sossi_write_reg(SOSSI_FIFO_REG, data);
-               count--;
-       }
+       set_cycles(width * height * sossi.bus_pick_width / 8);
+
+       DBGPRINT(2, "SOSSI_INIT1_REG %08x\n", sossi_read_reg(SOSSI_INIT1_REG));
+
+       sossi_start_transfer();
+       omap_enable_lcd_dma();
 }
 
-void sossi_set_tearing(int mode, int hs_counter, int detect_limit,
-                      int vs_counter, int vs_detect_limit, int flags)
+static void sossi_dma_callback(void *data)
 {
-       u32 l = 0;
-
-       l |= vs_counter << 30;
-       if (flags & SOSSI_FLAG_HS_INVERTED)
-               l |= 1 << 29;
-       if (flags & SOSSI_FLAG_VS_INVERTED)
-               l |= 1 << 28;
-       l |= mode << 26;
-       l |= hs_counter << 15;
-       l |= vs_detect_limit << 3;
-       l |= detect_limit;
-       sossi_write_reg(SOSSI_TEARING_REG, l);
+       omap_stop_lcd_dma();
+       sossi_stop_transfer();
+       sossi.lcdc_callback(sossi.lcdc_callback_data);
 }
 
-void sossi_read_data(void *data, unsigned int len)
+static void sossi_read_data(void *data, unsigned int len)
 {
-       /* Before reading we must check if some writings are going on */
-       while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
+       set_timing(RD_ACCESS);
+       /* CMD#/DATA */
        sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
        set_cycles(len);
+       sossi_start_transfer();
        while (len >= 4) {
                *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG);
                len -= 4;
@@ -342,4 +512,18 @@ void sossi_read_data(void *data, unsigned int len)
                len--;
                data++;
        }
+       sossi_stop_transfer();
 }
+
+struct lcd_ctrl_extif sossi_extif = {
+       .init                   = sossi_init,
+       .cleanup                = sossi_cleanup,
+       .get_clk_info           = sossi_get_clk_info,
+       .convert_timings        = sossi_convert_timings,
+       .set_timings            = sossi_set_timings,
+       .set_bits_per_cycle     = sossi_set_bits_per_cycle,
+       .write_command          = sossi_write_command,
+       .read_data              = sossi_read_data,
+       .write_data             = sossi_write_data,
+       .transfer_area          = sossi_transfer_area,
+};
diff --git a/drivers/video/omap/sossi.h b/drivers/video/omap/sossi.h
deleted file mode 100644 (file)
index b71a4b9..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef DRIVERS_VIDEO_OMAP_SOSSI_H
-#define DRIVERS_VIDEO_OMAP_SOSSI_H
-
-#define SOSSI_FLAG_HS_INVERTED          0x01
-#define SOSSI_FLAG_VS_INVERTED          0x02
-
-extern int sossi_init(void);
-extern void sossi_set_xfer_params(int bus_pick_count, int bus_pick_width);
-extern void sossi_set_timings(int tick_ns, int tw0_ns, int tw1_ns);
-extern void sossi_start_transfer(void);
-extern void sossi_stop_transfer(void);
-extern void sossi_send_cmd(const void *data, unsigned int len);
-extern void sossi_send_data(const void *data, unsigned int len);
-extern void sossi_send_data_const32(u32 data, unsigned int count);
-extern void sossi_prepare_dma_transfer(unsigned int count);
-extern void sossi_read_data(void *data, unsigned int len);
-extern void sossi_set_tearing(int mode, int hs_counter, int detect_limit,
-                             int vs_counter, int vs_detect_limit, int flags);
-
-#endif
index 684e871050e15c1e31cec12e9ba4d5d8e302349a..6d6240a4681cafb0cedb4eed9fb7e717d639b640 100644 (file)
@@ -21,6 +21,7 @@
 #define OMAP_TAG_LCD           0x4f05
 #define OMAP_TAG_GPIO_SWITCH   0x4f06
 #define OMAP_TAG_UART          0x4f07
+#define OMAP_TAG_FBMEM         0x4f08
 #define OMAP_TAG_STI_CONSOLE   0x4f09
 
 #define OMAP_TAG_BOOT_REASON    0x4f80
@@ -94,6 +95,13 @@ struct omap_lcd_config {
        char ctrl_name[16];
 };
 
+struct omap_fbmem_config {
+       u32 fb_sram_start;
+       u32 fb_sram_size;
+       u32 fb_sdram_start;
+       u32 fb_sdram_size;
+};
+
 /* Cover:
  *      high -> closed
  *      low  -> open
diff --git a/include/asm-arm/arch-omap/lcd_lph8923.h b/include/asm-arm/arch-omap/lcd_lph8923.h
new file mode 100644 (file)
index 0000000..004e67e
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LCD_LPH8923_H
+#define __LCD_LPH8923_H
+
+enum lcd_lph8923_test_num {
+       LCD_LPH8923_TEST_RGB_LINES,
+};
+
+enum lcd_lph8923_test_result {
+       LCD_LPH8923_TEST_SUCCESS,
+       LCD_LPH8923_TEST_INVALID,
+       LCD_LPH8923_TEST_FAILED,
+};
+
+#endif
index 4ba2622cc142803422a20cda69f4bad5076ebfd6..ffac7c0f827da55fa41bc90ab2280bcca244e815 100644 (file)
@@ -35,6 +35,7 @@
 #define OMAPFB_SYNC_GFX                OMAP_IO(37)
 #define OMAPFB_VSYNC           OMAP_IO(38)
 #define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum omapfb_update_mode)
+#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
 #define OMAPFB_GET_CAPS                OMAP_IOR(42, unsigned long)
 #define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum omapfb_update_mode)
 #define OMAPFB_LCD_TEST                OMAP_IOW(45, int)
@@ -71,6 +72,11 @@ struct omapfb_update_window {
        u32 format;
 };
 
+struct omapfb_update_window_old {
+       u32 x, y;
+       u32 width, height;
+};
+
 enum omapfb_plane {
        OMAPFB_PLANE_GFX = 0,
        OMAPFB_PLANE_VID1,
@@ -121,6 +127,8 @@ enum omapfb_update_mode {
 #include <linux/interrupt.h>
 #include <linux/fb.h>
 
+#include <asm/arch/board.h>
+
 #define OMAP_LCDC_INV_VSYNC             0x0001
 #define OMAP_LCDC_INV_HSYNC             0x0002
 #define OMAP_LCDC_INV_PIX_CLOCK         0x0004
@@ -184,17 +192,27 @@ struct extif_timings {
        int re_cycle_time;
        int cs_pulse_width;
        int access_time;
+
+       int clk_div;
+
+       u32 tim[5];             /* set by extif->convert_timings */
+
+       int converted;
 };
 
 struct lcd_ctrl_extif {
        int  (*init)            (void);
        void (*cleanup)         (void);
+       void (*get_clk_info)    (u32 *clk_period, u32 *max_clk_div);
+       int  (*convert_timings) (struct extif_timings *timings);
        void (*set_timings)     (const struct extif_timings *timings);
-       void (*write_command)   (u32 cmd);
-       u32  (*read_data)       (void);
-       void (*write_data)      (u32 data);
+       void (*set_bits_per_cycle)(int bpc);
+       void (*write_command)   (const void *buf, unsigned int len);
+       void (*read_data)       (void *buf, unsigned int len);
+       void (*write_data)      (const void *buf, unsigned int len);
        void (*transfer_area)   (int width, int height,
                                 void (callback)(void * data), void *data);
+       unsigned long           max_transmit_size;
 };
 
 struct lcd_ctrl {
@@ -207,6 +225,7 @@ struct lcd_ctrl {
        void            (*get_vram_layout)(unsigned long *size,
                                           void **virt_base,
                                           dma_addr_t *phys_base);
+       int             (*mmap)           (struct vm_area_struct *vma);
        unsigned long   (*get_caps)       (void);
        int             (*set_update_mode)(enum omapfb_update_mode mode);
        enum omapfb_update_mode (*get_update_mode)(void);
@@ -261,12 +280,10 @@ struct omapfb_device {
        struct device           *dev;
 };
 
-extern struct lcd_panel h3_panel;
-extern struct lcd_panel h2_panel;
-extern struct lcd_panel p2_panel;
-extern struct lcd_panel osk_panel;
-extern struct lcd_panel innovator1610_panel;
-extern struct lcd_panel innovator1510_panel;
+struct omapfb_platform_data {
+       struct omap_lcd_config   lcd;
+       struct omap_fbmem_config fbmem;
+};
 
 #ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl omap1_lcd_ctrl;
@@ -274,8 +291,12 @@ extern struct lcd_ctrl omap1_lcd_ctrl;
 extern struct lcd_ctrl omap2_disp_ctrl;
 #endif
 
+extern void omapfb_register_panel(struct lcd_panel *panel);
 extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
 
+/* in arch/arm/plat-omap/devices.c */
+extern void omapfb_reserve_mem(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* __OMAPFB_H */
index e72ccbf0fe06843cfb19d75c0ac261ddd95b8e23..6fc0dd57b7c383ae69c6aea14679e4f6c5bc1115 100644 (file)
@@ -20,6 +20,8 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
                                      u32 mem_type);
 extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
+extern unsigned long omap_fb_sram_start;
+extern unsigned long omap_fb_sram_size;
 
 /* Do not use these */
 extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);