]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: Add external LCD controller support for DSP Gateway
authorJuha Yrjola <juha.yrjola@nokia.com>
Tue, 21 Feb 2006 16:08:48 +0000 (18:08 +0200)
committerJuha Yrjola <juha.yrjola@nokia.com>
Tue, 21 Feb 2006 16:08:48 +0000 (18:08 +0200)
If an external LCD controller is in manual update mode, the DSP
must let the FB driver know when a frame should be send over the
remote framebuffer interface.

Original code by Toshihiro, FB parts by Imre.

Signed-off-by: Imre Deak <imre.deak@nokia.com>
Signed-off-by: Juha Yrjölä <juha.yrjola@nokia.com>
arch/arm/plat-omap/dsp/dsp_core.c
arch/arm/plat-omap/dsp/dsp_mem.c
drivers/video/omap/hwa742.c
drivers/video/omap/hwa742.h [deleted file]
drivers/video/omap/omapfb_main.c
include/asm-arm/arch-omap/dsp.h
include/asm-arm/arch-omap/omapfb.h

index f7aa2b8c962a44f377fcc67886fc03d8d843a6bb..a77216a454dc132fd2f9eb1f8d6da9a3a4cff6ad 100644 (file)
@@ -437,11 +437,15 @@ static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL);
 /*
  * kernel function dispatcher
  */
+extern void mbx1_fbctl_upd(void);
 extern void mbx1_fbctl_disable(void);
 
 static void mbx1_kfunc_fbctl(unsigned short data)
 {
        switch (data) {
+       case OMAP_DSP_MBCMD_FBCTL_UPD:
+               mbx1_fbctl_upd();
+               break;
        case OMAP_DSP_MBCMD_FBCTL_DISABLE:
                mbx1_fbctl_disable();
                break;
index f41bad2ae907101ed6c075f65efd603daa0c01df..109d9732c2db306f851dbab0deb38af393a328b4 100644 (file)
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/arch/tc.h>
+#include <asm/arch/omapfb.h>
 #include <asm/arch/dsp.h>
 #include <asm/arch/dsp_common.h>
 #include "uaccess_dsp.h"
+#include "ipbuf.h"
 #include "dsp.h"
 
 #define SZ_1MB 0x100000
@@ -116,6 +118,11 @@ struct exmap_tbl {
 static struct exmap_tbl exmap_tbl[DSPMMU_TLB_LINES];
 static DECLARE_RWSEM(exmap_sem);
 
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
 static int dsp_exunmap(unsigned long dspadr);
 
 static void *dspvect_page;
@@ -1002,6 +1009,23 @@ static unsigned long unmap_free_arm(struct exmap_tbl *ent)
                       "omapdsp: freeing 0x%lx bytes @ adr 0x%8p\n",
                       size, ent->buf);
        }
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       else if (ent->type == EXMAP_TYPE_FB) {
+               int status;
+               if (omapfb_nb) {
+                       status = omapfb_unregister_client(omapfb_nb);
+                       if (!status)
+                               printk("omapfb_unregister_client(): "
+                                      "success\n");
+                       else
+                               printk("omapfb_runegister_client(): "
+                                      "failure(%d)\n", status);
+                       kfree(omapfb_nb);
+                       omapfb_nb = NULL;
+                       omapfb_ready = 0;
+               }
+       }
+#endif
 
        return size;
 }
