From d13970fd2067e4a79c04d13f71b8d95bd7c9dee4 Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Tue, 21 Feb 2006 18:08:48 +0200 Subject: [PATCH] ARM: OMAP: Add external LCD controller support for DSP Gateway MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Juha Yrjölä --- arch/arm/plat-omap/dsp/dsp_core.c | 4 + arch/arm/plat-omap/dsp/dsp_mem.c | 128 +++++++++++++++++++++++++++++ drivers/video/omap/hwa742.c | 47 ++--------- drivers/video/omap/hwa742.h | 29 ------- drivers/video/omap/omapfb_main.c | 88 +++++++++++++++++--- include/asm-arm/arch-omap/dsp.h | 1 + include/asm-arm/arch-omap/omapfb.h | 22 +++++ 7 files changed, 239 insertions(+), 80 deletions(-) delete mode 100644 drivers/video/omap/hwa742.h diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c index f7aa2b8c962..a77216a454d 100644 --- a/arch/arm/plat-omap/dsp/dsp_core.c +++ b/arch/arm/plat-omap/dsp/dsp_core.c @@ -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; diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c index f41bad2ae90..109d9732c2d 100644 --- a/arch/arm/plat-omap/dsp/dsp_mem.c +++ b/arch/arm/plat-omap/dsp/dsp_mem.c @@ -46,9 +46,11 @@ #include #include #include +#include #include #include #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 */ diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 899573fe85f..f466c4b5b2b 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -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 index 7bbe63b4829..00000000000 --- a/drivers/video/omap/hwa742.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __HWA742_H -#define __HWA742_H - -#include - -#include - -#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 diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index fac072188eb..d32ba58ddd7 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -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); diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h index 57bf4f39ca5..ec834b38158 100644 --- a/include/asm-arm/arch-omap/dsp.h +++ b/include/asm-arm/arch-omap/dsp.h @@ -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 diff --git a/include/asm-arm/arch-omap/omapfb.h b/include/asm-arm/arch-omap/omapfb.h index ffac7c0f827..3c3722ffbd4 100644 --- a/include/asm-arm/arch-omap/omapfb.h +++ b/include/asm-arm/arch-omap/omapfb.h @@ -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); -- 2.41.3