/*
* 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;
#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
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;
"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;
}
#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;
/* 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;
}
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
*/
/* #define OMAPFB_DBG 1 */
-#include "hwa742.h"
#include "debug.h"
#define MODULE_NAME "omapfb-hwa742"
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];
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;
}
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)
{
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;
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);
.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,
+++ /dev/null
-#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
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;
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;
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)
{
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,
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);
#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
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;
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);
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
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);