@@ -1104,14 +1128,41 @@ static void exmap_flush(void)
 #error You configured OMAP_DSP_FBEXPORT, but FB was not configured!
 #endif /* CONFIG_FB */
 
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct omapfb_notifier_block *omapfb_nb,
+                              unsigned long event, struct omapfb_device *fbdev)
+{
+       /* XXX */
+       printk("omapfb_notifier_cb(): event = %s\n",
+              (event == OMAPFB_EVENT_READY)    ? "READY" :
+              (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+       if (event == OMAPFB_EVENT_READY)
+               omapfb_ready = 1;
+       else if (event == OMAPFB_EVENT_DISABLED)
+               omapfb_ready = 0;
+       return 0;
+}
+#endif
+
 static int dsp_fbexport(unsigned long *dspadr)
 {
        unsigned long dspadr_actual;
        unsigned long padr_sys, padr, fbsz_sys, fbsz;
        int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       int status;
+#endif
 
        printk(KERN_DEBUG "omapdsp: frame buffer export\n");
 
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       if (omapfb_nb) {
+               printk(KERN_WARNING
+                      "omapdsp: frame buffer has been exported already!\n");
+               return -EBUSY;
+       }
+#endif
+
        if (num_registered_fb == 0) {
                printk(KERN_INFO "omapdsp: frame buffer not registered.\n");
                return -EINVAL;
@@ -1169,6 +1220,21 @@ static int dsp_fbexport(unsigned long *dspadr)
        /* increase the DMA priority */
        set_emiff_dma_prio(15);
 
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       omapfb_nb = kmalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+       if (omapfb_nb == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: failed to allocate memory for omapfb_nb!\n");
+               dsp_exunmap(dspadr_actual);
+               return -ENOMEM;
+       }
+       status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+       if (!status)
+               printk("omapfb_register_client(): success\n");
+       else
+               printk("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
        return cnt;
 }
 
@@ -1529,6 +1595,68 @@ static int dsp_mem_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbx1_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(void *arg)
+{
+       int status;
+
+       status = dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
+                           OMAP_DSP_MBCMD_FBCTL_UPD);
+       if (status < 0) {
+               /* FIXME: DSP is busy !! */
+               printk(KERN_ERR
+                      "omapdsp: DSP is busy when trying to send FBCTL:UPD "
+                      "response!\n");
+       }
+}
+
+static DECLARE_WORK(fbupd_response_work, (void (*)(void *))fbupd_response,
+                   NULL);
+
+static void fbupd_cb(void *arg)
+{
+       schedule_work(&fbupd_response_work);
+}
+
+void mbx1_fbctl_upd(void)
+{
+       struct omapfb_update_window win;
+       volatile unsigned short *buf = ipbuf_sys_da->d;
+
+       /* FIXME: try count sometimes exceeds 1000. */
+       if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 5000) < 0) {
+               printk(KERN_ERR "mbx: FBCTL:UPD - IPBUF sync failed!\n");
+               return;
+       }
+       win.x = buf[0];
+       win.y = buf[1];
+       win.width = buf[2];
+       win.height = buf[3];
+       win.format = buf[4];
+       release_ipbuf_pvt(ipbuf_sys_da);
+
+       if (!omapfb_ready) {
+               printk(KERN_WARNING
+                      "omapdsp: fbupd() called while HWA742 is not ready!\n");
+               return;
+       }
+       //printk("calling omapfb_update_window_async()\n");
+       omapfb_update_window_async(&win, fbupd_cb, NULL);
+}
+
+#else /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
+void mbx1_fbctl_upd(void)
+{
+}
+#endif /* CONFIG_FB_OMAP_LCDC_EXTERNAL */
+
 /*
  * sysfs files
  */
index 899573fe85f44439e9b78b9fe5ea7196073ad884..f466c4b5b2b889aaf420c7fe7c9b11cf2ebc15b3 100644 (file)
@@ -34,7 +34,6 @@
 
 /* #define OMAPFB_DBG 1 */
 
-#include "hwa742.h"
 #include "debug.h"
 
 #define MODULE_NAME                    "omapfb-hwa742"
@@ -159,13 +158,6 @@ static void hwa742_write_reg(u8 reg, u8 data)
        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];
@@ -471,10 +463,12 @@ int hwa742_update_window_async(struct omapfb_update_window *win,
        DBGENTER(2);
 
        if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {
+               DBGPRINT(1, "invalid update mode\n");
                r = -EINVAL;
                goto out;
        }
        if (unlikely(win->format & ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE))) {
+               DBGPRINT(1, "invalid window flag");
                r = -EINVAL;
                goto out;
        }
@@ -544,37 +538,13 @@ static void hwa742_sync(void)
        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)
+static void hwa742_bind_client(struct omapfb_notifier_block *nb)
 {
-       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);
+               omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
        }
