diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-08-30 16:37:48 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-08-30 16:37:48 +0800 |
commit | a4d0bf3916d2f75a2977869e804d5f4fff4d1d3e (patch) | |
tree | 75c1f9f8074170da088e685b03bc40e0de67fe8b /drivers | |
parent | 65745dd4b7f80711d03dce5529fc501162428c53 (diff) | |
parent | 4d38f38359c287d1000bbef7731a03e32b8d9ca2 (diff) |
Merge remote branch 'fsl-linux-sdk/imx_3.0.35_12.09.01' into imx_3.0.35_android
Conflicts:
arch/arm/mach-mx6/board-mx6q_sabresd.c
arch/arm/mach-mx6/board-mx6sl_arm2.c
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/cpu_op-mx6.c
arch/arm/plat-mxc/cpufreq.c
Diffstat (limited to 'drivers')
23 files changed, 865 insertions, 278 deletions
diff --git a/drivers/dma/pxp/pxp_dma_v2.c b/drivers/dma/pxp/pxp_dma_v2.c index ceb72edbd39e..87b8f558ae8c 100644 --- a/drivers/dma/pxp/pxp_dma_v2.c +++ b/drivers/dma/pxp/pxp_dma_v2.c @@ -339,7 +339,14 @@ static void pxp_set_outbuf(struct pxps *pxp) BF_PXP_OUT_LRC_Y(out_params->height - 1), pxp->base + HW_PXP_OUT_LRC); - __raw_writel(out_params->stride, pxp->base + HW_PXP_OUT_PITCH); + if (out_params->pixel_fmt == PXP_PIX_FMT_RGB24) + __raw_writel(out_params->stride << 2, + pxp->base + HW_PXP_OUT_PITCH); + else if (out_params->pixel_fmt == PXP_PIX_FMT_RGB565) + __raw_writel(out_params->stride << 1, + pxp->base + HW_PXP_OUT_PITCH); + else + __raw_writel(out_params->stride, pxp->base + HW_PXP_OUT_PITCH); } static void pxp_set_s0colorkey(struct pxps *pxp) @@ -390,6 +397,13 @@ static void pxp_set_oln(int layer_no, struct pxps *pxp) __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->width) | BF_PXP_OUT_AS_LRC_Y(olparams_data->height), pxp->base + HW_PXP_OUT_AS_LRC); + + if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB24) + __raw_writel(olparams_data->width << 2, + pxp->base + HW_PXP_AS_PITCH); + else + __raw_writel(olparams_data->width << 1, + pxp->base + HW_PXP_AS_PITCH); } static void pxp_set_olparam(int layer_no, struct pxps *pxp) @@ -704,8 +718,9 @@ static void pxp_set_s0buf(struct pxps *pxp) __raw_writel(V, pxp->base + HW_PXP_PS_VBUF); } - /* TODO: only support RGB565, Y8, Y4 */ - if (s0_params->pixel_fmt == PXP_PIX_FMT_GREY) + /* TODO: only support RGB565, Y8, Y4, YUV420 */ + if (s0_params->pixel_fmt == PXP_PIX_FMT_GREY || + s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P) __raw_writel(s0_params->width, pxp->base + HW_PXP_PS_PITCH); else if (s0_params->pixel_fmt == PXP_PIX_FMT_GY04) __raw_writel(s0_params->width >> 1, pxp->base + HW_PXP_PS_PITCH); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index a01553aa0ffc..e0b1633ef218 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -651,7 +651,7 @@ config VIDEO_MXS_PXP config VIDEO_MXC_PXP_V4L2 tristate "MXC PxP V4L2 driver" - depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MX5 + depends on VIDEO_DEV && VIDEO_V4L2 && (ARCH_MX5 || SOC_IMX6SL) select VIDEOBUF_DMA_CONTIG ---help--- This is a video4linux driver for the Freescale PxP diff --git a/drivers/media/video/mxc/capture/Makefile b/drivers/media/video/mxc/capture/Makefile index 04b715352886..bdef5b401485 100644 --- a/drivers/media/video/mxc/capture/Makefile +++ b/drivers/media/video/mxc/capture/Makefile @@ -1,7 +1,7 @@ ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y) obj-$(CONFIG_VIDEO_MXC_CAMERA) += mxc_v4l2_capture.o obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o - obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_prp_vf_sdc_bg.o + obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o endif diff --git a/drivers/media/video/mxc/capture/ipu_bg_overlay_sdc.c b/drivers/media/video/mxc/capture/ipu_bg_overlay_sdc.c new file mode 100644 index 000000000000..1a0229720640 --- /dev/null +++ b/drivers/media/video/mxc/capture/ipu_bg_overlay_sdc.c @@ -0,0 +1,551 @@ + +/* + * Copyright 2004-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_bg_overlay_sdc_bg.c + * + * @brief IPU Use case for PRP-VF back-ground + * + * @ingroup IPU + */ +#include <linux/dma-mapping.h> +#include <linux/fb.h> +#include <linux/ipu.h> +#include <mach/mipi_csi2.h> +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +static int csi_buffer_num; +static u32 bpp, csi_mem_bufsize = 3; +static u32 out_format; +static struct ipu_soc *disp_ipu; +static u32 offset; + +static void csi_buf_work_func(struct work_struct *work) +{ + int err = 0; + cam_data *cam = + container_of(work, struct _cam_data, csi_work_struct); + + struct ipu_task task; + memset(&task, 0, sizeof(task)); + + if (csi_buffer_num) + task.input.paddr = cam->vf_bufs[0]; + else + task.input.paddr = cam->vf_bufs[1]; + task.input.width = cam->crop_current.width; + task.input.height = cam->crop_current.height; + task.input.format = IPU_PIX_FMT_UYVY; + + task.output.paddr = offset; + task.output.width = cam->overlay_fb->var.xres; + task.output.height = cam->overlay_fb->var.yres; + task.output.format = out_format; + task.output.rotate = cam->rotation; + task.output.crop.pos.x = cam->win.w.left; + task.output.crop.pos.y = cam->win.w.top; + if (cam->win.w.width > 1024 || cam->win.w.height > 1024) { + task.output.crop.w = cam->overlay_fb->var.xres; + task.output.crop.h = cam->overlay_fb->var.yres; + } else { + task.output.crop.w = cam->win.w.width; + task.output.crop.h = cam->win.w.height; + } +again: + err = ipu_check_task(&task); + if (err != IPU_CHECK_OK) { + if (err > IPU_CHECK_ERR_MIN) { + if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) { + task.input.crop.w -= 8; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) { + task.input.crop.h -= 8; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { + task.output.width -= 8; + task.output.crop.w = task.output.width; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { + task.output.height -= 8; + task.output.crop.h = task.output.height; + goto again; + } + printk(KERN_ERR "check ipu taks fail\n"); + return; + } + printk(KERN_ERR "check ipu taks fail\n"); + return; + } + err = ipu_queue_task(&task); + if (err < 0) + printk(KERN_ERR "queue ipu task error\n"); +} + +static void get_disp_ipu(cam_data *cam) +{ + if (cam->output > 2) + disp_ipu = ipu_get_soc(1); /* using DISP4 */ + else + disp_ipu = ipu_get_soc(0); +} + + +/*! + * csi ENC callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t csi_enc_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + + ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num); + schedule_work(&cam->csi_work_struct); + csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0; + return IRQ_HANDLED; +} + +static int csi_enc_setup(cam_data *cam) +{ + ipu_channel_params_t params; + u32 pixel_fmt; + int err = 0, sensor_protocol = 0; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (!cam) { + printk(KERN_ERR "cam private is NULL\n"); + return -ENXIO; + } + + memset(¶ms, 0, sizeof(ipu_channel_params_t)); + params.csi_mem.csi = cam->csi; + + sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); + switch (sensor_protocol) { + case IPU_CSI_CLK_MODE_GATED_CLK: + case IPU_CSI_CLK_MODE_NONGATED_CLK: + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: + params.csi_mem.interlaced = false; + break; + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: + params.csi_mem.interlaced = true; + break; + default: + printk(KERN_ERR "sensor protocol unsupported\n"); + return -EINVAL; + } + + ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_ENC, cam->csi, true, true); + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + params.csi_mem.mipi_en = true; + params.csi_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + params.csi_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } else { + printk(KERN_ERR "Fail to get mipi_csi2_info!\n"); + return -EPERM; + } +#endif + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + } + csi_mem_bufsize = cam->crop_current.width * cam->crop_current.height * 2; + cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize); + cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[0], + (dma_addr_t *) & + cam->vf_bufs[0], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[0] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_2; + } + cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize); + cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[1], + (dma_addr_t *) & + cam->vf_bufs[1], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[1] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_1; + } + pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); + + err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms); + if (err != 0) { + printk(KERN_ERR "ipu_init_channel %d\n", err); + goto out_1; + } + + pixel_fmt = IPU_PIX_FMT_UYVY; + err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, + pixel_fmt, cam->crop_current.width, + cam->crop_current.height, + cam->crop_current.width, IPU_ROTATE_NONE, + cam->vf_bufs[0], cam->vf_bufs[1], 0, + cam->offset.u_offset, cam->offset.u_offset); + if (err != 0) { + printk(KERN_ERR "CSI_MEM output buffer\n"); + goto out_1; + } + err = ipu_enable_channel(cam->ipu, CSI_MEM); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); + goto out_1; + } + + csi_buffer_num = 0; + + ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1); + return err; +out_1: + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } +out_2: + return err; +} + +/*! + * Enable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_enabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF); + err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, + csi_enc_callback, 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n"); + return err; + } + + INIT_WORK(&cam->csi_work_struct, csi_buf_work_func); + + err = csi_enc_setup(cam); + if (err != 0) { + printk(KERN_ERR "csi_enc_setup %d\n", err); + goto out1; + } + + return err; +out1: + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); + return err; +} + +/*! + * bg_overlay_start - start the overlay task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int bg_overlay_start(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + if (!cam) { + printk(KERN_ERR "private is NULL\n"); + return -EIO; + } + + if (cam->overlay_active == true) { + pr_debug("already start.\n"); + return 0; + } + + get_disp_ipu(cam); + + out_format = cam->v4l2_fb.fmt.pixelformat; + if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) { + bpp = 3, csi_mem_bufsize = 3; + pr_info("BGR24\n"); + } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) { + bpp = 2, csi_mem_bufsize = 2; + pr_info("RGB565\n"); + } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) { + bpp = 4, csi_mem_bufsize = 4; + pr_info("BGR32\n"); + } else { + printk(KERN_ERR + "unsupported fix format from the framebuffer.\n"); + return -EINVAL; + } + + offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top + + csi_mem_bufsize * cam->win.w.left; + + if (cam->v4l2_fb.base == 0) { + printk(KERN_ERR "invalid frame buffer address.\n"); + } else { + offset += (u32) cam->v4l2_fb.base; + } + + csi_mem_bufsize = cam->win.w.width * cam->win.w.height * csi_mem_bufsize; + + err = csi_enc_enabling_tasks(cam); + if (err != 0) { + printk(KERN_ERR "Error csi enc enable fail\n"); + return err; + } + + cam->overlay_active = true; + return err; +} + +/*! + * bg_overlay_stop - stop the overlay task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int bg_overlay_stop(void *private) +{ + int err = 0; + cam_data *cam = (cam_data *) private; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (cam->overlay_active == false) + return 0; + + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); + + err = ipu_disable_channel(cam->ipu, CSI_MEM, true); + + ipu_uninit_channel(cam->ipu, CSI_MEM); + + csi_buffer_num = 0; + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } else { + printk(KERN_ERR "Fail to get mipi_csi2_info!\n"); + return -EPERM; + } +#endif + + flush_work_sync(&cam->csi_work_struct); + cancel_work_sync(&cam->csi_work_struct); + ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_VF, cam->csi, false, false); + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } + if (cam->rot_vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->rot_vf_buf_size[0], + cam->rot_vf_bufs_vaddr[0], + cam->rot_vf_bufs[0]); + cam->rot_vf_bufs_vaddr[0] = NULL; + cam->rot_vf_bufs[0] = 0; + } + if (cam->rot_vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_vf_buf_size[1], + cam->rot_vf_bufs_vaddr[1], + cam->rot_vf_bufs[1]); + cam->rot_vf_bufs_vaddr[1] = NULL; + cam->rot_vf_bufs[1] = 0; + } + + cam->overlay_active = false; + return err; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int bg_overlay_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int bg_overlay_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select bg as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int bg_overlay_sdc_select(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->vf_start_sdc = bg_overlay_start; + cam->vf_stop_sdc = bg_overlay_stop; + cam->vf_enable_csi = bg_overlay_enable_csi; + cam->vf_disable_csi = bg_overlay_disable_csi; + cam->overlay_active = false; + } + + return 0; +} + +/*! + * function to de-select bg as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int bg_overlay_sdc_deselect(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->vf_start_sdc = NULL; + cam->vf_stop_sdc = NULL; + cam->vf_enable_csi = NULL; + cam->vf_disable_csi = NULL; + } + return 0; +} + +/*! + * Init background overlay task. + * + * @return Error code indicating success or failure + */ +__init int bg_overlay_sdc_init(void) +{ + return 0; +} + +/*! + * Deinit background overlay task. + * + * @return Error code indicating success or failure + */ +void __exit bg_overlay_sdc_exit(void) +{ +} + +module_init(bg_overlay_sdc_init); +module_exit(bg_overlay_sdc_exit); + +EXPORT_SYMBOL(bg_overlay_sdc_select); +EXPORT_SYMBOL(bg_overlay_sdc_deselect); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c b/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c index 05c88c7d409b..312462ac60e0 100644 --- a/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c +++ b/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c @@ -508,6 +508,8 @@ static int foreground_stop(void *private) } #endif + flush_work_sync(&cam->csi_work_struct); + cancel_work_sync(&cam->csi_work_struct); ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_VF, cam->csi, false, false); if (cam->vf_bufs_vaddr[0]) { diff --git a/drivers/media/video/mxc/capture/ipu_prp_sw.h b/drivers/media/video/mxc/capture/ipu_prp_sw.h index 7cdc521711cb..cba47baa4abe 100644 --- a/drivers/media/video/mxc/capture/ipu_prp_sw.h +++ b/drivers/media/video/mxc/capture/ipu_prp_sw.h @@ -29,12 +29,14 @@ int prp_enc_deselect(void *private); #ifdef CONFIG_MXC_IPU_PRP_VF_SDC int prp_vf_sdc_select(void *private); int prp_vf_sdc_deselect(void *private); +int prp_vf_sdc_select_bg(void *private); +int prp_vf_sdc_deselect_bg(void *private); #else int foreground_sdc_select(void *private); int foreground_sdc_deselect(void *private); +int bg_overlay_sdc_select(void *private); +int bg_overlay_sdc_deselect(void *private); #endif -int prp_vf_sdc_select_bg(void *private); -int prp_vf_sdc_deselect_bg(void *private); int prp_still_select(void *private); int prp_still_deselect(void *private); diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c index bddfee530274..423575c9d881 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c @@ -655,7 +655,11 @@ static int start_preview(cam_data *cam) err = foreground_sdc_select(cam); #endif else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC err = prp_vf_sdc_select_bg(cam); + #else + err = bg_overlay_sdc_select(cam); + #endif if (err != 0) return err; @@ -714,7 +718,11 @@ static int stop_preview(cam_data *cam) err = foreground_sdc_deselect(cam); #endif else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC err = prp_vf_sdc_deselect_bg(cam); + #else + err = bg_overlay_sdc_deselect(cam); + #endif return err; } diff --git a/drivers/media/video/mxc/capture/ov5642.c b/drivers/media/video/mxc/capture/ov5642.c index 245a92c15ef1..492748c6cac4 100644 --- a/drivers/media/video/mxc/capture/ov5642.c +++ b/drivers/media/video/mxc/capture/ov5642.c @@ -3228,6 +3228,7 @@ err: static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, enum ov5642_mode mode) { + int ret = 0; bool m_60Hz = false; u16 capture_frame_rate = 50; u16 g_preview_frame_rate = 225; @@ -3255,7 +3256,10 @@ static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, gain = 0; ov5642_read_reg(0x350b, &gain); - ov5642_init_mode(frame_rate, mode); + ret = ov5642_init_mode(frame_rate, mode); + if (ret < 0) + return ret; + ret_h = ret_m = ret_l = 0; ov5642_read_reg(0x380e, &ret_h); ov5642_read_reg(0x380f, &ret_l); @@ -3331,7 +3335,7 @@ static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, ov5642_write_reg(0x3500, exposure_high); msleep(500); - return 0; + return ret ; } diff --git a/drivers/media/video/mxc/output/mxc_pxp_v4l2.c b/drivers/media/video/mxc/output/mxc_pxp_v4l2.c index a26b5d918a26..a3a8294efb8e 100644 --- a/drivers/media/video/mxc/output/mxc_pxp_v4l2.c +++ b/drivers/media/video/mxc/output/mxc_pxp_v4l2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -254,10 +254,12 @@ static int pxp_set_fbinfo(struct pxps *pxp) fb->fmt.width = fbi->var.xres; fb->fmt.height = fbi->var.yres; + pxp->pxp_conf.out_param.stride = fbi->var.xres; if (fbi->var.bits_per_pixel == 16) fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565; else fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24; + fb->base = (void *)fbi->fix.smem_start; return 0; @@ -293,9 +295,9 @@ static int set_fb_blank(int blank) if (err) return err; - acquire_console_sem(); + console_lock(); fb_blank(fbi, blank); - release_console_sem(); + console_unlock(); return err; } @@ -679,7 +681,7 @@ static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf) * This waits until this buffer is out of danger, i.e., until it is no * longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vb, 0, 0); + videobuf_waiton(q, vb, 0, 0); if (txd) async_tx_ack(txd); @@ -710,7 +712,7 @@ static int pxp_buf_prepare(struct videobuf_queue *q, if (vb->state == VIDEOBUF_NEEDS_INIT) { struct pxp_channel *pchan = pxp->pxp_channel[0]; - struct scatterlist *sg = &buf->sg; + struct scatterlist *sg = &buf->sg[0]; /* This actually (allocates and) maps buffers */ ret = videobuf_iolock(q, vb, NULL); @@ -1055,7 +1057,8 @@ out: V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_FIELD_NONE, sizeof(struct pxp_buffer), - pxp); + pxp, + NULL); dev_dbg(&pxp->pdev->dev, "call pxp_open\n"); return 0; diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c index 4b3617f89b08..366d27a92286 100644 --- a/drivers/media/video/mxc/output/mxc_vout.c +++ b/drivers/media/video/mxc/output/mxc_vout.c @@ -244,7 +244,7 @@ static int alloc_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf) { buf->vaddr = dma_alloc_coherent(vout->vbq.dev, buf->size, &buf->paddr, - GFP_KERNEL); + GFP_DMA | GFP_KERNEL); if (!buf->vaddr) { v4l2_err(vout->vfd->v4l2_dev, "cannot get dma buf size:0x%x\n", buf->size); diff --git a/drivers/mfd/mxc-hdmi-core.c b/drivers/mfd/mxc-hdmi-core.c index 332843661d98..e9322477ff6d 100644 --- a/drivers/mfd/mxc-hdmi-core.c +++ b/drivers/mfd/mxc-hdmi-core.c @@ -63,6 +63,104 @@ int mxc_hdmi_disp_id; static struct mxc_edid_cfg hdmi_core_edid_cfg; static int hdmi_core_init; static unsigned int hdmi_dma_running; +static struct snd_pcm_substream *hdmi_audio_stream_playback; +static unsigned int hdmi_cable_state; +static unsigned int hdmi_blank_state; +static spinlock_t hdmi_audio_lock, hdmi_blank_state_lock, hdmi_cable_state_lock; + + +unsigned int hdmi_set_cable_state(unsigned int state) +{ + unsigned long flags; + + spin_lock_irqsave(&hdmi_cable_state_lock, flags); + hdmi_cable_state = state; + spin_unlock_irqrestore(&hdmi_cable_state_lock, flags); + + return 0; +} + +unsigned int hdmi_set_blank_state(unsigned int state) +{ + unsigned long flags; + + spin_lock_irqsave(&hdmi_blank_state_lock, flags); + hdmi_blank_state = state; + spin_unlock_irqrestore(&hdmi_blank_state_lock, flags); + + return 0; +} + +static void hdmi_audio_abort_stream(struct snd_pcm_substream *substream) +{ + unsigned long flags; + + snd_pcm_stream_lock_irqsave(substream, flags); + + if (snd_pcm_running(substream)) + snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + + snd_pcm_stream_unlock_irqrestore(substream, flags); +} + +int mxc_hdmi_abort_stream(void) +{ + unsigned long flags; + spin_lock_irqsave(&hdmi_audio_lock, flags); + if (hdmi_audio_stream_playback) + hdmi_audio_abort_stream(hdmi_audio_stream_playback); + spin_unlock_irqrestore(&hdmi_audio_lock, flags); + + return 0; +} + +static int check_hdmi_state(void) +{ + unsigned long flags1, flags2; + unsigned int ret; + + spin_lock_irqsave(&hdmi_cable_state_lock, flags1); + spin_lock_irqsave(&hdmi_blank_state_lock, flags2); + + ret = hdmi_cable_state && hdmi_blank_state; + + spin_unlock_irqrestore(&hdmi_blank_state_lock, flags2); + spin_unlock_irqrestore(&hdmi_cable_state_lock, flags1); + + return ret; +} + +int mxc_hdmi_register_audio(struct snd_pcm_substream *substream) +{ + unsigned long flags, flags1; + int ret = 0; + + snd_pcm_stream_lock_irqsave(substream, flags); + + if (substream && check_hdmi_state()) { + spin_lock_irqsave(&hdmi_audio_lock, flags1); + if (hdmi_audio_stream_playback) { + pr_err("%s unconsist hdmi auido stream!\n", __func__); + ret = -EINVAL; + } + hdmi_audio_stream_playback = substream; + spin_unlock_irqrestore(&hdmi_audio_lock, flags1); + } else + ret = -EINVAL; + + snd_pcm_stream_unlock_irqrestore(substream, flags); + + return ret; +} + +void mxc_hdmi_unregister_audio(struct snd_pcm_substream *substream) +{ + unsigned long flags; + + spin_lock_irqsave(&hdmi_audio_lock, flags); + hdmi_audio_stream_playback = NULL; + spin_unlock_irqrestore(&hdmi_audio_lock, flags); +} u8 hdmi_readb(unsigned int reg) { @@ -466,6 +564,7 @@ static int mxc_hdmi_core_probe(struct platform_device *pdev) struct fsl_mxc_hdmi_core_platform_data *pdata = pdev->dev.platform_data; struct mxc_hdmi_data *hdmi_data; struct resource *res; + unsigned long flags; int ret = 0; #ifdef DEBUG @@ -495,6 +594,23 @@ static int mxc_hdmi_core_probe(struct platform_device *pdev) spin_lock_init(&irq_spinlock); spin_lock_init(&edid_spinlock); + + spin_lock_init(&hdmi_cable_state_lock); + spin_lock_init(&hdmi_blank_state_lock); + spin_lock_init(&hdmi_audio_lock); + + spin_lock_irqsave(&hdmi_cable_state_lock, flags); + hdmi_cable_state = 0; + spin_unlock_irqrestore(&hdmi_cable_state_lock, flags); + + spin_lock_irqsave(&hdmi_blank_state_lock, flags); + hdmi_blank_state = 0; + spin_unlock_irqrestore(&hdmi_blank_state_lock, flags); + + spin_lock_irqsave(&hdmi_audio_lock, flags); + hdmi_audio_stream_playback = NULL; + spin_unlock_irqrestore(&hdmi_audio_lock, flags); + isfr_clk = clk_get(&hdmi_data->pdev->dev, "hdmi_isfr_clk"); if (IS_ERR(isfr_clk)) { ret = PTR_ERR(isfr_clk); diff --git a/drivers/mxc/asrc/mxc_asrc.c b/drivers/mxc/asrc/mxc_asrc.c index cf41f2994226..62d7ceb0e04f 100644 --- a/drivers/mxc/asrc/mxc_asrc.c +++ b/drivers/mxc/asrc/mxc_asrc.c @@ -316,22 +316,22 @@ int asrc_req_pair(int chn_num, enum asrc_pair_index *index) spin_lock_irqsave(&data_lock, lock_flags); if (chn_num > 2) { - pair = &g_asrc->asrc_pair[ASRC_PAIR_C]; + pair = &g_asrc->asrc_pair[ASRC_PAIR_B]; if (pair->active || (chn_num > pair->chn_max)) err = -EBUSY; else { - *index = ASRC_PAIR_C; + *index = ASRC_PAIR_B; pair->chn_num = chn_num; pair->active = 1; } } else { pair = &g_asrc->asrc_pair[ASRC_PAIR_A]; if (pair->active || (pair->chn_max == 0)) { - pair = &g_asrc->asrc_pair[ASRC_PAIR_B]; + pair = &g_asrc->asrc_pair[ASRC_PAIR_C]; if (pair->active || (pair->chn_max == 0)) err = -EBUSY; else { - *index = ASRC_PAIR_B; + *index = ASRC_PAIR_C; pair->chn_num = 2; pair->active = 1; } @@ -583,17 +583,23 @@ int asrc_config_pair(struct asrc_config *config) } } - if ((config->inclk == INCLK_ASRCK1_CLK) && + if ((config->inclk == INCLK_NONE) && (config->outclk == OUTCLK_ESAI_TX)) { reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCTR_REG); - reg |= (1 << (20 + config->pair)); - reg |= (0x02 << (13 + (config->pair << 1))); + reg &= ~(1 << (20 + config->pair)); + reg |= (0x03 << (13 + (config->pair << 1))); __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCTR_REG); err = asrc_set_clock_ratio(config->pair, config->input_sample_rate, config->output_sample_rate); if (err < 0) return err; + err = asrc_set_process_configuration(config->pair, + config->input_sample_rate, + config-> + output_sample_rate); + if (err < 0) + return err; } /* Config input and output wordwidth */ @@ -667,12 +673,6 @@ void asrc_start_conv(enum asrc_pair_index index) __raw_writel(reg, g_asrc->vaddr + ASRC_ASRDIA_REG + (index << 3)); - __raw_writel(reg, - g_asrc->vaddr + ASRC_ASRDIA_REG + - (index << 3)); - __raw_writel(reg, - g_asrc->vaddr + ASRC_ASRDIA_REG + - (index << 3)); } __raw_writel(0x40, g_asrc->vaddr + ASRC_ASRIER_REG); @@ -813,9 +813,9 @@ static int mxc_init_asrc(void) /* Enable overflow interrupt */ __raw_writel(0x00, g_asrc->vaddr + ASRC_ASRIER_REG); - /* Default 6: 2: 2 channel assignment */ - __raw_writel((0x06 << g_asrc->mxc_asrc_data->channel_bits * - 2) | (0x02 << g_asrc->mxc_asrc_data->channel_bits) | 0x02, + /* Default 2: 6: 2 channel assignment */ + __raw_writel((0x02 << g_asrc->mxc_asrc_data->channel_bits * + 2) | (0x06 << g_asrc->mxc_asrc_data->channel_bits) | 0x02, g_asrc->vaddr + ASRC_ASRCNCR_REG); /* Parameter Registers recommended settings */ @@ -1696,8 +1696,8 @@ static int mxc_asrc_probe(struct platform_device *pdev) g_asrc->dev->coherent_dma_mask = DMA_BIT_MASK(32); g_asrc->asrc_pair[0].chn_max = 2; - g_asrc->asrc_pair[1].chn_max = 2; - g_asrc->asrc_pair[2].chn_max = 6; + g_asrc->asrc_pair[1].chn_max = 6; + g_asrc->asrc_pair[2].chn_max = 2; g_asrc->asrc_pair[0].overload_error = 0; g_asrc->asrc_pair[1].overload_error = 0; g_asrc->asrc_pair[2].overload_error = 0; diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c index c4eac45a6152..029ab5e9dec7 100644 --- a/drivers/mxc/ipu3/ipu_capture.c +++ b/drivers/mxc/ipu3/ipu_capture.c @@ -803,7 +803,7 @@ void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel) dev_err(ipu->dev, "CSI irq %d in use\n", irq); return; } - ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(50)); + ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(500)); ipu_free_irq(ipu, irq, ipu); dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret); } diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 4e3526c81839..c97d15999301 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -176,174 +176,6 @@ static int __devinit ipu_clk_setup_enable(struct ipu_soc *ipu, return 0; } -#if 0 -static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - struct ipu_soc *ipu = irq_desc_get_handler_data(desc); - const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 }; - u32 status; - int i, line; - - for (i = 0;; i++) { - if (int_reg[i] == 0) - break; - - status = ipu_cm_read(ipu, IPU_INT_STAT(int_reg[i])); - status &= ipu_cm_read(ipu, IPU_INT_CTRL(int_reg[i])); - - while ((line = ffs(status))) { - line--; - status &= ~(1UL << line); - line += ipu->irq_start + (int_reg[i] - 1) * 32; - generic_handle_irq(line); - } - - } -} - -static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - struct ipu_soc *ipu = irq_desc_get_handler_data(desc); - const int int_reg[] = { 5, 6, 9, 10, 0 }; - u32 status; - int i, line; - - for (i = 0;; i++) { - if (int_reg[i] == 0) - break; - - status = ipu_cm_read(ipu, IPU_INT_STAT(int_reg[i])); - status &= ipu_cm_read(ipu, IPU_INT_CTRL(int_reg[i])); - - while ((line = ffs(status))) { - line--; - status &= ~(1UL << line); - line += ipu->irq_start + (int_reg[i] - 1) * 32; - generic_handle_irq(line); - } - - } -} - -static void ipu_ack_irq(struct irq_data *d) -{ - struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq - ipu->irq_start; - unsigned long flags; - - spin_lock_irqsave(&ipu->ipu_lock, flags); - ipu_cm_write(ipu, 1 << (irq % 32), IPU_INT_STAT(irq / 32 + 1)); - spin_unlock_irqrestore(&ipu->ipu_lock, flags); -} - -static void ipu_unmask_irq(struct irq_data *d) -{ - struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq - ipu->irq_start; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&ipu->ipu_lock, flags); - reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32 + 1)); - reg |= 1 << (irq % 32); - ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32 + 1)); - spin_unlock_irqrestore(&ipu->ipu_lock, flags); -} - -static void ipu_mask_irq(struct irq_data *d) -{ - struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq - ipu->irq_start; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&ipu->ipu_lock, flags); - reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32 + 1)); - reg &= ~(1 << (irq % 32)); - ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32 + 1)); - spin_unlock_irqrestore(&ipu->ipu_lock, flags); -} - -static struct irq_chip ipu_irq_chip = { - .name = "IPU", - .irq_ack = ipu_ack_irq, - .irq_mask = ipu_mask_irq, - .irq_unmask = ipu_unmask_irq, -}; - -static void __devinit ipu_irq_setup(struct ipu_soc *ipu) -{ - int i; - - for (i = ipu->irq_start; i < ipu->irq_start + MX5_IPU_IRQS; i++) { - irq_set_chip_and_handler(i, &ipu_irq_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID); - irq_set_chip_data(i, ipu); - } - - irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler); - irq_set_handler_data(ipu->irq_sync, ipu); - irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler); - irq_set_handler_data(ipu->irq_err, ipu); -} - -int ipu_request_irq(struct ipu_soc *ipu, unsigned int irq, - irq_handler_t handler, unsigned long flags, - const char *name, void *dev) -{ - return request_irq(ipu->irq_start + irq, handler, flags, name, dev); -} -EXPORT_SYMBOL_GPL(ipu_request_irq); - -void ipu_enable_irq(struct ipu_soc *ipu, unsigned int irq) -{ - return enable_irq(ipu->irq_start + irq); -} -EXPORT_SYMBOL_GPL(ipu_disable_irq); - -void ipu_disable_irq(struct ipu_soc *ipu, unsigned int irq) -{ - return disable_irq(ipu->irq_start + irq); -} -EXPORT_SYMBOL_GPL(ipu_disable_irq); - -void ipu_free_irq(struct ipu_soc *ipu, unsigned int irq, void *dev_id) -{ - free_irq(ipu->irq_start + irq, dev_id); -} -EXPORT_SYMBOL_GPL(ipu_free_irq); - -static irqreturn_t ipu_completion_handler(int irq, void *dev) -{ - struct completion *completion = dev; - - complete(completion); - return IRQ_HANDLED; -} - -int ipu_wait_for_interrupt(struct ipu_soc *ipu, int interrupt, int timeout_ms) -{ - DECLARE_COMPLETION_ONSTACK(completion); - int ret; - - ret = ipu_request_irq(ipu, interrupt, ipu_completion_handler, - 0, NULL, &completion); - if (ret) { - dev_err(ipu->dev, - "ipu request irq %d fail\n", interrupt); - return ret; - } - - ret = wait_for_completion_timeout(&completion, - msecs_to_jiffies(timeout_ms)); - - ipu_free_irq(ipu, interrupt, &completion); - - return ret > 0 ? 0 : -ETIMEDOUT; -} -EXPORT_SYMBOL_GPL(ipu_wait_for_interrupt); -#endif - struct ipu_soc *ipu_get_soc(int id) { if (id >= MXC_IPU_MAX_NUM) diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index 215fc706407f..d12ffdfc7847 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -1111,7 +1111,7 @@ static int prepare_task(struct ipu_task_entry *t) if (t->set.task != 0) { dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n", t->set.task, t); - BUG(); + return -EINVAL; } t->set.task |= VDOA_ONLY; } @@ -1173,7 +1173,8 @@ static int _get_vdoa_ipu_res(struct ipu_task_entry *t) for (i = 0; i < max_ipu_no; i++) { ipu = ipu_get_soc(i); if (IS_ERR(ipu)) - BUG(); + dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n", + t->task_no, found_vdoa, i); used = &tbl->used[i][IPU_PP_CH_VF]; if (t->set.mode & VDI_MODE) { @@ -1194,7 +1195,8 @@ static int _get_vdoa_ipu_res(struct ipu_task_entry *t) break; } } else - BUG(); + dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n", + t->task_no, found_vdoa, t->set.mode); } if (found_ipu) goto next; @@ -1202,7 +1204,8 @@ static int _get_vdoa_ipu_res(struct ipu_task_entry *t) for (i = 0; i < max_ipu_no; i++) { ipu = ipu_get_soc(i); if (IS_ERR(ipu)) - BUG(); + dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n", + t->task_no, found_vdoa, i); if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) { used = &tbl->used[i][IPU_PP_CH_PP]; @@ -1225,7 +1228,9 @@ next: t->ipu_id = i; t->dev = ipu->dev; if (atomic_inc_return(&t->res_get) == 2) - BUG(); + dev_err(t->dev, + "ERR no:0x%x,found_vdoa:%d,get ipu twice\n", + t->task_no, found_vdoa); } out: dev_dbg(t->dev, @@ -1246,12 +1251,12 @@ static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only) int rel_vdoa = 0, rel_ipu = 0; struct ipu_channel_tabel *tbl = &ipu_ch_tbl; - if (!tsk) - BUG(); mutex_lock(&tbl->lock); if (tsk->set.mode & VDOA_MODE) { if (!tbl->vdoa_used && tsk->vdoa_handle) - BUG(); + dev_err(tsk->dev, + "ERR no:0x%x,vdoa not used,mode:0x%x\n", + tsk->task_no, tsk->set.mode); if (tbl->vdoa_used && tsk->vdoa_handle) { tbl->vdoa_used = 0; vdoa_put_handle(&tsk->vdoa_handle); @@ -1263,13 +1268,13 @@ static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only) } } - if (tsk) { - tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0; - rel_ipu = 1; - ret = atomic_inc_return(&tsk->res_free); - if (ret == 2) - BUG(); - } + tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0; + rel_ipu = 1; + ret = atomic_inc_return(&tsk->res_free); + if (ret == 2) + dev_err(tsk->dev, + "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n", + tsk->task_no, rel_vdoa); out: dev_dbg(tsk->dev, "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n", @@ -1300,12 +1305,16 @@ static int get_vdoa_ipu_res(struct ipu_task_entry *t) goto out; } else { if (!(t->set.task & VDOA_ONLY) && (!t->ipu)) - BUG(); + dev_err(t->dev, + "ERR[no-0x%x] can not get ipu!\n", + t->task_no); ret = atomic_read(&req_cnt); if (ret > 0) ret = atomic_dec_return(&req_cnt); else - BUG(); + dev_err(t->dev, + "ERR[no-0x%x] req_cnt:%d mismatch!\n", + t->task_no, ret); dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n", t->task_no, t, ret); found = 1; @@ -1827,7 +1836,8 @@ static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t) CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret); } else { ret = -EINVAL; - BUG(); + dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n", + t->task_no, t->input.format); } done: @@ -1914,7 +1924,8 @@ static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t) else if (IPU_DEINTERLACE_FIELD_BOTTOM == t->input.deinterlace.field_fmt) params.mem_prp_vf_mem.field_fmt = V4L2_FIELD_INTERLACED_BT; else - BUG(); + dev_err(t->dev, "ERR[no-0x%x]invalid field fmt:0x%x!\n", + t->task_no, t->input.deinterlace.field_fmt); ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, ¶ms); if (ret < 0) { t->state = STATE_INIT_CHAN_FAIL; @@ -2232,8 +2243,10 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t) unsigned char *base_off; struct ipu_task_entry *parent = t->parent; - if (!parent) - BUG(); + if (!parent) { + dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no); + return; + } stripe_mode = t->task_no & 0xf; task_no = t->task_no >> 4; @@ -2544,13 +2557,15 @@ static void do_task(struct ipu_task_entry *t) busy = ic_vf_pp_is_busy(ipu, true); else if (t->task_id == IPU_TASK_ID_PP) busy = ic_vf_pp_is_busy(ipu, false); - else - BUG(); + else { + dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n", + t->task_no, t->task_id); + return; + } if (busy) { dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n", (void *)t, t->task_no, t->task_id); t->state = STATE_IPU_BUSY; - BUG(); return; } @@ -2602,7 +2617,7 @@ static void do_task(struct ipu_task_entry *t) ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev, r_size, &ipu->rot_dma[rot_idx].paddr, - GFP_KERNEL); + GFP_DMA | GFP_KERNEL); CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL, "ic_and_rot", STATE_SYS_NO_MEM, chan_setup, -ENOMEM); @@ -2629,7 +2644,6 @@ static void do_task(struct ipu_task_entry *t) } else { dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t); t->state = STATE_ERR; - BUG(); return; } @@ -2832,7 +2846,9 @@ static void get_res_do_task(struct ipu_task_entry *t) found = get_vdoa_ipu_res(t); if (!found) { - BUG(); + dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n", + t, t->task_no); + return; } else { if (t->set.task & VDOA_ONLY) do_task_vdoa_only(t); @@ -2886,12 +2902,18 @@ static void wait_split_task_complete(struct ipu_task_entry *parent, ret = -ETIMEDOUT; goto out; } else { - if (idx < 0) - BUG(); + if (idx < 0) { + dev_err(parent->dev, + "ERR:[0x%p] no-0x%x, invalid task idx:%d\n", + parent, parent->task_no, idx); + continue; + } tsk = sp_task[idx].child_task; mutex_lock(lock); if (!tsk->split_done || !tsk->ipu) - BUG(); + dev_err(tsk->dev, + "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n", + tsk->task_no, tsk->split_done, tsk->ipu); tsk->split_done = 0; mutex_unlock(lock); @@ -2911,7 +2933,8 @@ out: for (k = 0; k < max_ipu_no; k++) { ipu = ipu_get_soc(k); if (IS_ERR(ipu)) { - BUG(); + dev_err(parent->dev, "no:0x%x, null ipu:%d\n", + parent->task_no, k); } else { busy_vf = ic_vf_pp_is_busy(ipu, true); busy_pp = ic_vf_pp_is_busy(ipu, false); @@ -2948,10 +2971,6 @@ out: spin_unlock_irqrestore(&ipu_task_list_lock, flags); if (!tsk->ipu) continue; - if (STATE_IN_PROGRESS == tsk->state) { - do_task_release(tsk, 1); - put_vdoa_ipu_res(tsk, 0); - } if (tsk->state != STATE_OK) { dev_err(tsk->dev, "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n", @@ -2992,7 +3011,9 @@ static inline int find_task(struct ipu_task_entry **t, int thread_id) "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n", thread_id, tsk, tsk->task_no, tsk->set.mode); } else - BUG(); + dev_err(tsk->dev, + "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n", + thread_id, tsk->task_no, tsk->set.mode); } spin_unlock_irqrestore(&ipu_task_list_lock, flags); @@ -3027,7 +3048,6 @@ static int ipu_task_thread(void *argv) &cpu_mask); if (ret < 0) { pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret); - BUG(); } pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu); } @@ -3039,8 +3059,11 @@ static int ipu_task_thread(void *argv) wait_event(thread_waitq, find_task(&tsk, curr_thread_id)); - if (!tsk) - BUG(); + if (!tsk) { + pr_err("thread:%d can not find task.\n", + curr_thread_id); + continue; + } /* note: other threads run split child task */ split_parent = need_split(tsk) && !tsk->parent; @@ -3083,7 +3106,9 @@ static int ipu_task_thread(void *argv) /* FIXME: ensure the correct sequence for split 4size: 5/6->9/a*/ if (!sp_tsk0) - BUG(); + dev_err(tsk->dev, + "ERR: no-0x%x,can not get split_tsk0\n", + tsk->task_no); wake_up(&thread_waitq); get_res_do_task(sp_tsk0); dev_dbg(sp_tsk0->dev, @@ -3127,8 +3152,7 @@ static int ipu_task_thread(void *argv) kref_put(&tsk->refcount, task_mem_free); } - pr_info("%s exit.\n", __func__); - BUG(); + pr_info("ERR %s exit.\n", __func__); return 0; } @@ -3301,7 +3325,7 @@ static long mxc_ipu_ioctl(struct file *file, mem->cpu_addr = dma_alloc_coherent(ipu_dev, size, &mem->phy_addr, - GFP_KERNEL); + GFP_DMA | GFP_KERNEL); if (mem->cpu_addr == NULL) { kfree(mem); return -ENOMEM; diff --git a/drivers/mxc/thermal/cooling.c b/drivers/mxc/thermal/cooling.c index 772f771c8149..0feefeaa6008 100644 --- a/drivers/mxc/thermal/cooling.c +++ b/drivers/mxc/thermal/cooling.c @@ -177,6 +177,7 @@ int anatop_thermal_cpu_hotplug(bool cpu_on) sys_write(fd, (char *)"1", MAX_CPU_ONLINE_LEN); cpu_mask &= ~(0x1 << cpu); ret = 0; + sys_close(fd); break; } sys_close(fd); @@ -198,6 +199,7 @@ int anatop_thermal_cpu_hotplug(bool cpu_on) sys_write(fd, (char *)"0", MAX_CPU_ONLINE_LEN); cpu_mask |= 0x1 << cpu; ret = 0; + sys_close(fd); break; } sys_close(fd); diff --git a/drivers/mxc/thermal/thermal.c b/drivers/mxc/thermal/thermal.c index 0f4cfb8304ce..6f3c7a912170 100644 --- a/drivers/mxc/thermal/thermal.c +++ b/drivers/mxc/thermal/thermal.c @@ -152,6 +152,8 @@ static const struct anatop_device_id thermal_device_ids[] = { {ANATOP_THERMAL_HID}, {""}, }; +int thermal_hot; +EXPORT_SYMBOL(thermal_hot); enum { DEBUG_USER_STATE = 1U << 0, @@ -584,6 +586,7 @@ static int anatop_thermal_notify(struct thermal_zone_device *thermal, int trip, printk(KERN_WARNING "thermal_notify: trip_critical reached!\n"); arch_reset(mode, cmd); } else if (trip_type == THERMAL_TRIP_HOT) { + thermal_hot = 1; printk(KERN_DEBUG "thermal_notify: trip_hot reached!\n"); type = ANATOP_THERMAL_NOTIFY_HOT; /* if temperature increase, continue to detach secondary CPUs*/ @@ -598,6 +601,7 @@ static int anatop_thermal_notify(struct thermal_zone_device *thermal, int trip, printk(KERN_INFO "No secondary CPUs detached!\n"); full_run = false; } else { + thermal_hot = 0; if (!full_run) { temperature_cooling = 0; if (cooling_cpuhotplug) diff --git a/drivers/mxc/vpu/Kconfig b/drivers/mxc/vpu/Kconfig index dada2040e2ad..6562697f25f5 100644 --- a/drivers/mxc/vpu/Kconfig +++ b/drivers/mxc/vpu/Kconfig @@ -19,4 +19,13 @@ config MXC_VPU_DEBUG This is an option for the developers; most people should say N here. This enables MXC VPU driver debugging. +config MX6_VPU_352M + bool "MX6 VPU 352M" + depends on MXC_VPU + default n + help + Increase VPU frequncy to 352M, the config will disable bus frequency + adjust dynamic, and CPU lowest setpoint will be 352Mhz. + This config is used for special VPU use case. + endmenu diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index 048776bfdc57..c3a48307c918 100755 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -68,7 +68,6 @@ #define cpu_to_hc32(x) cpu_to_le32((x)) #define hc32_to_cpu(x) le32_to_cpu((x)) #endif - #define DMA_ADDR_INVALID (~(dma_addr_t)0) DEFINE_MUTEX(udc_resume_mutex); extern void usb_debounce_id_vbus(void); @@ -340,7 +339,7 @@ static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) struct fsl_usb2_platform_data *pdata = udc->pdata; u32 portsc; unsigned long flags; - spin_lock_irqsave(&udc->lock, flags); + spin_lock_irqsave(&pdata->lock, flags); if (pdata && pdata->phy_lowpower_suspend) { pdata->phy_lowpower_suspend(pdata, enable); @@ -356,7 +355,7 @@ static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) } } pdata->lowpower = enable; - spin_unlock_irqrestore(&udc->lock, flags); + spin_unlock_irqrestore(&pdata->lock, flags); } static int dr_controller_setup(struct fsl_udc *udc) @@ -473,6 +472,9 @@ static void dr_controller_run(struct fsl_udc *udc) { u32 temp; + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_dir = 0; + fsl_platform_pullup_enable(udc->pdata); /* Enable DR irq reg */ @@ -2206,9 +2208,9 @@ static void fsl_gadget_disconnect_event(struct work_struct *work) fsl_writel(tmp | (OTGSC_B_SESSION_VALID_IRQ_EN), &dr_regs->otgsc); udc->stopped = 1; + spin_unlock_irqrestore(&udc->lock, flags); /* enable wake up */ dr_wake_up_enable(udc, true); - spin_unlock_irqrestore(&udc->lock, flags); /* close USB PHY clock */ dr_phy_low_power_mode(udc, true); /* close dr controller clock */ @@ -2445,8 +2447,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, dr_controller_run(udc_controller); if (udc_controller->stopped) dr_clk_gate(false); - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_dir = 0; } printk(KERN_INFO "%s: bind to driver %s \n", udc_controller->gadget.name, driver->driver.name); @@ -3210,6 +3210,7 @@ static int __devinit fsl_udc_probe(struct platform_device *pdev) udc_controller->charger.enable = false; #endif + spin_lock_init(&pdata->lock); return 0; err4: @@ -3464,6 +3465,7 @@ static int fsl_udc_resume(struct platform_device *pdev) */ if (udc_controller->suspended && !udc_controller->stopped) { dr_clk_gate(true); + dr_wake_up_enable(udc_controller, false); dr_phy_low_power_mode(udc_controller, false); } /* Enable DR irq reg and set controller Run */ @@ -3483,9 +3485,6 @@ static int fsl_udc_resume(struct platform_device *pdev) dr_controller_setup(udc_controller); dr_controller_run(udc_controller); } - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_dir = 0; - end: /* if udc is resume by otg id change and no device * connecting to the otg, otg will enter low power mode*/ diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index 787374ab138d..b872d94b3fc3 100755 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -31,6 +31,9 @@ extern void usb_host_set_wakeup(struct device *wkup_dev, bool para); static void fsl_usb_lowpower_mode(struct fsl_usb2_platform_data *pdata, bool enable) { + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); if (enable) { if (pdata->phy_lowpower_suspend) pdata->phy_lowpower_suspend(pdata, true); @@ -39,6 +42,7 @@ static void fsl_usb_lowpower_mode(struct fsl_usb2_platform_data *pdata, bool ena pdata->phy_lowpower_suspend(pdata, false); } pdata->lowpower = enable; + spin_unlock_irqrestore(&pdata->lock, flags); } static void fsl_usb_clk_gate(struct fsl_usb2_platform_data *pdata, bool enable) @@ -304,6 +308,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver, ehci = hcd_to_ehci(hcd); pdata->pm_command = ehci->command; + spin_lock_init(&pdata->lock); return retval; err6: free_irq(irq, (void *)pdev); @@ -337,7 +342,6 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; u32 tmp; - unsigned long flags; if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { /* Need open clock for register access */ @@ -366,9 +370,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, } /*disable the host wakeup and put phy to low power mode */ usb_host_set_wakeup(hcd->self.controller, false); - spin_lock_irqsave(&ehci->lock, flags); fsl_usb_lowpower_mode(pdata, true); - spin_unlock_irqrestore(&ehci->lock, flags); /*free the ehci_fsl_pre_irq */ free_irq(hcd->irq, (void *)pdev); usb_remove_hcd(hcd); @@ -430,7 +432,6 @@ static int ehci_fsl_bus_suspend(struct usb_hcd *hcd) struct fsl_usb2_platform_data *pdata; u32 tmp, portsc, cmd; struct ehci_hcd *ehci = hcd_to_ehci(hcd); - unsigned long flags; pdata = hcd->self.controller->platform_data; printk(KERN_DEBUG "%s begins, %s\n", __func__, pdata->name); @@ -458,9 +459,7 @@ static int ehci_fsl_bus_suspend(struct usb_hcd *hcd) if (pdata->platform_suspend) pdata->platform_suspend(pdata); usb_host_set_wakeup(hcd->self.controller, true); - spin_lock_irqsave(&ehci->lock, flags); fsl_usb_lowpower_mode(pdata, true); - spin_unlock_irqrestore(&ehci->lock, flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); printk(KERN_DEBUG "%s ends, %s\n", __func__, pdata->name); @@ -472,8 +471,6 @@ static int ehci_fsl_bus_resume(struct usb_hcd *hcd) { int ret = 0; struct fsl_usb2_platform_data *pdata; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - unsigned long flags; pdata = hcd->self.controller->platform_data; printk(KERN_DEBUG "%s begins, %s\n", __func__, pdata->name); @@ -490,9 +487,7 @@ static int ehci_fsl_bus_resume(struct usb_hcd *hcd) set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, true); usb_host_set_wakeup(hcd->self.controller, false); - spin_lock_irqsave(&ehci->lock, flags); fsl_usb_lowpower_mode(pdata, false); - spin_unlock_irqrestore(&ehci->lock, flags); } if (pdata->platform_resume) @@ -669,7 +664,6 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct usb_device *roothub = hcd->self.root_hub; - unsigned long flags; u32 port_status; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; @@ -745,9 +739,7 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, pdata->pm_portsc &= ~PORT_PTS_PHCD; usb_host_set_wakeup(hcd->self.controller, true); - spin_lock_irqsave(&ehci->lock, flags); fsl_usb_lowpower_mode(pdata, true); - spin_unlock_irqrestore(&ehci->lock, flags); if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -801,9 +793,7 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, true); usb_host_set_wakeup(hcd->self.controller, false); - spin_lock_irqsave(&ehci->lock, flags); fsl_usb_lowpower_mode(pdata, false); - spin_unlock_irqrestore(&ehci->lock, flags); } spin_lock_irqsave(&ehci->lock, flags); diff --git a/drivers/video/mxc/ldb.c b/drivers/video/mxc/ldb.c index 8b84498fd285..426b139b14b8 100644 --- a/drivers/video/mxc/ldb.c +++ b/drivers/video/mxc/ldb.c @@ -316,7 +316,14 @@ int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v) writel(data, ldb->control_reg); } } + break; } + case FB_EVENT_SUSPEND: + if (ldb->setting[index].clk_en) { + clk_disable(ldb->setting[index].ldb_di_clk); + ldb->setting[index].clk_en = false; + } + break; default: break; } diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index a2ccbaa81a8d..8a052e0433d3 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -436,13 +436,13 @@ static int mxcfb_set_par(struct fb_info *fbi) dma_alloc_coherent(fbi->device, alpha_mem_len, &mxc_fbi->alpha_phy_addr0, - GFP_KERNEL); + GFP_DMA | GFP_KERNEL); mxc_fbi->alpha_virt_addr1 = dma_alloc_coherent(fbi->device, alpha_mem_len, &mxc_fbi->alpha_phy_addr1, - GFP_KERNEL); + GFP_DMA | GFP_KERNEL); if (mxc_fbi->alpha_virt_addr0 == NULL || mxc_fbi->alpha_virt_addr1 == NULL) { dev_err(fbi->device, "mxcfb: dma alloc for" @@ -1782,7 +1782,7 @@ static int mxcfb_map_video_memory(struct fb_info *fbi) fbi->screen_base = dma_alloc_writecombine(fbi->device, fbi->fix.smem_len, (dma_addr_t *)&fbi->fix.smem_start, - GFP_KERNEL); + GFP_DMA | GFP_KERNEL); if (fbi->screen_base == 0) { dev_err(fbi->device, "Unable to allocate framebuffer memory\n"); fbi->fix.smem_len = 0; diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c index 999e3b157211..9e23bdea331f 100644 --- a/drivers/video/mxc_hdmi.c +++ b/drivers/video/mxc_hdmi.c @@ -1543,6 +1543,7 @@ static void mxc_hdmi_notify_fb(struct mxc_hdmi *hdmi) static void mxc_hdmi_edid_rebuild_modelist(struct mxc_hdmi *hdmi) { int i; + struct fb_videomode *mode; dev_dbg(&hdmi->pdev->dev, "%s\n", __func__); @@ -1554,10 +1555,14 @@ static void mxc_hdmi_edid_rebuild_modelist(struct mxc_hdmi *hdmi) for (i = 0; i < hdmi->fbi->monspecs.modedb_len; i++) { /* * We might check here if mode is supported by HDMI. - * We do not currently support interlaced modes + * We do not currently support interlaced modes. + * And add CEA modes in the modelist. */ - if (!(hdmi->fbi->monspecs.modedb[i].vmode & - FB_VMODE_INTERLACED)) { + mode = &hdmi->fbi->monspecs.modedb[i]; + + if (!(mode->vmode & FB_VMODE_INTERLACED) && + (mxc_edid_mode_to_vic(mode) != 0)) { + dev_dbg(&hdmi->pdev->dev, "Added mode %d:", i); dev_dbg(&hdmi->pdev->dev, "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n", @@ -1567,8 +1572,7 @@ static void mxc_hdmi_edid_rebuild_modelist(struct mxc_hdmi *hdmi) hdmi->fbi->monspecs.modedb[i].vmode, hdmi->fbi->monspecs.modedb[i].flag); - fb_add_videomode(&hdmi->fbi->monspecs.modedb[i], - &hdmi->fbi->modelist); + fb_add_videomode(mode, &hdmi->fbi->modelist); } } @@ -1651,6 +1655,8 @@ static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi) if (fb_mode_is_equal(&hdmi->previous_non_vga_mode, mode)) { dev_dbg(&hdmi->pdev->dev, "%s: Video mode same as previous\n", __func__); + /* update fbi mode in case modelist is updated */ + hdmi->fbi->mode = mode; mxc_hdmi_phy_init(hdmi); } else { dev_dbg(&hdmi->pdev->dev, "%s: New video mode\n", __func__); @@ -1674,6 +1680,13 @@ static void mxc_hdmi_cable_connected(struct mxc_hdmi *hdmi) /* HDMI Initialization Step C */ edid_status = mxc_hdmi_read_edid(hdmi); + /* Read EDID again if first EDID read failed */ + if (edid_status == HDMI_EDID_NO_MODES || + edid_status == HDMI_EDID_FAIL) { + dev_info(&hdmi->pdev->dev, "Read EDID again\n"); + edid_status = mxc_hdmi_read_edid(hdmi); + } + /* HDMI Initialization Steps D, E, F */ switch (edid_status) { case HDMI_EDID_SUCCESS: @@ -1756,10 +1769,13 @@ static void hotplug_worker(struct work_struct *work) #ifdef CONFIG_MXC_HDMI_CEC mxc_hdmi_cec_handle(0x80); #endif + hdmi_set_cable_state(1); } else if (!(phy_int_pol & HDMI_PHY_HPD)) { /* Plugout event */ dev_dbg(&hdmi->pdev->dev, "EVENT=plugout\n"); + hdmi_set_cable_state(0); + mxc_hdmi_abort_stream(); mxc_hdmi_cable_disconnected(hdmi); /* Make HPD intr active high to capture plugin event */ @@ -2048,10 +2064,13 @@ static int mxc_hdmi_fb_event(struct notifier_block *nb, if (hdmi->fb_reg && hdmi->cable_plugin) mxc_hdmi_setup(hdmi, val); + hdmi_set_blank_state(1); } else if (*((int *)event->data) != hdmi->blank) { dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_BLANK - BLANK\n"); + hdmi_set_blank_state(0); + mxc_hdmi_abort_stream(); mxc_hdmi_phy_disable(hdmi); |