From: Ziggy471 Date: Thu, 31 Mar 2011 11:43:01 +0000 (-0400) Subject: added HDMwIn v1.2.5, modified to accomodate none MSM HDMI devices X-Git-Url: https://ziggy471.com/git/gitweb.cgi?p=ziggy471-frankenstein-kernel.git;a=commitdiff;h=742ecca2daaf0f284d8077cdfb2c9c88d9914635 added HDMwIn v1.2.5, modified to accomodate none MSM HDMI devices --- --- a/drivers/video/msm/hdmi/fb-hdmi.c +++ b/drivers/video/msm/hdmi/fb-hdmi.c @@ -46,6 +46,8 @@ #define HDMI_DBG(s...) do {} while (0) #endif +#define BITS_PER_PIXEL 16 + struct update_info_t { int left; int top; @@ -68,6 +70,12 @@ struct hdmifb_info { int yres; unsigned long state; atomic_t use_count; + int vsyncMode; + int mirroring; + int doubleBuffering; + struct mdp_blit_req* vsyncBlitReq; + struct mdp_blit_req mirrorReq; + struct mirror_statistics mirror_stats; }; static struct mdp_device *mdp; @@ -88,6 +96,11 @@ static int hdmifb_release(struct fb_info return 0; } +static int hdmifb_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos) +{ + pr_info("%s\n", __func__); + return 0; +} static int hdmifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { u32 size; @@ -286,13 +299,143 @@ static int hdmifb_blit(struct fb_info *i if (copy_from_user(&req, &list->req[i], sizeof(req))) return -EFAULT; req.flags |= MDP_DITHER; - ret = mdp->blit(mdp, info, &req); + + /* Copy the requested blit in case we're mirroring */ + if (_hdmi_fb->mirroring) + { + memcpy(&_hdmi_fb->mirrorReq, &req, sizeof(struct mdp_blit_req)); + + /* Default double-buffering off */ + _hdmi_fb->doubleBuffering = 0; + + /* Are we rotating? */ + if ((req.flags & MDP_ROT_MASK) == MDP_ROT_90 || (req.flags & MDP_ROT_MASK) == MDP_ROT_270) + { + /* Are we scaling at the same time? */ + if (req.src_rect.w != req.dst_rect.w || req.src_rect.h != req.dst_rect.h) + { + _hdmi_fb->doubleBuffering = 1; + } + else + { + // Switch us back to buffer 0 + mdp->dma(mdp, _hdmi_fb->fb->fix.smem_start, _hdmi_fb->fb->var.xres * 2, + _hdmi_fb->fb->var.xres, _hdmi_fb->fb->var.yres, 0, 0, + &_hdmi_fb->dma_callback, _hdmi_fb->panel->interface_type); + } + } + } + + ret = mdp->blit(mdp, info, &req); if (ret) return ret; } return 0; } +void reportUnderflow(void) +{ + if (_hdmi_fb) _hdmi_fb->mirror_stats.underflows++; +} + +int hdmi_usePanelSync(void) +{ + if (_hdmi_fb->mirroring && + (_hdmi_fb->vsyncMode == VSYNC_NONE || _hdmi_fb->vsyncMode == VSYNC_HDMI_ONLY)) + return 0; + return 1; +} + +int hdmi_useHdmiSync(void) +{ + if (_hdmi_fb->mirroring && + (_hdmi_fb->vsyncMode == VSYNC_NONE || _hdmi_fb->vsyncMode == VSYNC_PANEL_ONLY)) + return 0; + return 1; +} + +void blit_on_vsync(struct mdp_blit_req* blitReq) +{ + struct msm_panel_data *panel = _hdmi_fb->panel; + + /* Request mirror blit and vsync callback */ + _hdmi_fb->vsyncBlitReq = blitReq; + panel->request_vsync(panel, &_hdmi_fb->vsync_callback); + return; +} + +void hdmi_DoBlit(int fb0Offset) +{ + int yoffset = 0; + + /* Always track frame counts, so we can measure FPS of panel-only mode */ + _hdmi_fb->mirror_stats.frames++; + + /* This handles the disabled case */ + if (_hdmi_fb->mirroring == 0 || _hdmi_fb->mirrorReq.src.width == 0) + return; + + /* Verify HDMI is enabled */ + if ((test_bit(fb_enabled, &_hdmi_fb->state) == 0) || + (test_bit(hdmi_enabled, &_hdmi_fb->state) == 0)) + return; + + /* Set the proper offsets */ + _hdmi_fb->mirrorReq.src.offset = fb0Offset; + + if (_hdmi_fb->doubleBuffering) + { + if (_hdmi_fb->mirrorReq.dst.offset == 0) + { + yoffset = _hdmi_fb->mirrorReq.dst.height; + _hdmi_fb->mirrorReq.dst.offset = yoffset * _hdmi_fb->mirrorReq.dst.width * BITS_PER_PIXEL / 8; + } + else + { + _hdmi_fb->mirrorReq.dst.offset = 0; + yoffset = 0; + } + } + else + { + if (_hdmi_fb->mirrorReq.dst.offset != 0) + { + // Force us back to the primary buffer + _hdmi_fb->mirrorReq.dst.offset = 0; + mdp->dma(mdp, _hdmi_fb->fb->fix.smem_start, _hdmi_fb->fb->var.xres * 2, + _hdmi_fb->fb->var.xres, _hdmi_fb->fb->var.yres, 0, 0, + &_hdmi_fb->dma_callback, _hdmi_fb->panel->interface_type); + } + } + + /* Either schedule the blit on vsync, or do it now */ + if (hdmi_useHdmiSync() && !_hdmi_fb->doubleBuffering) + { + blit_on_vsync(&_hdmi_fb->mirrorReq); + } + else + { + mdp->blit(mdp, _hdmi_fb->fb, &_hdmi_fb->mirrorReq); + } + + if (_hdmi_fb->doubleBuffering) + { + if (hdmi_useHdmiSync()) + { + hdmifb_pan_update(_hdmi_fb->fb, 0, 0, + _hdmi_fb->fb->var.xres, _hdmi_fb->fb->var.yres, yoffset); + } + else + { + mdp->dma(mdp, _hdmi_fb->mirrorReq.dst.offset + _hdmi_fb->fb->fix.smem_start, + _hdmi_fb->fb->var.xres * 2, _hdmi_fb->fb->var.xres, _hdmi_fb->fb->var.yres, 0, 0, + &_hdmi_fb->dma_callback, _hdmi_fb->panel->interface_type); + } + } + + return; +} + enum ioctl_cmd_index { CMD_SET_MODE, CMD_GET_MODE, @@ -304,6 +447,17 @@ enum ioctl_cmd_index { CMD_ESTABLISH_TIMING, }; +/*static char *cmd_str[] = { + "HDMI_SET_MODE", + "HDMI_GET_MODE", + "HDMI_DISABLE", + "HDMI_ENABLE", + "HDMI_GET_STATE", + "HDMI_BLIT", + "HDMI_CABLE_STAT", + "HDMI_ESTABLISH_TIMING", +};*/ + static int hdmifb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg) { struct hdmifb_info *hdmi_fb = p->par; @@ -324,6 +478,7 @@ static int hdmifb_ioctl(struct fb_info * get_user(val, (unsigned __user *) arg); //pr_info("[hdmi] SET_MODE: %d\n", val); ret = hdmifb_change_mode(p, val); + _hdmi_fb->mirroring = 0; break; case HDMI_GET_MODE: /* @@ -335,6 +490,7 @@ static int hdmifb_ioctl(struct fb_info * break; case HDMI_DISABLE: get_user(val, (unsigned __user *) arg); + _hdmi_fb->mirroring = 0; ret = hdmifb_pause(p, 1); break; case HDMI_ENABLE: @@ -384,6 +540,37 @@ static int hdmifb_ioctl(struct fb_info * &dinfo, sizeof(dinfo)); break; } + + case HDMI_GET_MIRRORING: + ret = put_user(hdmi_fb->mirroring, (unsigned __user *) arg); + break; + case HDMI_SET_MIRRORING: + get_user(val, (unsigned __user *) arg); + hdmi_fb->mirroring = val; + memset(&hdmi_fb->mirror_stats, 0, sizeof(struct mirror_statistics)); + hdmi_fb->mirror_stats.statisticsTime = ktime_to_ns(ktime_get()); + break; + case HDMI_GET_STATISTICS: + { + struct mirror_statistics temp; + + memcpy(&temp, &hdmi_fb->mirror_stats, sizeof(struct mirror_statistics)); + temp.statisticsTime = ktime_to_ns(ktime_get()) - hdmi_fb->mirror_stats.statisticsTime; + ret = copy_to_user((unsigned __user *) arg, &temp, sizeof(struct mirror_statistics)); + } + break; + case HDMI_CLEAR_STATISTICS: + memset(&hdmi_fb->mirror_stats, 0, sizeof(struct mirror_statistics)); + hdmi_fb->mirror_stats.statisticsTime = ktime_to_ns(ktime_get()); + break; + case HDMI_GET_VSYNC_MODE: + ret = put_user(hdmi_fb->vsyncMode, (unsigned __user *) arg); + break; + case HDMI_SET_VSYNC_MODE: + get_user(val, (unsigned __user *) arg); + hdmi_fb->vsyncMode = val; + ret = 0; + break; default: printk(KERN_ERR "hdmi: unknown cmd, cmd = %d\n", cmd); } @@ -401,6 +588,7 @@ static struct fb_ops hdmi_fb_ops = { .fb_copyarea = hdmifb_copyarea, .fb_imageblit = hdmifb_imageblit, .fb_ioctl = hdmifb_ioctl, + .fb_read = hdmifb_read, }; #ifdef CONFIG_HAS_EARLYSUSPEND @@ -443,8 +631,6 @@ static void hdmifb_resume(struct early_s } #endif -#define BITS_PER_PIXEL 16 - static void setup_fb_info(struct hdmifb_info *hdmi_fb) { struct fb_info *fb_info = hdmi_fb->fb; @@ -543,6 +729,14 @@ static void hdmi_handle_vsync(struct msm vsync_callback); struct msm_panel_data *panel = hdmi->panel; + /* Handle blitting requests */ + if (hdmi->vsyncBlitReq) + { + mdp->blit(mdp, _hdmi_fb->fb, hdmi->vsyncBlitReq); + hdmi->vsyncBlitReq = NULL; + return; + } + spin_lock_irqsave(&hdmi->update_lock, irq_flags); x = hdmi->update_info.left; y = hdmi->update_info.top; @@ -600,6 +794,9 @@ static int hdmifb_probe(struct platform_ if (!info) return -ENOMEM; + /* Zero out the structure before using it */ + memset(info, 0, sizeof(struct hdmifb_info)); + hdmi_fb = info->par; _hdmi_fb = hdmi_fb; hdmi_fb->fb = info; --- a/drivers/video/msm/hdmi/transmitter.c +++ b/drivers/video/msm/hdmi/transmitter.c @@ -381,7 +381,7 @@ static int hdmi_get_cable_state(struct h container_of(hdmi_device, struct hdmi_info, hdmi_dev); *connect = hdmi->cable_connected; #endif - HDMI_DBG("%s, state=%s\n", __func__, *connect ? "on" : "off" ); +// HDMI_DBG("%s, state=%s\n", __func__, *connect ? "on" : "off" ); return 0; } --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,13 @@ struct class *mdp_class; +/* Used to report LCDC underflows */ +#ifndef CONFIG_MSM_HDMI +void reportUnderflow(void) { return; } +#else +void reportUnderflow(void); +#endif + #define MDP_CMD_DEBUG_ACCESS_BASE (0x10000) static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue); @@ -141,6 +149,15 @@ static irqreturn_t mdp_isr(int irq, void // pr_info("%s: status=%08x (irq_mask=%08x)\n", __func__, status, // mdp_irq_mask); + +#ifdef CONFIG_MSM_HDMI + if (status & MDP_LCDC_UNDERFLOW) + { + pr_err("%s: LCDC Underflow\n", __func__); + reportUnderflow(); + } +#endif + status &= mdp_irq_mask; #ifdef CONFIG_MSM_MDP40 if (mdp->mdp_dev.overrides & MSM_MDP4_MDDI_DMA_SWITCH) { @@ -435,6 +452,20 @@ static int get_img(struct mdp_img *img, struct file *file; unsigned long vstart; +#ifdef CONFIG_MSM_HDMI + if (img->memory_id & 0x40000000) + { + struct fb_info *fb = registered_fb[img->memory_id & 0x0000FFFF]; + if (fb) + { + *start = fb->fix.smem_start; + *len = fb->fix.smem_len; + } + *filep = NULL; + return 0; + } +#endif + if (!get_pmem_file(img->memory_id, start, &vstart, len, filep)) return 0; else if (!get_msm_hw3d_file(img->memory_id, &img->offset, start, len, --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -33,11 +33,20 @@ #include #include #include +#include "mdp_hw.h" extern void start_drawing_late_resume(struct early_suspend *h); static void msmfb_resume_handler(struct early_suspend *h); static void msmfb_resume(struct work_struct *work); +#ifndef CONFIG_MSM_HDMI +void hdmi_DoBlit(int offset) { return; } +int hdmi_usePanelSync(void) { return 1; } +#else +void hdmi_DoBlit(int offset); +int hdmi_usePanelSync(void); +#endif + #define MSMFB_DEBUG 1 #ifdef CONFIG_FB_MSM_LOGO #define INIT_IMAGE_FILE "/logo.rle" @@ -397,19 +406,30 @@ restart: msmfb->yoffset); spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); - /* if the panel is all the way on wait for vsync, otherwise sleep - * for 16 ms (long enough for the dma to panel) and then begin dma */ - msmfb->vsync_request_time = ktime_get(); - if (panel->request_vsync && (sleeping == AWAKE)) { - wake_lock_timeout(&msmfb->idle_lock, HZ/4); - panel->request_vsync(panel, &msmfb->vsync_callback); + if (!hdmi_usePanelSync()) + { + msmfb->vsync_request_time = ktime_get(); + msmfb_start_dma(msmfb); } else { - if (!hrtimer_active(&msmfb->fake_vsync)) { - hrtimer_start(&msmfb->fake_vsync, - ktime_set(0, NSEC_PER_SEC/60), - HRTIMER_MODE_REL); + /* if the panel is all the way on wait for vsync, otherwise sleep + * for 16 ms (long enough for the dma to panel) and then begin dma */ + msmfb->vsync_request_time = ktime_get(); + if (panel->request_vsync && (sleeping == AWAKE)) { + wake_lock_timeout(&msmfb->idle_lock, HZ/4); + panel->request_vsync(panel, &msmfb->vsync_callback); + } else { + if (!hrtimer_active(&msmfb->fake_vsync)) { + hrtimer_start(&msmfb->fake_vsync, + ktime_set(0, NSEC_PER_SEC/60), + HRTIMER_MODE_REL); + } } } + + /* We did the DMA, now blit the data to the other display */ + hdmi_DoBlit(msmfb->xres * msmfb->yoffset * BYTES_PER_PIXEL(msmfb)); + + return; } static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top, --- a/include/linux/htc_hdmi.h +++ b/include/linux/htc_hdmi.h @@ -34,6 +34,13 @@ enum { #define HDMI_GET_EDID _IOR(HDMI_IOCTL_MAGIC, 9, unsigned) #define HDMI_GET_DISPLAY_INFO _IOR(HDMI_IOCTL_MAGIC, 10, unsigned) +#define HDMI_GET_MIRRORING _IOR(HDMI_IOCTL_MAGIC, 30, unsigned) +#define HDMI_SET_MIRRORING _IOW(HDMI_IOCTL_MAGIC, 31, unsigned) +#define HDMI_GET_STATISTICS _IOR(HDMI_IOCTL_MAGIC, 32, unsigned) +#define HDMI_CLEAR_STATISTICS _IOW(HDMI_IOCTL_MAGIC, 33, unsigned) +#define HDMI_GET_VSYNC_MODE _IOR(HDMI_IOCTL_MAGIC, 34, unsigned) +#define HDMI_SET_VSYNC_MODE _IOW(HDMI_IOCTL_MAGIC, 35, unsigned) + #define ASPECT(w, h) (w << 8 | h) struct video_mode { unsigned short width, height, refresh_rate, aspect; @@ -47,10 +54,25 @@ enum { }; struct display_info { - unsigned int visible_width; /* in mm */ - unsigned int visible_height; - unsigned int resolution_width; /* in pixel */ - unsigned int resolution_height; + unsigned int visible_width; /* in mm */ + unsigned int visible_height; + unsigned int resolution_width; /* in pixel */ + unsigned int resolution_height; +}; + +/* Gathered statistics for mirroring */ +struct mirror_statistics { + unsigned int frames; /* Number of panel frames requested */ + unsigned int underflows; /* Number of times we underflowed the LCDC */ + s64 statisticsTime; /* Mirror time, in ns */ +}; + +/* Panel state while mirroring */ +enum { + VSYNC_ALL = 0, + VSYNC_PANEL_ONLY, + VSYNC_HDMI_ONLY, + VSYNC_NONE }; #endif