-       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)
 {
@@ -597,9 +567,7 @@ static int hwa742_set_update_mode(enum omapfb_update_mode mode)
 
        switch (hwa742.update_mode) {
        case OMAPFB_MANUAL_UPDATE:
-               notifier_call_chain(&hwa742_client_list,
-                                   HWA742_EVENT_DISABLED,
-                                   hwa742.fbdev);
+               omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED);
                break;
        case OMAPFB_AUTO_UPDATE:
                hwa742.stop_auto_update = 1;
@@ -615,9 +583,7 @@ static int hwa742_set_update_mode(enum omapfb_update_mode mode)
 
        switch (mode) {
        case OMAPFB_MANUAL_UPDATE:
-               notifier_call_chain(&hwa742_client_list,
-                                   HWA742_EVENT_READY,
-                                   hwa742.fbdev);
+               omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
                break;
        case OMAPFB_AUTO_UPDATE:
                hwa742_update_window_auto(0);
@@ -915,6 +881,7 @@ struct lcd_ctrl hwa742_ctrl = {
        .name                   = "hwa742",
        .init                   = hwa742_init,
        .cleanup                = hwa742_cleanup,
+       .bind_client            = hwa742_bind_client,
        .get_caps               = hwa742_get_caps,
        .set_update_mode        = hwa742_set_update_mode,
        .get_update_mode        = hwa742_get_update_mode,
diff --git a/drivers/video/omap/hwa742.h b/drivers/video/omap/hwa742.h
deleted file mode 100644 (file)
index 7bbe63b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#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 fac072188eb0a50385f8c58da47f47bb78c880af..d32ba58ddd7041266173ae6548424bd1cb83de15 100644 (file)
@@ -67,6 +67,10 @@ static int           manual_update = 1;
 static int             manual_update;
 #endif
 
+static struct platform_device  *fbdev_pdev;
+static struct lcd_panel                *fbdev_panel;
+static struct omapfb_device    *omapfb_dev;
+
 static struct caps_table_struct {
         unsigned long flag;
         const char *name;
@@ -576,28 +580,52 @@ static int omapfb_set_par(struct fb_info *fbi)
        return r;
 }
 
-static int omapfb_update_win(struct omapfb_device *fbdev,
-                               struct omapfb_update_window *win)
+int omapfb_update_window_async(struct omapfb_update_window *win,
+                                       void (*callback)(void *),
+                                       void *callback_data)
 {
-       struct fb_var_screeninfo *var = &fbdev->fb_info->var;
-       int ret;
+       struct omapfb_device *fbdev = omapfb_dev;
+       struct fb_var_screeninfo *var;
+
+       DBGENTER(2);
+       if (fbdev == NULL) {
+               DBGPRINT(1, "no fbdev\n");
+               return -ENODEV;
+       }
+
+       var = &fbdev->fb_info->var;
 
-       if (win->x >= var->xres || win->y >= var->yres)
+       if (win->x >= var->xres || win->y >= var->yres) {
+               DBGPRINT(1, "invalid x %d, y %d\n", win->x, win->y);
                return -EINVAL;
+       }
 
        if (!fbdev->ctrl->update_window ||
-           fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
+           fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) {
+               DBGPRINT(1, "invalid update mode\n");
                return -ENODEV;
+       }
 
        if (win->x + win->width >= var->xres)
                win->width = var->xres - win->x;
        if (win->y + win->height >= var->yres)
                win->height = var->yres - win->y;
-       if (!win->width || !win->height)
+       if (!win->width || !win->height) {
+               DBGPRINT(1, "zero size window\n");
                return 0;
+       }
+
+       return fbdev->ctrl->update_window(win, callback, callback_data);
+}
+EXPORT_SYMBOL(omapfb_update_window_async);
+
+static int omapfb_update_win(struct omapfb_device *fbdev,
+                               struct omapfb_update_window *win)
+{
+       int ret;
 
        omapfb_rqueue_lock(fbdev);
-       ret = fbdev->ctrl->update_window(win, NULL, 0);
+       ret = omapfb_update_window_async(win, NULL, 0);
        omapfb_rqueue_unlock(fbdev);
 
        return ret;
@@ -659,6 +687,45 @@ static int omapfb_set_color_key(struct omapfb_device *fbdev,
        return r;
 }
 
+static struct notifier_block *omapfb_client_list;
+
+int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
+                           omapfb_notifier_callback_t callback,
+                           void *callback_data)
+{
+       int r;
+
+       DBGENTER(1);
+
+       omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
+                                       unsigned long, void *))callback;
+       omapfb_nb->data = callback_data;
+       r = notifier_chain_register(&omapfb_client_list, &omapfb_nb->nb);
+       if (r)
+               return r;
+       if (omapfb_dev != NULL &&
+           omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
+               omapfb_dev->ctrl->bind_client(omapfb_nb);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(omapfb_register_client);
+
+int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
+{
+       return notifier_chain_unregister(&omapfb_client_list,
+                                        &omapfb_nb->nb);
+}
+EXPORT_SYMBOL(omapfb_unregister_client);
+
+void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
+{
+       DBGENTER(1);
+       notifier_call_chain(&omapfb_client_list, event, fbdev);
+}
+EXPORT_SYMBOL(omapfb_notify_clients);
+
 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
                                   enum omapfb_update_mode mode)
 {
@@ -1291,6 +1358,8 @@ static int omapfb_do_probe(struct platform_device *pdev, struct lcd_panel *panel
        hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
        vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
 
+       omapfb_dev = fbdev;
+
        pr_info(MODULE_NAME ": initialized vram=%lu "
                        "pixclock %lu kHz hfreq %lu.%lu kHz vfreq %lu.%lu Hz\n",
                        fbdev->vram_size,
@@ -1306,9 +1375,6 @@ 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);
index 57bf4f39ca580db55612fca034381eb7e999c814..ec834b381586997759035db2940a19ed9b9f97b0 100644 (file)
@@ -182,6 +182,7 @@ struct omap_dsp_varinfo {
 
 #define OMAP_DSP_MBCMD_KFUNC_FBCTL     0x00
 
+#define OMAP_DSP_MBCMD_FBCTL_UPD       0x0000
 #define OMAP_DSP_MBCMD_FBCTL_ENABLE    0x0002
 #define OMAP_DSP_MBCMD_FBCTL_DISABLE   0x0003
 
index ffac7c0f827da55fa41bc90ab2280bcca244e815..3c3722ffbd421b24eeb3cdad575a4903fd4cacac 100644 (file)
@@ -215,6 +215,15 @@ struct lcd_ctrl_extif {
        unsigned long           max_transmit_size;
 };
 
+struct omapfb_notifier_block {
+       struct notifier_block   nb;
+       void                    *data;
+};
+
+typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
+                                          unsigned long event,
+                                          struct omapfb_device *fbdev);
+
 struct lcd_ctrl {
        const char      *name;
        void            *data;
@@ -222,6 +231,7 @@ struct lcd_ctrl {
        int             (*init)           (struct omapfb_device *fbdev,
                                           int ext_mode, int req_vram_size);
        void            (*cleanup)        (void);
+       void            (*bind_client)    (struct omapfb_notifier_block *nb);
        void            (*get_vram_layout)(unsigned long *size,
                                           void **virt_base,
                                           dma_addr_t *phys_base);
@@ -285,6 +295,9 @@ struct omapfb_platform_data {
        struct omap_fbmem_config fbmem;
 };
 
+#define OMAPFB_EVENT_READY     1
+#define OMAPFB_EVENT_DISABLED  2
+
 #ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl omap1_lcd_ctrl;
 #else
@@ -293,6 +306,15 @@ extern struct lcd_ctrl omap2_disp_ctrl;
 
 extern void omapfb_register_panel(struct lcd_panel *panel);
 extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
+extern void omapfb_notify_clients(struct omapfb_device *fbdev,
+                                 unsigned long event);
+extern int  omapfb_register_client(struct omapfb_notifier_block *nb,
+                                   omapfb_notifier_callback_t callback,
+                                   void *callback_data);
+extern int  omapfb_unregister_client(struct omapfb_notifier_block *nb);
+extern int  omapfb_update_window_async(struct omapfb_update_window *win,
+                                       void (*callback)(void *),
+                                       void *callback_data);
 
 /* in arch/arm/plat-omap/devices.c */
 extern void omapfb_reserve_mem(void);