diff --git a/arch/arm/mach-mx5/mx51_efikamx.c b/arch/arm/mach-mx5/mx51_efikamx.c index 45006897cd4..82acff656e3 100644 --- a/arch/arm/mach-mx5/mx51_efikamx.c +++ b/arch/arm/mach-mx5/mx51_efikamx.c @@ -287,10 +287,48 @@ static struct sys_timer mx51_efikamx_timer = { static void __init mx51_efikamx_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { + struct tag *mem_tag = 0; + int total_mem = SZ_512M; + int sys_mem = 0; + int fb_mem; + + /* + * a note on these sizes. we reserve enough memory to set up a framebuffer + * of maximum size for the platform, with triple buffer, at maximum + * reasonable bit depth. Since the Smartbook has a 16-bit LVDS interface + * the most reasonable depth is 16-bit, hence 1280x720-16 * 3 is ~6MB + * and we can get away with a minimal reservation of 8MB. For the Smarttop + * the maximum resolution is 1920x1080-32 * 3 which is just over 24MB and + * we reserve 32MB as it is a nice, round number + */ + + if (machine_is_mx51_efikasb()) { + fb_mem = SZ_8M; + } else if (machine_is_mx51_efikamx()) { + fb_mem = SZ_32M; + } + mxc_set_cpu_type(MXC_CPU_MX51); get_cpu_wp = mx51_efikamx_get_cpu_wp; set_num_cpu_wp = mx51_efikamx_set_num_cpu_wp; + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + break; + } + } + + if (fb_mem) { + sys_mem = total_mem - fb_mem; + + if (mem_tag) { + fb_mem = total_mem - fb_mem; + mem_tag->u.mem.size = sys_mem; + mx51_efikamx_display_adjust_mem(mem_tag->u.mem.start + sys_mem, fb_mem); + } + } } diff --git a/arch/arm/mach-mx5/mx51_efikamx.h b/arch/arm/mach-mx5/mx51_efikamx.h index a26294ef22a..21cb22c37e0 100644 --- a/arch/arm/mach-mx5/mx51_efikamx.h +++ b/arch/arm/mach-mx5/mx51_efikamx.h @@ -15,7 +15,8 @@ extern int mx51_efikamx_revision(void); -/* move to mx51_efikamx.h */ +extern void __init mx51_efikamx_display_adjust_mem(unsigned int start, unsigned int size); + extern void __init mx51_efikamx_io_init(void); extern int __init mx51_efikamx_init_mc13892(void); extern void __init mx51_efikamx_timer_init(void); diff --git a/arch/arm/mach-mx5/mx51_efikamx_display.c b/arch/arm/mach-mx5/mx51_efikamx_display.c index c8c2edf22ee..40819771079 100644 --- a/arch/arm/mach-mx5/mx51_efikamx_display.c +++ b/arch/arm/mach-mx5/mx51_efikamx_display.c @@ -41,6 +41,7 @@ #include "../../../drivers/video/mxc/siihdmi.h" + extern void mx5_ipu_reset(void); static struct mxc_ipu_config mxc_ipu_data = { .rev = 2, @@ -188,7 +189,17 @@ static char *mxcfb_clocks[] = { }; +static struct resource mx51_efikamx_fb_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; +void __init mx51_efikamx_display_adjust_mem(unsigned int start, unsigned int size) +{ + mx51_efikamx_fb_resources[0].start = start; + mx51_efikamx_fb_resources[0].end = start + size - 1; +} void __init mx51_efikamx_init_display(void) { @@ -252,14 +263,20 @@ void __init mx51_efikamx_init_display(void) * (DI0 on MX, DI1 on SB) first to make it the first framebuffer device. */ mxc_ipu_data.di_clk[display_id] = clk_get(NULL, mxcfb_clocks[display_id]); + + mxc_fb_devices[display_id].num_resources = ARRAY_SIZE(mx51_efikamx_fb_resources); + mxc_fb_devices[display_id].resource = mx51_efikamx_fb_resources; mxc_register_device(&mxc_fb_devices[display_id], &mx51_efikamx_display_data[display_id]); +#if defined(ANDROID_SUPPORT) /* register /dev/fb1 even though it's not used. We just register the other DI with the LVDS platform * data, since this is all it really needs to create the framebuffer, even though it just won't be - * used for anything + * used for anything. This actually won't work for now because there's some real weirdness about + * the preallocated memory and a second framebuffer in the same resource area (it has no idea how + * big the other framebuffer is..) */ mxc_register_device(&mxc_fb_devices[!display_id], &mx51_efikamx_display_data[EFIKASB_LVDS_DISPLAY_ID]); - +#endif /* video overlay, absolutely must be /dev/fb2 and therefore registered after TWO framebuffers otherwise * the v4l2sink doesn't work right. This is probably actually a major bug in userspace somewhere.. */ diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index bec388ea775..a970be7311c 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -75,6 +75,7 @@ struct mxcfb_info { void *alpha_virt_addr1; uint32_t alpha_mem_len; uint32_t ipu_ch_irq; + uint32_t ipu_alp_ch_irq; uint32_t cur_ipu_buf; uint32_t cur_ipu_alpha_buf; @@ -627,6 +628,13 @@ static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; + /* + * pad xres_virtual to 32 pixels to make it more suitable for + * gpu acceleration + */ + if (var->xres_virtual & 0x1f) + var->xres_virtual = (var->xres_virtual + 31) & ~31; + /* Default Y virtual size is 3*yres */ if (var->yres_virtual < (var->yres * 3)) var->yres_virtual = (var->yres * 3); @@ -1475,10 +1483,12 @@ static int mxcfb_resume(struct platform_device *pdev) */ static int mxcfb_map_video_memory(struct fb_info *fbi) { - if (fbi->fix.line_length == 0) fbi->fix.line_length = fbi->var.xres; + if (fbi->fix.line_length == 0) { + return -EINVAL; + } - fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length; - fbi->fix.smem_len = (fbi->fix.smem_len + SZ_1M - 1) & ~(SZ_1M - 1); + if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) + fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length; fbi->screen_base = dma_alloc_writecombine(fbi->device, fbi->fix.smem_len, @@ -1614,6 +1624,50 @@ static ssize_t swap_disp_chan(struct device *dev, } DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan); +static int mxcfb_setup(struct fb_info *fbi, struct platform_device *pdev) +{ + struct mxcfb_info *mxcfbi = (struct mxcfb_info *) fbi->par; + struct mxc_fb_platform_data *plat_data = pdev->dev.platform_data; + int ret = 0; + + /* default to 640x480@60 */ + fb_videomode_to_var(&fbi->var, &cea_modes[1]); + + if (plat_data && !mxcfbi->ipu_di_pix_fmt) { + mxcfbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt; +#if 0 + /* try and use a bit depth closest to the bit depth we use for the panel */ + if (!mxcfbi->default_bpp) + mxcfbi->default_bpp = pixfmt_to_bpp(plat_data->interface_pix_fmt); +#endif + } + + if (!mxcfbi->default_bpp) + mxcfbi->default_bpp = 16; + + if (plat_data && plat_data->mode && plat_data->num_modes) + fb_videomode_to_modelist(plat_data->mode, plat_data->num_modes, + &fbi->modelist); + + if (!mxcfbi->fb_mode_str && plat_data && plat_data->mode_str) + mxcfbi->fb_mode_str = plat_data->mode_str; + + if (mxcfbi->fb_mode_str) { + ret = fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, NULL, 0, NULL, + mxcfbi->default_bpp); + if ((!ret || (ret > 2)) && plat_data && plat_data->mode && plat_data->num_modes) + fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, plat_data->mode, + plat_data->num_modes, NULL, mxcfbi->default_bpp); + } + + + mxcfb_check_var(&fbi->var, fbi); + mxcfb_set_fix(fbi); + + return ret; +} + + /*! * Probe routine for the framebuffer driver. It is called during the * driver binding process. The following functions are performed in @@ -1626,7 +1680,7 @@ static int mxcfb_probe(struct platform_device *pdev) { struct fb_info *fbi; struct mxcfb_info *mxcfbi; - struct mxc_fb_platform_data *plat_data = pdev->dev.platform_data; + struct resource *res; char *options; char name[] = "mxcdi0fb"; int ret = 0; @@ -1659,6 +1713,7 @@ static int mxcfb_probe(struct platform_device *pdev) } mxcfbi->ipu_di = pdev->id; + mxcfbi->ipu_alp_ch_irq = -1; if (pdev->id == 0) { ipu_disp_set_global_alpha(mxcfbi->ipu_ch, true, 0x80); @@ -1666,30 +1721,17 @@ static int mxcfb_probe(struct platform_device *pdev) strcpy(fbi->fix.id, "DISP3 BG"); if (!g_dp_in_use) - if (ipu_request_irq(IPU_IRQ_BG_ALPHA_SYNC_EOF, - mxcfb_alpha_irq_handler, 0, - MXCFB_NAME, fbi) != 0) { - dev_err(&pdev->dev, "Error registering BG " - "alpha irq handler.\n"); - ret = -EBUSY; - goto err1; - } + mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF; g_dp_in_use = true; } else if (pdev->id == 1) { strcpy(fbi->fix.id, "DISP3 BG - DI1"); if (!g_dp_in_use) - if (ipu_request_irq(IPU_IRQ_BG_ALPHA_SYNC_EOF, - mxcfb_alpha_irq_handler, 0, - MXCFB_NAME, fbi) != 0) { - dev_err(&pdev->dev, "Error registering BG " - "alpha irq handler.\n"); - ret = -EBUSY; - goto err1; - } + mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF; g_dp_in_use = true; } else if (pdev->id == 2) { /* Overlay */ mxcfbi->ipu_ch_irq = IPU_IRQ_FG_SYNC_EOF; + mxcfbi->ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF; mxcfbi->ipu_ch = MEM_FG_SYNC; mxcfbi->ipu_di = -1; mxcfbi->overlay = true; @@ -1697,14 +1739,6 @@ static int mxcfb_probe(struct platform_device *pdev) strcpy(fbi->fix.id, "DISP3 FG"); - if (ipu_request_irq(IPU_IRQ_FG_ALPHA_SYNC_EOF, - mxcfb_alpha_irq_handler, 0, - MXCFB_NAME, fbi) != 0) { - dev_err(&pdev->dev, "Error registering FG alpha irq " - "handler.\n"); - ret = -EBUSY; - goto err1; - } } mxcfb_info[pdev->id] = fbi; @@ -1717,47 +1751,30 @@ static int mxcfb_probe(struct platform_device *pdev) } ipu_disable_irq(mxcfbi->ipu_ch_irq); - /* default to 640x480@60 */ - fb_videomode_to_var(&fbi->var, &cea_modes[1]); - - if (plat_data && !mxcfbi->ipu_di_pix_fmt) { - mxcfbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt; -#if 0 - /* try and use a bit depth closest to the bit depth we use for the panel */ - if (!mxcfbi->default_bpp) - mxcfbi->default_bpp = pixfmt_to_bpp(plat_data->interface_pix_fmt); -#endif + if (mxcfbi->ipu_alp_ch_irq != -1) { + if (ipu_request_irq(mxcfbi->ipu_alp_ch_irq, + mxcfb_alpha_irq_handler, 0, + MXCFB_NAME, fbi) != 0) { + dev_err(&pdev->dev, "Error registering alpha irq handler.\n"); + ret = -EBUSY; + goto err2; + } } - if (!mxcfbi->default_bpp) - mxcfbi->default_bpp = 16; - - if (plat_data && plat_data->mode && plat_data->num_modes) - fb_videomode_to_modelist(plat_data->mode, plat_data->num_modes, - &fbi->modelist); - - if (!mxcfbi->fb_mode_str && plat_data && plat_data->mode_str) - mxcfbi->fb_mode_str = plat_data->mode_str; - - if (mxcfbi->fb_mode_str) { - ret = fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, NULL, 0, NULL, - mxcfbi->default_bpp); - if ((!ret || (ret > 2)) && plat_data && plat_data->mode && plat_data->num_modes) - fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, plat_data->mode, - plat_data->num_modes, NULL, mxcfbi->default_bpp); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res && res->end) { + fbi->fix.smem_len = res->end - res->start + 1; + fbi->fix.smem_start = res->start; + fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len); } - mxcfb_check_var(&fbi->var, fbi); - - mxcfb_set_fix(fbi); - - /* allocate fb first */ - if (mxcfb_map_video_memory(fbi) < 0) - return -ENOMEM; + ret = mxcfb_setup(fbi, pdev); + if (ret < 0) + goto err3; ret = register_framebuffer(fbi); if (ret < 0) - goto err2; + goto err3; platform_set_drvdata(pdev, fbi); @@ -1767,6 +1784,9 @@ static int mxcfb_probe(struct platform_device *pdev) return 0; +err3: + if (mxcfbi->ipu_alp_ch_irq != -1) + ipu_free_irq(mxcfbi->ipu_alp_ch_irq, fbi); err2: ipu_free_irq(mxcfbi->ipu_ch_irq, fbi); err1: