summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorguoyin.chen <guoyin.chen@freescale.com>2013-07-15 15:01:21 +0800
committerguoyin.chen <guoyin.chen@freescale.com>2013-07-15 15:01:21 +0800
commit5793da66dd82a437c23d4a833674c0e09bd1aa07 (patch)
tree2f34bdc95dedb46d2a91d12837e58b1cf3a3e33f /drivers
parentf128c5660150679f00e518da8e3f582e9a2f03a8 (diff)
parent9e268cc3e4386f1a5a31a62f7207e5a9b8420124 (diff)
Merge remote-tracking branch 'fsl-linux-sdk/imx_3.0.35_4.1.0' into imx_3.0.35_android
Conflicts: arch/arm/mach-mx6/Kconfig arch/arm/mach-mx6/board-mx6q_arm2.c arch/arm/mach-mx6/board-mx6q_arm2.h arch/arm/mach-mx6/board-mx6q_hdmidongle.c arch/arm/mach-mx6/board-mx6q_sabreauto.c arch/arm/mach-mx6/board-mx6q_sabreauto.h arch/arm/mach-mx6/board-mx6q_sabrelite.c arch/arm/mach-mx6/board-mx6q_sabresd.c arch/arm/mach-mx6/board-mx6q_sabresd.h arch/arm/mach-mx6/clock.c arch/arm/mach-mx6/pcie.c arch/arm/plat-mxc/include/mach/iomux-mx6q.h arch/arm/plat-mxc/include/mach/pcie.h drivers/dma/imx-sdma.c drivers/input/touchscreen/egalax_ts.c drivers/media/video/mxc/capture/csi_v4l2_capture.c drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c drivers/mxc/mlb/mxc_mlb150.c drivers/mxc/thermal/thermal.c drivers/net/fec.c drivers/usb/host/ehci-arc.c drivers/video/mxc/mxc_ipuv3_fb.c include/linux/fec.h sound/soc/imx/imx-wm8962.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/imx-sdma.c97
-rw-r--r--drivers/media/video/mxc/capture/csi_v4l2_capture.c208
-rw-r--r--drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c1
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.c2
-rw-r--r--drivers/media/video/mxc/output/mxc_vout.c187
-rw-r--r--drivers/media/video/videobuf-dma-contig.c3
-rw-r--r--drivers/mmc/core/mmc.c71
-rw-r--r--drivers/mxc/asrc/mxc_asrc.c324
-rw-r--r--drivers/mxc/gpu-viv/Kbuild2
-rw-r--r--drivers/mxc/ipu3/ipu_capture.c1
-rw-r--r--drivers/mxc/ipu3/ipu_common.c67
-rw-r--r--drivers/mxc/ipu3/ipu_device.c64
-rw-r--r--drivers/mxc/ipu3/ipu_disp.c8
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h10
-rwxr-xr-xdrivers/mxc/mlb/mxc_mlb150.c25
-rw-r--r--drivers/mxc/thermal/thermal.c18
-rw-r--r--drivers/mxc/vpu/mxc_vpu.c28
-rwxr-xr-xdrivers/net/fec.c65
-rw-r--r--drivers/regulator/pfuze100-regulator.c4
-rwxr-xr-xdrivers/usb/gadget/arcotg_udc.c17
-rwxr-xr-xdrivers/usb/host/ehci-arc.c105
-rwxr-xr-xdrivers/usb/otg/fsl_otg.c11
-rw-r--r--drivers/video/mxc/mxc_edid.c4
-rw-r--r--drivers/video/mxc/mxc_elcdif_fb.c14
-rw-r--r--drivers/video/mxc/mxc_epdc_fb.c2
-rw-r--r--drivers/video/mxc/mxcfb_sii902x_elcdif.c32
-rw-r--r--drivers/video/mxc_hdmi.c400
27 files changed, 1235 insertions, 535 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 9c2419e4fffb..9048f469337f 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -7,7 +7,7 @@
*
* Based on code from Freescale:
*
- * Copyright 2004-2012 Freescale Semiconductor, Inc.
+ * Copyright 2004-2013 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -33,11 +33,14 @@
#include <linux/platform_device.h>
#include <linux/dmaengine.h>
#include <linux/delay.h>
+#include <linux/genalloc.h>
#include <asm/irq.h>
#include <mach/sdma.h>
#include <mach/dma.h>
#include <mach/hardware.h>
+#include <mach/iram.h>
+
/* SDMA registers */
#define SDMA_H_C0PTR 0x000
@@ -328,6 +331,7 @@ struct sdma_engine {
struct clk *clk;
struct sdma_script_start_addrs *script_addrs;
spinlock_t irq_reg_lock;
+ spinlock_t channel_0_lock;
};
#define SDMA_H_CONFIG_DSPDMA (1 << 12) /* indicates if the DSPDMA is used */
@@ -335,6 +339,35 @@ struct sdma_engine {
#define SDMA_H_CONFIG_ACR (1 << 4) /* indicates if AHB freq /core freq = 2 or 1 */
#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
+#ifdef CONFIG_SDMA_IRAM
+static unsigned long sdma_iram_paddr;
+static void *sdma_iram_vaddr;
+#define sdma_iram_phys_to_virt(p) (sdma_iram_vaddr + ((p) - sdma_iram_paddr))
+#define sdma_iram_virt_to_phys(v) (sdma_iram_paddr + ((v) - sdma_iram_vaddr))
+static struct gen_pool *sdma_iram_pool;
+
+/*!
+ * Allocates uncacheable buffer from IRAM
+ */
+void __iomem *sdma_iram_malloc(size_t size, unsigned long *buf)
+{
+ *buf = gen_pool_alloc(sdma_iram_pool, size);
+ if (!buf)
+ return NULL;
+
+ return sdma_iram_phys_to_virt(*buf);
+}
+
+void sdma_iram_free(unsigned long *buf, u32 size)
+{
+ if (!sdma_iram_pool)
+ return;
+
+ gen_pool_free(sdma_iram_pool, buf, size);
+}
+#endif /*CONFIG_SDMA_IRAM */
+
+
static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
{
u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
@@ -385,14 +418,23 @@ static int sdma_run_channel(struct sdma_channel *sdmac)
{
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
+ unsigned long timeout = 1000;
int ret;
- init_completion(&sdmac->done);
+ writel(1 << channel, sdma->regs + SDMA_H_START);
- wmb();
- writel_relaxed(1 << channel, sdma->regs + SDMA_H_START);
+ while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) {
+ if (timeout-- <= 0)
+ break;
+ udelay(1);
+ }
- ret = wait_for_completion_timeout(&sdmac->done, HZ);
+ if (ret) {
+ /* Clear the interrupt status */
+ writel_relaxed(ret, sdma->regs + SDMA_H_INTR);
+ } else {
+ dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
+ }
return ret ? 0 : -ETIMEDOUT;
}
@@ -403,14 +445,21 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
void *buf_virt;
dma_addr_t buf_phys;
+ unsigned long flags;
int ret;
+#ifdef CONFIG_SDMA_IRAM
+ buf_virt = sdma_iram_malloc(size, (unsigned long)&buf_phys);
+#else
buf_virt = dma_alloc_coherent(NULL,
size,
&buf_phys, GFP_KERNEL);
+#endif
if (!buf_virt)
return -ENOMEM;
+ spin_lock_irqsave(&sdma->channel_0_lock, flags);
+
bd0->mode.command = C0_SETPM;
bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
bd0->mode.count = size / 2;
@@ -421,7 +470,12 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
ret = sdma_run_channel(&sdma->channel[0]);
+ spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
+#ifdef CONFIG_SDMA_IRAM
+ sdma_iram_free(buf_phys, size);
+#else
dma_free_coherent(NULL, size, buf_virt, buf_phys);
+#endif
return ret;
}
@@ -518,10 +572,6 @@ static void mxc_sdma_handle_channel(struct sdma_channel *sdmac)
{
complete(&sdmac->done);
- /* not interested in channel 0 interrupts */
- if (sdmac->channel == 0)
- return;
-
switch (sdmac->mode) {
case SDMA_MODE_LOOP:
sdma_handle_channel_loop(sdmac);
@@ -548,6 +598,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
spin_lock_irqsave(&sdma->irq_reg_lock, flag);
stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
+ /* not interested in channel 0 interrupts */
+ stat &= ~1;
writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
spin_unlock_irqrestore(&sdma->irq_reg_lock, flag);
@@ -696,6 +748,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
struct sdma_context_data *context = sdma->context;
struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
int ret;
+ unsigned long flags;
if (sdmac->direction == DMA_DEV_TO_MEM)
@@ -720,6 +773,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0);
dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1);
+ spin_lock_irqsave(&sdma->channel_0_lock, flags);
memset(context, 0, sizeof(*context));
context->channel_state.pc = load_address;
@@ -736,6 +790,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
ret = sdma_run_channel(&sdma->channel[0]);
+ spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
return ret;
}
@@ -882,7 +937,12 @@ static int sdma_request_channel(struct sdma_channel *sdmac)
int channel = sdmac->channel;
int ret = -EBUSY;
+#ifdef CONFIG_SDMA_IRAM
+ sdmac->bd = sdma_iram_malloc(sizeof(sdmac->bd),
+ (unsigned long)&sdmac->bd_phys);
+#else
sdmac->bd = dma_alloc_noncached(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
+#endif
if (!sdmac->bd) {
ret = -ENOMEM;
goto out;
@@ -1045,8 +1105,11 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
+#ifdef CONFIG_SDMA_IRAM
+ sdma_iram_free(sdmac->bd_phys, sizeof(sdmac->bd));
+#else
dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
-
+#endif
clk_disable(sdma->clk);
}
@@ -1430,10 +1493,22 @@ static int __init sdma_init(struct sdma_engine *sdma)
/* Be sure SDMA has not started yet */
writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
+#ifdef CONFIG_SDMA_IRAM
+ /* Allocate memory for SDMA channel and buffer descriptors */
+ sdma_iram_vaddr = iram_alloc(SZ_4K, &sdma_iram_paddr);
+ sdma_iram_pool = gen_pool_create(PAGE_SHIFT/2, -1);
+ gen_pool_add(sdma_iram_pool, sdma_iram_paddr, SZ_4K, -1);
+
+ sdma->channel_control = sdma_iram_malloc(MAX_DMA_CHANNELS *
+ sizeof(struct sdma_channel_control)
+ + sizeof(struct sdma_context_data),
+ &ccb_phys);
+#else
sdma->channel_control = dma_alloc_coherent(NULL,
MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
sizeof(struct sdma_context_data),
&ccb_phys, GFP_KERNEL);
+#endif
if (!sdma->channel_control) {
ret = -ENOMEM;
@@ -1501,6 +1576,8 @@ static int __init sdma_probe(struct platform_device *pdev)
if (!sdma)
return -ENOMEM;
+ spin_lock_init(&sdma->channel_0_lock);
+
sdma->dev = &pdev->dev;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
index 745440911a1f..7e108f7bac03 100644
--- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
@@ -42,10 +42,13 @@
static int video_nr = -1;
static cam_data *g_cam;
+static int req_buf_number;
static int csi_v4l2_master_attach(struct v4l2_int_device *slave);
static void csi_v4l2_master_detach(struct v4l2_int_device *slave);
static u8 camera_power(cam_data *cam, bool cameraOn);
+struct v4l2_crop crop_current;
+struct v4l2_window win_current;
/*! Information about this driver. */
static struct v4l2_int_master csi_v4l2_master = {
@@ -62,6 +65,37 @@ static struct v4l2_int_device csi_v4l2_int_device = {
},
};
+static struct v4l2_queryctrl pxp_controls[] = {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rotation",
+ .minimum = 0,
+ .maximum = 270,
+ .step = 90,
+ .default_value = 0,
+ .flags = 0,
+ },
+};
+
/* Callback function triggered after PxP receives an EOF interrupt */
static void pxp_dma_done(void *arg)
{
@@ -108,7 +142,7 @@ static int pxp_chan_init(cam_data *cam)
/*
* Function to call PxP DMA driver and send our new V4L2 buffer
- * through the PxP and PxP will process this buffer in place.
+ * through the PxP.
* Note: This is a blocking call, so upon return the PxP tx should be complete.
*/
static int pxp_process_update(cam_data *cam)
@@ -177,21 +211,41 @@ static int pxp_process_update(cam_data *cam)
proc_data->srect.width = pxp_conf->s0_param.width;
proc_data->srect.height = pxp_conf->s0_param.height;
- proc_data->drect.top = 0;
+ if (crop_current.c.top != 0)
+ proc_data->srect.top = crop_current.c.top;
+ if (crop_current.c.left != 0)
+ proc_data->srect.left = crop_current.c.left;
+ if (crop_current.c.width != 0)
+ proc_data->srect.width = crop_current.c.width;
+ if (crop_current.c.height != 0)
+ proc_data->srect.height = crop_current.c.height;
+
proc_data->drect.left = 0;
+ proc_data->drect.top = 0;
proc_data->drect.width = proc_data->srect.width;
proc_data->drect.height = proc_data->srect.height;
- proc_data->scaling = 0;
- proc_data->hflip = 0;
- proc_data->vflip = 0;
- proc_data->rotate = 0;
- proc_data->bgcolor = 0;
+
+ if (win_current.w.left != 0)
+ proc_data->drect.left = win_current.w.left;
+ if (win_current.w.top != 0)
+ proc_data->drect.top = win_current.w.top;
+ if (win_current.w.width != 0)
+ proc_data->drect.width = win_current.w.width;
+ if (win_current.w.height != 0)
+ proc_data->drect.height = win_current.w.height;
+
+ pr_debug("srect l: %d, t: %d, w: %d, h: %d; "
+ "drect l: %d, t: %d, w: %d, h: %d\n",
+ proc_data->srect.left, proc_data->srect.top,
+ proc_data->srect.width, proc_data->srect.height,
+ proc_data->drect.left, proc_data->drect.top,
+ proc_data->drect.width, proc_data->drect.height);
pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
pxp_conf->out_param.width = proc_data->drect.width;
pxp_conf->out_param.height = proc_data->drect.height;
- if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+ if (cam->rotation % 180)
pxp_conf->out_param.stride = pxp_conf->out_param.height;
else
pxp_conf->out_param.stride = pxp_conf->out_param.width;
@@ -742,7 +796,7 @@ static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
* camera can change. */
pr_debug("csi_v4l2_s_fmt size changed\n");
}
- if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ if (cam->rotation % 180) {
height = &f->fmt.pix.width;
width = &f->fmt.pix.height;
} else {
@@ -824,6 +878,11 @@ static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
cam->win = f->fmt.win;
+ win_current = f->fmt.win;
+ size = win_current.w.width * win_current.w.height * 2;
+ if (cam->v2f.fmt.pix.sizeimage < size)
+ cam->v2f.fmt.pix.sizeimage = size;
+
break;
default:
retval = -EINVAL;
@@ -897,6 +956,39 @@ exit:
return err;
}
+static int pxp_set_cstate(cam_data *cam, struct v4l2_control *vc)
+{
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
+
+ if (vc->id == V4L2_CID_HFLIP) {
+ proc_data->hflip = vc->value;
+ } else if (vc->id == V4L2_CID_VFLIP) {
+ proc_data->vflip = vc->value;
+ } else if (vc->id == V4L2_CID_PRIVATE_BASE) {
+ if (vc->value % 90)
+ return -ERANGE;
+ proc_data->rotate = vc->value;
+ cam->rotation = vc->value;
+ }
+
+ return 0;
+}
+
+static int pxp_get_cstate(cam_data *cam, struct v4l2_control *vc)
+{
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
+
+ if (vc->id == V4L2_CID_HFLIP)
+ vc->value = proc_data->hflip;
+ else if (vc->id == V4L2_CID_VFLIP)
+ vc->value = proc_data->vflip;
+ else if (vc->id == V4L2_CID_PRIVATE_BASE)
+ vc->value = proc_data->rotate;
+
+ return 0;
+}
+
+
/*!
* Dequeue one V4L capture buffer
*
@@ -959,9 +1051,9 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf)
* to RGB565; but for encoding, usually we don't use RGB format.
*/
if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
- /* PxP processes it in place */
sg_dma_address(&cam->sg[0]) = buf->m.offset;
- sg_dma_address(&cam->sg[1]) = buf->m.offset;
+ sg_dma_address(&cam->sg[1]) =
+ cam->frame[req_buf_number].paddress;
retval = pxp_process_update(cam);
if (retval) {
pr_err("Unable to submit PxP update task.\n");
@@ -970,6 +1062,9 @@ static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf)
pxp_complete_update(cam);
}
up(&cam->busy_lock);
+ memcpy(cam->frame[buf->index].vaddress,
+ cam->frame[req_buf_number].vaddress,
+ cam->v2f.fmt.pix.sizeimage);
return retval;
}
@@ -1246,9 +1341,33 @@ static long csi_v4l_do_ioctl(struct file *file,
}
case VIDIOC_S_CROP:
- pr_debug(" case not supported\n");
+ {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ retval = -EINVAL;
+ break;
+ }
+ crop->c.width -= crop->c.width % 8;
+ crop->c.height -= crop->c.height % 8;
+
+ crop_current.c = crop->c;
+
break;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ retval = -EINVAL;
+ break;
+ }
+ crop->c = crop_current.c;
+
+ break;
+
+ }
case VIDIOC_REQBUFS: {
struct v4l2_requestbuffers *req = arg;
pr_debug(" case VIDIOC_REQBUFS\n");
@@ -1274,7 +1393,9 @@ static long csi_v4l_do_ioctl(struct file *file,
INIT_LIST_HEAD(&cam->working_q);
INIT_LIST_HEAD(&cam->done_q);
if (req->memory & V4L2_MEMORY_MMAP)
- retval = csi_allocate_frame_buf(cam, req->count);
+ retval = csi_allocate_frame_buf(cam, req->count + 1);
+ req_buf_number = req->count;
+ }
break;
}
@@ -1401,16 +1522,63 @@ static long csi_v4l_do_ioctl(struct file *file,
}
case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *vc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (vc->id == pxp_controls[i].id) {
+ if (vc->value < pxp_controls[i].minimum ||
+ vc->value > pxp_controls[i].maximum) {
+ retval = -ERANGE;
+ break;
+ }
+ retval = pxp_set_cstate(cam, vc);
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(pxp_controls))
+ retval = -EINVAL;
+ break;
+
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *vc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (vc->id == pxp_controls[i].id) {
+ retval = pxp_get_cstate(cam, vc);
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(pxp_controls))
+ retval = -EINVAL;
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (qc->id && qc->id == pxp_controls[i].id) {
+ memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(pxp_controls))
+ retval = -EINVAL;
+ break;
+ }
case VIDIOC_G_STD:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_ENUMSTD:
- case VIDIOC_G_CROP:
case VIDIOC_CROPCAP:
case VIDIOC_S_STD:
- case VIDIOC_G_CTRL:
case VIDIOC_TRY_FMT:
- case VIDIOC_QUERYCTRL:
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
@@ -1510,8 +1678,14 @@ static struct video_device csi_v4l_template = {
*/
static void init_camera_struct(cam_data *cam)
{
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
pr_debug("In MVC: %s\n", __func__);
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = 0;
+ proc_data->bgcolor = 0;
+
/* Default everything to 0 */
memset(cam, 0, sizeof(cam_data));
@@ -1598,6 +1772,8 @@ static int __devinit csi_v4l2_probe(struct platform_device *pdev)
err = -ENOMEM;
goto out;
}
+ memset(&crop_current, 0, sizeof(crop_current));
+ memset(&win_current, 0, sizeof(win_current));
init_camera_struct(g_cam);
platform_set_drvdata(pdev, (void *)g_cam);
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 6d8d4399d7ad..856078a52b6f 100644
--- a/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c
+++ b/drivers/media/video/mxc/capture/ipu_fg_overlay_sdc.c
@@ -396,6 +396,7 @@ static int foreground_start(void *private)
fbvar.yres = cam->win.w.height;
fbvar.yres_virtual = cam->win.w.height * 2;
fbvar.yoffset = 0;
+ fbvar.vmode &= ~FB_VMODE_YWRAP;
fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
fbvar.activate |= FB_ACTIVATE_FORCE;
fb_set_var(fbi, &fbvar);
diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
index 175f9c6820f3..0b2e08c07775 100644
--- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
@@ -2677,7 +2677,7 @@ static void init_camera_struct(cam_data *cam, struct platform_device *pdev)
cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL);
cam->self->module = THIS_MODULE;
- sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);
+ sprintf(cam->self->name, "mxc_v4l2_cap%d", pdev->id);
cam->self->type = v4l2_int_type_master;
cam->self->u.master = &mxc_v4l2_master;
}
diff --git a/drivers/media/video/mxc/output/mxc_vout.c b/drivers/media/video/mxc/output/mxc_vout.c
index 626bad59e151..452c5735e3ea 100644
--- a/drivers/media/video/mxc/output/mxc_vout.c
+++ b/drivers/media/video/mxc/output/mxc_vout.c
@@ -30,8 +30,8 @@
#define UYVY_BLACK (0x00800080)
#define RGB_BLACK (0x0)
-#define NV12_UV_BLACK (0x80)
-#define NV12_Y_BLACK (0x0)
+#define UV_BLACK (0x80)
+#define Y_BLACK (0x0)
#define MAX_FB_NUM 6
#define FB_BUFS 3
@@ -58,6 +58,16 @@
((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \
((vout)->task.input.height == FRAME_HEIGHT_1080P) && \
((vout)->task.input.crop.h == FRAME_HEIGHT_1080P))
+#define IS_PLANAR_PIXEL_FORMAT(format) \
+ (format == IPU_PIX_FMT_NV12 || \
+ format == IPU_PIX_FMT_YUV420P2 || \
+ format == IPU_PIX_FMT_YUV420P || \
+ format == IPU_PIX_FMT_YVU420P || \
+ format == IPU_PIX_FMT_YUV422P || \
+ format == IPU_PIX_FMT_YVU422P || \
+ format == IPU_PIX_FMT_YUV444P)
+
+#define NSEC_PER_FRAME_30FPS (33333333)
struct mxc_vout_fb {
char *name;
@@ -108,12 +118,12 @@ struct mxc_vout_output {
struct dma_mem vdoa_output[VDOA_FB_BUFS];
bool timer_stop;
- struct timer_list timer;
+ struct hrtimer timer;
struct workqueue_struct *v4l_wq;
struct work_struct disp_work;
unsigned long frame_count;
unsigned long vdi_frame_cnt;
- unsigned long start_jiffies;
+ ktime_t start_ktime;
int ctrl_rotate;
int ctrl_vflip;
@@ -121,7 +131,8 @@ struct mxc_vout_output {
dma_addr_t disp_bufs[FB_BUFS];
- struct videobuf_buffer *pre_vb;
+ struct videobuf_buffer *pre1_vb;
+ struct videobuf_buffer *pre2_vb;
};
struct mxc_vout_dev {
@@ -499,29 +510,26 @@ static bool is_pp_bypass(struct mxc_vout_output *vout)
static void setup_buf_timer(struct mxc_vout_output *vout,
struct videobuf_buffer *vb)
{
- unsigned long timeout;
+ ktime_t expiry_time, now;
/* if timestamp is 0, then default to 30fps */
- if ((vb->ts.tv_sec == 0)
- && (vb->ts.tv_usec == 0)
- && vout->start_jiffies)
- timeout =
- vout->start_jiffies + vout->frame_count * HZ / 30;
+ if ((vb->ts.tv_sec == 0) && (vb->ts.tv_usec == 0))
+ expiry_time = ktime_add_ns(vout->start_ktime,
+ NSEC_PER_FRAME_30FPS * vout->frame_count);
else
- timeout = get_jiffies(&vb->ts);
+ expiry_time = timeval_to_ktime(vb->ts);
- if (jiffies >= timeout) {
+ now = hrtimer_cb_get_time(&vout->timer);
+ if ((now.tv64 > expiry_time.tv64)) {
v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
"warning: timer timeout already expired.\n");
+ expiry_time = now;
}
- if (mod_timer(&vout->timer, timeout)) {
- v4l2_warn(vout->vfd->v4l2_dev,
- "warning: timer was already set\n");
- }
+ hrtimer_start(&vout->timer, expiry_time, HRTIMER_MODE_ABS);
- v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
- "timer handler next schedule: %lu\n", timeout);
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "timer handler next "
+ "schedule: %lldnsecs\n", expiry_time.tv64);
}
static int show_buf(struct mxc_vout_output *vout, int idx,
@@ -598,10 +606,21 @@ static void disp_work_func(struct work_struct *work)
}
if (deinterlace_3_field(vout)) {
if (list_is_singular(&vout->active_list)) {
- v4l2_warn(vout->vfd->v4l2_dev,
- "no enough entry for 3 fields deinterlacer\n");
- spin_unlock_irqrestore(q->irqlock, flags);
- return;
+ if (list_empty(&vout->queue_list)) {
+ vout->timer_stop = true;
+ spin_unlock_irqrestore(q->irqlock, flags);
+ v4l2_warn(vout->vfd->v4l2_dev,
+ "no enough entry for 3 fields "
+ "deinterlacer\n");
+ return;
+ }
+
+ /*
+ * We need to use the next vb even if it is
+ * not on the active list.
+ */
+ vb_next = list_first_entry(&vout->queue_list,
+ struct videobuf_buffer, queue);
} else
vb_next = list_first_entry(vout->active_list.next,
struct videobuf_buffer, queue);
@@ -719,21 +738,28 @@ vdi_frame_rate_double:
list_del(&vb->queue);
/*
- * previous videobuf finish show, set VIDEOBUF_DONE state here
- * to avoid tearing issue in pp bypass case, which make sure
- * showing buffer will not be dequeue to write new data. It also
- * bring side-effect that the last buffer can not be dequeue
- * correctly, app need take care about it.
+ * The videobuf before the last one has been shown. Set
+ * VIDEOBUF_DONE state here to avoid tearing issue in ic bypass
+ * case, which makes sure a buffer being shown will not be
+ * dequeued to be overwritten. It also brings side-effect that
+ * the last 2 buffers can not be dequeued correctly, apps need
+ * to take care of it.
*/
- if (vout->pre_vb) {
- vout->pre_vb->state = VIDEOBUF_DONE;
- wake_up_interruptible(&vout->pre_vb->done);
+ if (vout->pre2_vb) {
+ vout->pre2_vb->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->pre2_vb->done);
+ vout->pre2_vb = NULL;
}
- if (vout->linear_bypass_pp)
- vout->pre_vb = vb;
- else {
- vout->pre_vb = NULL;
+ if (vout->linear_bypass_pp) {
+ vout->pre2_vb = vout->pre1_vb;
+ vout->pre1_vb = vb;
+ } else {
+ if (vout->pre1_vb) {
+ vout->pre1_vb->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->pre1_vb->done);
+ vout->pre1_vb = NULL;
+ }
vb->state = VIDEOBUF_DONE;
wake_up_interruptible(&vb->done);
}
@@ -761,10 +787,11 @@ err:
return;
}
-static void mxc_vout_timer_handler(unsigned long arg)
+static enum hrtimer_restart mxc_vout_timer_handler(struct hrtimer *timer)
{
- struct mxc_vout_output *vout =
- (struct mxc_vout_output *) arg;
+ struct mxc_vout_output *vout = container_of(timer,
+ struct mxc_vout_output,
+ timer);
struct videobuf_queue *q = &vout->vbq;
struct videobuf_buffer *vb;
unsigned long flags = 0;
@@ -777,7 +804,7 @@ static void mxc_vout_timer_handler(unsigned long arg)
*/
if (list_empty(&vout->queue_list)) {
spin_unlock_irqrestore(q->irqlock, flags);
- return;
+ return HRTIMER_NORESTART;
}
/* move videobuf from queued list to active list */
@@ -792,12 +819,14 @@ static void mxc_vout_timer_handler(unsigned long arg)
list_del(&vb->queue);
list_add(&vb->queue, &vout->queue_list);
spin_unlock_irqrestore(q->irqlock, flags);
- return;
+ return HRTIMER_NORESTART;
}
vb->state = VIDEOBUF_ACTIVE;
spin_unlock_irqrestore(q->irqlock, flags);
+
+ return HRTIMER_NORESTART;
}
/* Video buffer call backs */
@@ -850,21 +879,21 @@ static void mxc_vout_buffer_queue(struct videobuf_queue *q,
struct videobuf_buffer *vb)
{
struct mxc_vout_output *vout = q->priv_data;
+ struct videobuf_buffer *active_vb;
list_add_tail(&vb->queue, &vout->queue_list);
vb->state = VIDEOBUF_QUEUED;
if (vout->timer_stop) {
if (deinterlace_3_field(vout) &&
- list_empty(&vout->active_list)) {
- vb = list_first_entry(&vout->queue_list,
+ !list_empty(&vout->active_list)) {
+ active_vb = list_first_entry(&vout->active_list,
struct videobuf_buffer, queue);
- list_del(&vb->queue);
- list_add_tail(&vb->queue, &vout->active_list);
+ setup_buf_timer(vout, active_vb);
} else {
setup_buf_timer(vout, vb);
- vout->timer_stop = false;
}
+ vout->timer_stop = false;
}
}
@@ -1379,6 +1408,14 @@ static int mxc_vidioc_s_crop(struct file *file, void *fh,
/* stride line limitation */
crop->c.height -= crop->c.height % 8;
crop->c.width -= crop->c.width % 8;
+ if ((crop->c.width <= 0) || (crop->c.height <= 0) ||
+ ((crop->c.left + crop->c.width) > (b->left + b->width)) ||
+ ((crop->c.top + crop->c.height) > (b->top + b->height))) {
+ v4l2_err(vout->vfd->v4l2_dev, "s_crop err: %d, %d, %d, %d",
+ crop->c.left, crop->c.top,
+ crop->c.width, crop->c.height);
+ return -EINVAL;
+ }
/* the same setting, return */
if (vout->disp_support_windows) {
@@ -1397,7 +1434,7 @@ static int mxc_vidioc_s_crop(struct file *file, void *fh,
/* wait current work finish */
if (vout->vbq.streaming)
- cancel_work_sync(&vout->disp_work);
+ flush_workqueue(vout->v4l_wq);
mutex_lock(&vout->task_lock);
@@ -1551,7 +1588,7 @@ static int mxc_vidioc_s_ctrl(struct file *file, void *fh,
/* wait current work finish */
if (vout->vbq.streaming)
- cancel_work_sync(&vout->disp_work);
+ flush_workqueue(vout->v4l_wq);
mutex_lock(&vout->task_lock);
switch (ctrl->id) {
@@ -1751,7 +1788,10 @@ static int config_disp_output(struct mxc_vout_output *vout)
"ERR:%s fb_set_var ret:%d\n", __func__, ret);
return ret;
}
- display_buf_size = fbi->fix.line_length * fbi->var.yres;
+ if (vout->linear_bypass_pp || vout->tiled_bypass_pp)
+ display_buf_size = fbi->fix.line_length * fbi->var.yres_virtual;
+ else
+ display_buf_size = fbi->fix.line_length * fbi->var.yres;
for (i = 0; i < fb_num; i++)
vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size;
if (vout->tiled_bypass_pp) {
@@ -1784,11 +1824,11 @@ static int config_disp_output(struct mxc_vout_output *vout)
/* fill black when video config changed */
color = colorspaceofpixel(vout->task.output.format) == YUV_CS ?
UYVY_BLACK : RGB_BLACK;
- if (vout->task.output.format == IPU_PIX_FMT_NV12) {
+ if (IS_PLANAR_PIXEL_FORMAT(vout->task.output.format)) {
size = display_buf_size * 8 /
fmt_to_bpp(vout->task.output.format);
- memset(fbi->screen_base, NV12_Y_BLACK, size);
- memset(fbi->screen_base + size, NV12_UV_BLACK,
+ memset(fbi->screen_base, Y_BLACK, size);
+ memset(fbi->screen_base + size, UV_BLACK,
display_buf_size - size);
} else {
pixel = (u32 *)fbi->screen_base;
@@ -1812,6 +1852,22 @@ err:
return ret;
}
+static inline void wait_for_vsync(struct mxc_vout_output *vout)
+{
+ struct fb_info *fbi = vout->fbi;
+ mm_segment_t old_fs;
+
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned long)NULL);
+ set_fs(old_fs);
+ }
+
+ return;
+}
+
static void release_disp_output(struct mxc_vout_output *vout)
{
struct fb_info *fbi = vout->fbi;
@@ -1871,14 +1927,14 @@ static int mxc_vidioc_streamon(struct file *file, void *fh,
goto done;
}
- init_timer(&vout->timer);
+ hrtimer_init(&vout->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
vout->timer.function = mxc_vout_timer_handler;
- vout->timer.data = (unsigned long)vout;
vout->timer_stop = true;
- vout->start_jiffies = jiffies;
+ vout->start_ktime = hrtimer_cb_get_time(&vout->timer);
- vout->pre_vb = NULL;
+ vout->pre1_vb = NULL;
+ vout->pre2_vb = NULL;
ret = videobuf_streamon(q);
done:
@@ -1893,10 +1949,17 @@ static int mxc_vidioc_streamoff(struct file *file, void *fh,
int ret = 0;
if (q->streaming) {
- cancel_work_sync(&vout->disp_work);
flush_workqueue(vout->v4l_wq);
- del_timer_sync(&vout->timer);
+ hrtimer_cancel(&vout->timer);
+
+ /*
+ * Wait for 2 vsyncs to make sure
+ * frames are drained on triple
+ * buffer.
+ */
+ wait_for_vsync(vout);
+ wait_for_vsync(vout);
release_disp_output(vout);
@@ -2048,9 +2111,13 @@ static int mxc_vout_probe(struct platform_device *pdev)
return -ENOMEM;
dev->dev = &pdev->dev;
- dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask), GFP_KERNEL);
- *dev->dev->dma_mask = DMA_BIT_MASK(32);
- dev->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ if (!dev->dev->dma_mask) {
+ dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask),
+ GFP_KERNEL);
+ if (dev->dev->dma_mask)
+ *dev->dev->dma_mask = DMA_BIT_MASK(32);
+ dev->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ }
ret = v4l2_device_register(dev->dev, &dev->v4l2_dev);
if (ret) {
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index af7ff78c9259..2a5623c5a213 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -284,7 +284,8 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
mem->size = PAGE_ALIGN(buf->bsize);
mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
- &mem->dma_handle, GFP_DMA);
+ &mem->dma_handle,
+ GFP_DMA | GFP_KERNEL | __GFP_NOFAIL);
if (!mem->vaddr) {
dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
mem->size);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a2f4b13bce21..8c1d5b2502c2 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -496,7 +496,7 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int err, busy = 0;
- u32 part, new_part;
+ u32 part;
u8 *ext_csd, boot_config;
struct mmc_command cmd;
struct mmc_card *card = container_of(dev, struct mmc_card, dev);
@@ -514,12 +514,28 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr,
/* it's a normal SD/MMC but user request to configure boot partition */
if (card->ext_csd.boot_size <= 0) {
- printk(KERN_ERR "%s: this is a normal SD/MMC card"
- " but you request to access boot partition!\n",
+ pr_err("%s: fail to send SWITCH command to card " \
+ "to update boot_config of the EXT_CSD!\n",
mmc_hostname(card->host));
return -EINVAL;
}
+ /*
+ * partition must be -
+ * 0 - user area
+ * 1 - boot partition 1
+ * 2 - boot partition 2
+ * DO NOT switch the partitions that used to be accessed
+ * in OS layer HERE
+ */
+ if (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) {
+ pr_err("%s: DO NOT switch the partitions that used to be\n" \
+ " accessed in OS layer HERE. please following the\n" \
+ " guidance of Documentation/mmc/mmc-dev-parts.txt.\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
printk(KERN_ERR "%s: could not allocate a buffer to "
@@ -574,29 +590,11 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr,
goto err_rtn;
}
- /* switch the partitions that used to be accessed in OS layer */
- /* partition must be -
- * 0 - user area
- * 1 - boot partition 1
- * 2 - boot partition 2
- */
- if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) > 2) {
- printk(KERN_ERR "%s: wrong partition id"
- " 0 (user area), 1 (boot1), 2 (boot2)\n",
- mmc_hostname(card->host));
- err = -EINVAL;
- goto err_rtn;
- }
-
-
- /* Send SWITCH command to change partition for access */
- boot_config &= ~EXT_CSD_BOOT_PARTITION_ACCESS_MASK;
- boot_config |= (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, boot_config, card->ext_csd.part_time);
if (err) {
- printk(KERN_ERR "%s: fail to send SWITCH command"
- " to card to swich partition for access!\n",
+ pr_err("%s: fail to send SWITCH command to card " \
+ "to update boot_config of the EXT_CSD!\n",
mmc_hostname(card->host));
goto err_rtn;
}
@@ -634,14 +632,6 @@ setup_boot_partitions(struct device *dev, struct device_attribute *attr,
goto err_rtn;
}
- new_part = ext_csd[EXT_CSD_PART_CONFIG] &
- EXT_CSD_BOOT_PARTITION_ACCESS_MASK;
- if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) != new_part) {
- printk(KERN_ERR "%s: after SWITCH, current part id %d is not"
- " same as requested partition %d!\n",
- mmc_hostname(card->host), new_part, part);
- goto err_rtn;
- }
card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG];
err_rtn:
@@ -669,8 +659,8 @@ setup_boot_bus(struct device *dev, struct device_attribute *attr,
sscanf(buf, "%d\n", &boot_bus);
if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
- printk(KERN_ERR "%s: invalid mmc version"
- " mmc version is below version 4!)\n",
+ pr_err("%s: fail to send SWITCH command to card " \
+ "to update boot_config of the EXT_CSD!\n",
mmc_hostname(card->host));
return -EINVAL;
}
@@ -794,16 +784,6 @@ static ssize_t mmc_boot_info_show(struct device *dev,
"Reserved",
"User area enabled for boot"};
- char *boot_partition_access[8] = {
- "No access to boot partition",
- "R/W boot partition 1",
- "R/W boot partition 2",
- "R/W Replay Protected Memory Block (RPMB)",
- "Access to General Purpose partition 1",
- "Access to General Purpose partition 2",
- "Access to General Purpose partition 3",
- "Access to General Purpose partition 4"};
-
char *bus_width[4] = {
"x1 (sdr) or x4 (ddr) bus width in boot operation mode",
"x4 (sdr/ddr) bus width in boot operation mode",
@@ -817,7 +797,6 @@ static ssize_t mmc_boot_info_show(struct device *dev,
"Reserved"};
int partition;
- int access;
int width;
int mode;
u8 *ext_csd = NULL;
@@ -830,7 +809,6 @@ static ssize_t mmc_boot_info_show(struct device *dev,
mmc_read_ext_csd(card, ext_csd);
partition = (card->ext_csd.boot_config >> 3) & 0x7;
- access = card->ext_csd.boot_config & 0x7;
width = card->ext_csd.boot_bus_width & 0x3;
mode = (card->ext_csd.boot_bus_width >> 3) & 0x3;
@@ -843,7 +821,6 @@ static ssize_t mmc_boot_info_show(struct device *dev,
"boot_partition:0x%02x;\n"
" BOOT_ACK:%x - %s\n"
" BOOT_PARTITION-ENABLE: %x - %s\n"
- " PARTITION_ACCESS:%x - %s\n"
"boot_bus:0x%02x\n"
" BOOT_MODE:%x - %s\n"
" RESET_BOOT_BUS_WIDTH:%x - %s\n"
@@ -872,8 +849,6 @@ static ssize_t mmc_boot_info_show(struct device *dev,
"No boot acknowledge sent",
partition,
boot_partition[partition],
- access,
- boot_partition_access[access],
card->ext_csd.boot_bus_width,
mode,
diff --git a/drivers/mxc/asrc/mxc_asrc.c b/drivers/mxc/asrc/mxc_asrc.c
index ecfd236b3e1b..ea6573867a5c 100644
--- a/drivers/mxc/asrc/mxc_asrc.c
+++ b/drivers/mxc/asrc/mxc_asrc.c
@@ -53,18 +53,18 @@ DEFINE_SPINLOCK(pair_lock);
DEFINE_SPINLOCK(input_int_lock);
DEFINE_SPINLOCK(output_int_lock);
-#define AICPA 0 /* Input Clock Divider A Offset */
-#define AICDA 3 /* Input Clock Prescaler A Offset */
-#define AICPB 6 /* Input Clock Divider B Offset */
-#define AICDB 9 /* Input Clock Prescaler B Offset */
-#define AOCPA 12 /* Output Clock Divider A Offset */
-#define AOCDA 15 /* Output Clock Prescaler A Offset */
-#define AOCPB 18 /* Output Clock Divider B Offset */
-#define AOCDB 21 /* Output Clock Prescaler B Offset */
-#define AICPC 0 /* Input Clock Divider C Offset */
-#define AICDC 3 /* Input Clock Prescaler C Offset */
-#define AOCDC 6 /* Output Clock Prescaler C Offset */
-#define AOCPC 9 /* Output Clock Divider C Offset */
+#define AICPA 0 /* Input Clock Prescaler A Offset */
+#define AICDA 3 /* Input Clock Divider A Offset */
+#define AICPB 6 /* Input Clock Prescaler B Offset */
+#define AICDB 9 /* Input Clock Divider B Offset */
+#define AOCPA 12 /* Output Clock Prescaler A Offset */
+#define AOCDA 15 /* Output Clock Divider A Offset */
+#define AOCPB 18 /* Output Clock Prescaler B Offset */
+#define AOCDB 21 /* Output Clock Divider B Offset */
+#define AICPC 0 /* Input Clock Prescaler C Offset */
+#define AICDC 3 /* Input Clock Divider C Offset */
+#define AOCPC 6 /* Output Clock Prescaler C Offset */
+#define AOCDC 9 /* Output Clock Divider C Offset */
char *asrc_pair_id[] = {
[0] = "ASRC RX PAIR A",
@@ -144,12 +144,15 @@ static unsigned char output_clk_map_v1[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
};
+/* V2 uses the same map for input and output */
static unsigned char input_clk_map_v2[] = {
- 0, 1, 2, 3, 4, 5, 0xf, 0xf, 0xf, 8, 9, 0xa, 0xb, 0xc, 0xf, 0xd,
+/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf*/
+ 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd,
};
static unsigned char output_clk_map_v2[] = {
- 8, 9, 0xa, 0, 0xc, 0x5, 0xf, 0xf, 0, 1, 2, 0xf, 0xf, 4, 0xf, 0xd,
+/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf*/
+ 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd,
};
static unsigned char *input_clk_map, *output_clk_map;
@@ -318,34 +321,42 @@ int asrc_req_pair(int chn_num, enum asrc_pair_index *index)
int err = 0;
unsigned long lock_flags;
struct asrc_pair *pair;
+ int imax = 0, busy = 0, i;
+
spin_lock_irqsave(&data_lock, lock_flags);
- if (chn_num > 2) {
- pair = &g_asrc->asrc_pair[ASRC_PAIR_B];
- if (pair->active || (chn_num > pair->chn_max))
- err = -EBUSY;
- else {
- *index = ASRC_PAIR_B;
- pair->chn_num = chn_num;
- pair->active = 1;
+ for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) {
+ pair = &g_asrc->asrc_pair[i];
+ if (chn_num > pair->chn_max) {
+ imax++;
+ continue;
+ } else if (pair->active) {
+ busy++;
+ continue;
}
+ /* Save the current qualified pair */
+ *index = i;
+
+ /* Check if this pair is a perfect one */
+ if (chn_num == pair->chn_max)
+ break;
+ }
+
+ if (imax >= ASRC_PAIR_MAX_NUM) {
+ pr_err("No pair could afford requested channel number.\n");
+ err = -EINVAL;
+ } else if (busy >= ASRC_PAIR_MAX_NUM) {
+ pr_err("All pairs are busy now.\n");
+ err = -EBUSY;
+ } else if (busy + imax >= ASRC_PAIR_MAX_NUM) {
+ pr_err("All affordable pairs are busy now.\n");
+ err = -EBUSY;
} else {
- pair = &g_asrc->asrc_pair[ASRC_PAIR_A];
- if (pair->active || (pair->chn_max == 0)) {
- pair = &g_asrc->asrc_pair[ASRC_PAIR_C];
- if (pair->active || (pair->chn_max == 0))
- err = -EBUSY;
- else {
- *index = ASRC_PAIR_C;
- pair->chn_num = 2;
- pair->active = 1;
- }
- } else {
- *index = ASRC_PAIR_A;
- pair->chn_num = 2;
- pair->active = 1;
- }
+ pair = &g_asrc->asrc_pair[*index];
+ pair->chn_num = chn_num;
+ pair->active = 1;
}
+
spin_unlock_irqrestore(&data_lock, lock_flags);
if (!err) {
@@ -381,6 +392,9 @@ int asrc_config_pair(struct asrc_config *config)
int err = 0;
int reg, tmp, channel_num;
unsigned long lock_flags;
+ unsigned long aicp_shift, aocp_shift;
+ unsigned long asrc_asrcdr_reg, dp_clear_mask;
+
/* Set the channel number */
reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCNCR_REG);
spin_lock_irqsave(&data_lock, lock_flags);
@@ -426,142 +440,68 @@ int asrc_config_pair(struct asrc_config *config)
__raw_writel(reg, g_asrc->vaddr + ASRC_ASRCTR_REG);
/* Default Clock Divider Setting */
- reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR1_REG);
- if (config->pair == ASRC_PAIR_A) {
- reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR1_REG);
- reg &= 0xfc0fc0;
- /* Input Part */
- if ((config->inclk & 0x0f) == INCLK_SPDIF_RX)
- reg |= 7 << AICPA;
- else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX)
- reg |= 6 << AICPA;
- else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) {
- tmp =
- asrc_get_asrck_clock_divider(config->
- input_sample_rate);
- reg |= tmp << AICPA;
- } else {
- if (config->input_word_width == ASRC_WIDTH_16_BIT)
- reg |= 5 << AICPA;
- else if (config->input_word_width == ASRC_WIDTH_24_BIT)
- reg |= 6 << AICPA;
- else
- err = -EFAULT;
- }
- /* Output Part */
- if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX)
- reg |= 7 << AOCPA;
- else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX)
- reg |= 6 << AOCPA;
- else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) &&
- ((config->inclk & 0x0f) == INCLK_NONE))
- reg |= 5 << AOCPA;
- else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) {
- tmp =
- asrc_get_asrck_clock_divider(config->
- output_sample_rate);
- reg |= tmp << AOCPA;
- } else {
- if (config->output_word_width == ASRC_WIDTH_16_BIT)
- reg |= 5 << AOCPA;
- else if (config->output_word_width == ASRC_WIDTH_24_BIT)
- reg |= 6 << AOCPA;
- else
- err = -EFAULT;
- }
-
- __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCDR1_REG);
-
- } else if (config->pair == ASRC_PAIR_B) {
- reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR1_REG);
- reg &= 0x03f03f;
- /* Input Part */
- if ((config->inclk & 0x0f) == INCLK_SPDIF_RX)
- reg |= 7 << AICPB;
- else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX)
- reg |= 6 << AICPB;
- else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) {
- tmp =
- asrc_get_asrck_clock_divider(config->
- input_sample_rate);
- reg |= tmp << AICPB;
- } else {
- if (config->input_word_width == ASRC_WIDTH_16_BIT)
- reg |= 5 << AICPB;
- else if (config->input_word_width == ASRC_WIDTH_24_BIT)
- reg |= 6 << AICPB;
- else
- err = -EFAULT;
- }
- /* Output Part */
- if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX)
- reg |= 7 << AOCPB;
- else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX)
- reg |= 6 << AOCPB;
- else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) &&
- ((config->inclk & 0x0f) == INCLK_NONE))
- reg |= 5 << AOCPB;
- else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) {
- tmp =
- asrc_get_asrck_clock_divider(config->
- output_sample_rate);
- reg |= tmp << AOCPB;
- } else {
- if (config->output_word_width == ASRC_WIDTH_16_BIT)
- reg |= 5 << AOCPB;
- else if (config->output_word_width == ASRC_WIDTH_24_BIT)
- reg |= 6 << AOCPB;
- else
- err = -EFAULT;
- }
-
- __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCDR1_REG);
+ switch (config->pair) {
+ case ASRC_PAIR_A:
+ asrc_asrcdr_reg = ASRC_ASRCDR1_REG;
+ dp_clear_mask = 0xfc0fc0;
+ aicp_shift = AICPA;
+ aocp_shift = AOCPA;
+ break;
+ case ASRC_PAIR_B:
+ asrc_asrcdr_reg = ASRC_ASRCDR1_REG;
+ dp_clear_mask = 0x03f03f;
+ aicp_shift = AICPB;
+ aocp_shift = AOCPB;
+ break;
+ case ASRC_PAIR_C:
+ asrc_asrcdr_reg = ASRC_ASRCDR2_REG;
+ dp_clear_mask = 0x00;
+ aicp_shift = AICPC;
+ aocp_shift = AOCPC;
+ break;
+ default:
+ pr_err("Invalid Pair number %d\n", config->pair);
+ return -EFAULT;
+ }
+ reg = __raw_readl(g_asrc->vaddr + asrc_asrcdr_reg);
+ reg &= dp_clear_mask;
+ /* Input Part */
+ if ((config->inclk & 0x0f) == INCLK_SPDIF_RX)
+ reg |= 7 << aicp_shift;
+ else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX)
+ reg |= 6 << aicp_shift;
+ else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) {
+ tmp = asrc_get_asrck_clock_divider(config->input_sample_rate);
+ reg |= tmp << aicp_shift;
} else {
- reg = __raw_readl(g_asrc->vaddr + ASRC_ASRCDR2_REG);
- reg &= 0;
- /* Input Part */
- if ((config->inclk & 0x0f) == INCLK_SPDIF_RX)
- reg |= 7 << AICPC;
- else if ((config->inclk & 0x0f) == INCLK_SPDIF_TX)
- reg |= 6 << AICPC;
- else if ((config->inclk & 0x0f) == INCLK_ASRCK1_CLK) {
- tmp =
- asrc_get_asrck_clock_divider(config->
- input_sample_rate);
- reg |= tmp << AICPC;
- } else {
- if (config->input_word_width == ASRC_WIDTH_16_BIT)
- reg |= 5 << AICPC;
- else if (config->input_word_width == ASRC_WIDTH_24_BIT)
- reg |= 6 << AICPC;
- else
- err = -EFAULT;
- }
- /* Output Part */
- if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX)
- reg |= 7 << AOCPC;
- else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX)
- reg |= 6 << AOCPC;
- else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) &&
- ((config->inclk & 0x0f) == INCLK_NONE))
- reg |= 5 << AOCPC;
- else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) {
- tmp =
- asrc_get_asrck_clock_divider(config->
- output_sample_rate);
- reg |= tmp << AOCPC;
- } else {
- if (config->output_word_width == ASRC_WIDTH_16_BIT)
- reg |= 5 << AOCPC;
- else if (config->output_word_width == ASRC_WIDTH_24_BIT)
- reg |= 6 << AOCPC;
- else
- err = -EFAULT;
- }
- __raw_writel(reg, g_asrc->vaddr + ASRC_ASRCDR2_REG);
-
+ if (config->input_word_width == ASRC_WIDTH_16_BIT)
+ reg |= 5 << aicp_shift;
+ else if (config->input_word_width == ASRC_WIDTH_24_BIT)
+ reg |= 6 << aicp_shift;
+ else
+ err = -EFAULT;
}
+ /* Output Part */
+ if ((config->outclk & 0x0f) == OUTCLK_SPDIF_RX)
+ reg |= 7 << aocp_shift;
+ else if ((config->outclk & 0x0f) == OUTCLK_SPDIF_TX)
+ reg |= 6 << aocp_shift;
+ else if (((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK)
+ && ((config->inclk & 0x0f) == INCLK_NONE))
+ reg |= 5 << aocp_shift;
+ else if ((config->outclk & 0x0f) == OUTCLK_ASRCK1_CLK) {
+ tmp = asrc_get_asrck_clock_divider(config->output_sample_rate);
+ reg |= tmp << aocp_shift;
+ } else {
+ if (config->output_word_width == ASRC_WIDTH_16_BIT)
+ reg |= 5 << aocp_shift;
+ else if (config->output_word_width == ASRC_WIDTH_24_BIT)
+ reg |= 6 << aocp_shift;
+ else
+ err = -EFAULT;
+ }
+ __raw_writel(reg, g_asrc->vaddr + asrc_asrcdr_reg);
/* check whether ideal ratio is a must */
if ((config->inclk & 0x0f) == INCLK_NONE) {
@@ -597,25 +537,6 @@ int asrc_config_pair(struct asrc_config *config)
}
}
- 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 |= (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 */
reg = __raw_readl(
g_asrc->vaddr + ASRC_ASRMCR1A_REG + (config->pair << 2));
@@ -877,10 +798,10 @@ static int mxc_init_asrc(void)
__raw_writel(0x001f00, g_asrc->vaddr + ASRC_ASRTFR1);
/* Set the processing clock for 76KHz, 133M */
- __raw_writel(0x30E, g_asrc->vaddr + ASRC_ASR76K_REG);
+ __raw_writel(0x06D6, g_asrc->vaddr + ASRC_ASR76K_REG);
/* Set the processing clock for 56KHz, 133M */
- __raw_writel(0x0426, g_asrc->vaddr + ASRC_ASR56K_REG);
+ __raw_writel(0x0947, g_asrc->vaddr + ASRC_ASR56K_REG);
return 0;
}
@@ -1035,7 +956,7 @@ static void mxc_free_dma_buf(struct asrc_pair_params *params)
}
if (params->output_dma_total.dma_vaddr != NULL) {
- kfree(params->input_dma_total.dma_vaddr);
+ kfree(params->output_dma_total.dma_vaddr);
params->output_dma_total.dma_vaddr = NULL;
}
@@ -1847,13 +1768,26 @@ static int asrc_write_proc_attr(struct file *file, const char *buffer,
total = 10;
else
total = 5;
- if ((na + nb + nc) != total) {
- pr_info("Wrong ASRCNR settings\n");
- return -EFAULT;
+
+ if ((na + nb + nc) > total) {
+ pr_err("Don't surpass %d for total.\n", total);
+ return -EINVAL;
+ } else if (na % 2 != 0 || nb % 2 != 0 || nc % 2 != 0) {
+ pr_err("Please set an even number for each pair.\n");
+ return -EINVAL;
+ } else if (na < 0 || nb < 0 || nc < 0) {
+ pr_err("Please set an positive number for each pair.\n");
+ return -EINVAL;
}
+
reg = na | (nb << g_asrc->mxc_asrc_data->channel_bits) |
(nc << (g_asrc->mxc_asrc_data->channel_bits * 2));
+ /* Update chn_max */
+ g_asrc->asrc_pair[ASRC_PAIR_A].chn_max = na;
+ g_asrc->asrc_pair[ASRC_PAIR_B].chn_max = nb;
+ g_asrc->asrc_pair[ASRC_PAIR_C].chn_max = nc;
+
clk_enable(g_asrc->mxc_asrc_data->asrc_core_clk);
__raw_writel(reg, g_asrc->vaddr + ASRC_ASRCNCR_REG);
clk_disable(g_asrc->mxc_asrc_data->asrc_core_clk);
diff --git a/drivers/mxc/gpu-viv/Kbuild b/drivers/mxc/gpu-viv/Kbuild
index 0b18a7bdcc49..93b12591986d 100644
--- a/drivers/mxc/gpu-viv/Kbuild
+++ b/drivers/mxc/gpu-viv/Kbuild
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (C) 2005 - 2012 by Vivante Corp.
+# Copyright (C) 2005 - 2013 by Vivante Corp.
#
# 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
diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c
index c768d8b2b420..3e2acf2f725c 100644
--- a/drivers/mxc/ipu3/ipu_capture.c
+++ b/drivers/mxc/ipu3/ipu_capture.c
@@ -98,6 +98,7 @@ ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
break;
case IPU_PIX_FMT_GENERIC:
+ case IPU_PIX_FMT_GENERIC_16:
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
break;
case IPU_PIX_FMT_RGB565:
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index 563d5320cc9d..e914a9b7baa3 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -110,6 +110,17 @@ static inline int _ipu_is_primary_disp_chan(uint32_t dma_chan)
(dma_chan == 28) || (dma_chan == 41));
}
+static inline int _ipu_is_sync_irq(uint32_t irq)
+{
+ /* sync interrupt register number */
+ int reg_num = irq / 32 + 1;
+
+ return ((reg_num == 1) || (reg_num == 2) || (reg_num == 3) ||
+ (reg_num == 4) || (reg_num == 7) || (reg_num == 8) ||
+ (reg_num == 11) || (reg_num == 12) || (reg_num == 13) ||
+ (reg_num == 14) || (reg_num == 15));
+}
+
#define idma_is_valid(ch) (ch != NO_DMA)
#define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0)
#define idma_is_set(ipu, reg, dma) (ipu_idmac_read(ipu, reg(dma)) & idma_mask(dma))
@@ -1166,10 +1177,17 @@ int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
rot_mode);
} else if (_ipu_is_smfc_chan(dma_chan)) {
burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
- if ((pixel_fmt == IPU_PIX_FMT_GENERIC) &&
- ((_ipu_ch_param_get_bpp(ipu, dma_chan) == 5) ||
- (_ipu_ch_param_get_bpp(ipu, dma_chan) == 3)))
+ /*
+ * This is different from IPUv3 spec, but it is confirmed
+ * in IPUforum that SMFC burst size should be NPB[6:3]
+ * when IDMAC works in 16-bit generic data mode.
+ */
+ if (pixel_fmt == IPU_PIX_FMT_GENERIC)
+ /* 8 bits per pixel */
burst_size = burst_size >> 4;
+ else if (pixel_fmt == IPU_PIX_FMT_GENERIC_16)
+ /* 16 bits per pixel */
+ burst_size = burst_size >> 3;
else
burst_size = burst_size >> 2;
_ipu_smfc_set_burst_size(ipu, channel, burst_size-1);
@@ -2458,23 +2476,40 @@ static irqreturn_t ipu_err_irq_handler(int irq, void *desc)
* @param ipu ipu handler
* @param irq Interrupt line to enable interrupt for.
*
+ * @return This function returns 0 on success or negative error code on
+ * fail.
*/
-void ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq)
+int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq)
{
uint32_t reg;
unsigned long lock_flags;
+ int ret = 0;
_ipu_get(ipu);
spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+ /*
+ * Check sync interrupt handler only, since we do nothing for
+ * error interrupts but than print out register values in the
+ * error interrupt source handler.
+ */
+ if (_ipu_is_sync_irq(irq) && (ipu->irq_list[irq].handler == NULL)) {
+ dev_err(ipu->dev, "handler hasn't been registered on sync "
+ "irq %d\n", irq);
+ ret = -EACCES;
+ goto out;
+ }
+
reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
reg |= IPUIRQ_2_MASK(irq);
ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
-
+out:
spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
_ipu_put(ipu);
+
+ return ret;
}
EXPORT_SYMBOL(ipu_enable_irq);
@@ -2586,6 +2621,7 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
{
uint32_t reg;
unsigned long lock_flags;
+ int ret = 0;
BUG_ON(irq >= IPU_IRQ_COUNT);
@@ -2596,8 +2632,19 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
if (ipu->irq_list[irq].handler != NULL) {
dev_err(ipu->dev,
"handler already installed on irq %d\n", irq);
- spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Check sync interrupt handler only, since we do nothing for
+ * error interrupts but than print out register values in the
+ * error interrupt source handler.
+ */
+ if (_ipu_is_sync_irq(irq) && (handler == NULL)) {
+ dev_err(ipu->dev, "handler is NULL for sync irq %d\n", irq);
+ ret = -EINVAL;
+ goto out;
}
ipu->irq_list[irq].handler = handler;
@@ -2611,12 +2658,12 @@ int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
reg |= IPUIRQ_2_MASK(irq);
ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
-
+out:
spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
_ipu_put(ipu);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(ipu_request_irq);
@@ -2791,6 +2838,7 @@ uint32_t bytes_per_pixel(uint32_t fmt)
case IPU_PIX_FMT_YUV444P:
return 1;
break;
+ case IPU_PIX_FMT_GENERIC_16: /* generic data */
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
@@ -2798,6 +2846,7 @@ uint32_t bytes_per_pixel(uint32_t fmt)
break;
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_YUV444:
return 3;
break;
case IPU_PIX_FMT_GENERIC_32: /*generic data */
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
index cdf76b0ca68c..b10ce2a16f3a 100644
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -680,6 +680,11 @@ static void dump_check_warn(struct device *dev, int warn)
static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
{
+ if ((width == 0) || (height == 0)) {
+ pr_err("Invalid param: width=%d, height=%d\n", width, height);
+ return -EINVAL;
+ }
+
if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
(IPU_PIX_FMT_TILED_NV12F == fmt)) {
if (crop->w || crop->h) {
@@ -719,6 +724,12 @@ static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
crop->h -= crop->h%8;
}
+ if ((crop->w == 0) || (crop->h == 0)) {
+ pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
+ crop->w, crop->h);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -733,26 +744,28 @@ static void update_offset(unsigned int fmt,
case IPU_PIX_FMT_YUV420P:
*off = pos_y * width + pos_x;
*uoff = (width * (height - pos_y) - pos_x)
- + ((width/2 * pos_y/2) + pos_x/2);
- *voff = *uoff + (width/2 * height/2);
+ + (width/2) * (pos_y/2) + pos_x/2;
+ /* In case height is odd, round up to even */
+ *voff = *uoff + (width/2) * ((height+1)/2);
break;
case IPU_PIX_FMT_YVU420P:
*off = pos_y * width + pos_x;
*voff = (width * (height - pos_y) - pos_x)
- + ((width/2 * pos_y/2) + pos_x/2);
- *uoff = *voff + (width/2 * height/2);
+ + (width/2) * (pos_y/2) + pos_x/2;
+ /* In case height is odd, round up to even */
+ *uoff = *voff + (width/2) * ((height+1)/2);
break;
case IPU_PIX_FMT_YVU422P:
*off = pos_y * width + pos_x;
*voff = (width * (height - pos_y) - pos_x)
- + ((width * pos_y)/2 + pos_x/2);
- *uoff = *voff + (width * height)/2;
+ + (width/2) * pos_y + pos_x/2;
+ *uoff = *voff + (width/2) * height;
break;
case IPU_PIX_FMT_YUV422P:
*off = pos_y * width + pos_x;
*uoff = (width * (height - pos_y) - pos_x)
- + (width * pos_y)/2 + pos_x/2;
- *voff = *uoff + (width * height)/2;
+ + (width/2) * pos_y + pos_x/2;
+ *voff = *uoff + (width/2) * height;
break;
case IPU_PIX_FMT_YUV444P:
*off = pos_y * width + pos_x;
@@ -762,7 +775,7 @@ static void update_offset(unsigned int fmt,
case IPU_PIX_FMT_NV12:
*off = pos_y * width + pos_x;
*uoff = (width * (height - pos_y) - pos_x)
- + width * pos_y/2 + pos_x;
+ + width * (pos_y/2) + pos_x;
break;
case IPU_PIX_FMT_TILED_NV12:
/*
@@ -799,6 +812,7 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
struct stripe_param down_stripe;
u32 iw, ih, ow, oh;
u32 max_width;
+ int ret;
if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
return IPU_CHECK_ERR_SPLIT_WITH_ROT;
@@ -809,12 +823,26 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
ow = t->output.crop.w;
oh = t->output.crop.h;
+ memset(&left_stripe, 0, sizeof(left_stripe));
+ memset(&right_stripe, 0, sizeof(right_stripe));
+ memset(&up_stripe, 0, sizeof(up_stripe));
+ memset(&down_stripe, 0, sizeof(down_stripe));
+
if (t->set.split_mode & RL_SPLIT) {
+ /*
+ * We do want equal strips: initialize stripes in case
+ * calc_stripes returns before actually doing the calculation
+ */
+ left_stripe.input_width = iw / 2;
+ left_stripe.output_width = ow / 2;
+ right_stripe.input_column = iw / 2;
+ right_stripe.output_column = ow / 2;
+
if (vdi_split)
max_width = soc_max_vdi_in_width();
else
max_width = soc_max_out_width();
- ipu_calc_stripes_sizes(iw,
+ ret = ipu_calc_stripes_sizes(iw,
ow,
max_width,
(((unsigned long long)1) << 32), /* 32bit for fractional*/
@@ -823,6 +851,9 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
t->output.format,
&left_stripe,
&right_stripe);
+ if (ret)
+ dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+ t->task_no, ret);
t->set.sp_setting.iw = left_stripe.input_width;
t->set.sp_setting.ow = left_stripe.output_width;
t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
@@ -846,7 +877,15 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
if (t->set.split_mode & UD_SPLIT) {
- ipu_calc_stripes_sizes(ih,
+ /*
+ * We do want equal strips: initialize stripes in case
+ * calc_stripes returns before actually doing the calculation
+ */
+ up_stripe.input_width = ih / 2;
+ up_stripe.output_width = oh / 2;
+ down_stripe.input_column = ih / 2;
+ down_stripe.output_column = oh / 2;
+ ret = ipu_calc_stripes_sizes(ih,
oh,
soc_max_out_height(),
(((unsigned long long)1) << 32), /* 32bit for fractional*/
@@ -855,6 +894,9 @@ static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
t->output.format,
&up_stripe,
&down_stripe);
+ if (ret)
+ dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+ t->task_no, ret);
t->set.sp_setting.ih = up_stripe.input_width;
t->set.sp_setting.oh = up_stripe.output_width;
t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c
index 35b78199b0df..87fa001b8246 100644
--- a/drivers/mxc/ipu3/ipu_disp.c
+++ b/drivers/mxc/ipu3/ipu_disp.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -61,7 +61,7 @@ static unsigned long _ipu_pixel_clk_get_rate(struct clk *clk)
{
struct ipu_soc *ipu = pixelclk2ipu(clk);
u32 div;
- u64 final_rate = clk_get_rate(clk->parent) * 16;
+ u64 final_rate = (unsigned long long)clk_get_rate(clk->parent) * 16;
_ipu_get(ipu);
div = ipu_di_read(ipu, clk->id, DI_BS_CLKGEN0);
@@ -1297,6 +1297,10 @@ int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk,
msleep(5);
/* Get integer portion of divider */
div = clk_get_rate(clk_get_parent(&ipu->pixel_clk[disp])) / rounded_pixel_clk;
+ if (!div) {
+ dev_err(ipu->dev, "invalid pixel clk div = 0\n");
+ return -EINVAL;
+ }
mutex_lock(&ipu->mutex_lock);
diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h
index 1387c4948446..6d0a470dfef1 100644
--- a/drivers/mxc/ipu3/ipu_param_mem.h
+++ b/drivers/mxc/ipu3/ipu_param_mem.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -285,6 +285,13 @@ static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
ipu_ch_param_set_field(&params, 1, 78, 7, 63); /* burst size */
break;
+ case IPU_PIX_FMT_GENERIC_16:
+ /* Represents 16-bit generic data */
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ break;
case IPU_PIX_FMT_GENERIC_32:
/*Represents 32-bit Generic data */
break;
@@ -695,6 +702,7 @@ static inline void _ipu_ch_offset_update(struct ipu_soc *ipu,
switch (pixel_fmt) {
case IPU_PIX_FMT_GENERIC:
+ case IPU_PIX_FMT_GENERIC_16:
case IPU_PIX_FMT_GENERIC_32:
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_BGR24:
diff --git a/drivers/mxc/mlb/mxc_mlb150.c b/drivers/mxc/mlb/mxc_mlb150.c
index 6b07d0f0a428..3cc0289c57b8 100755
--- a/drivers/mxc/mlb/mxc_mlb150.c
+++ b/drivers/mxc/mlb/mxc_mlb150.c
@@ -288,8 +288,8 @@ enum CLK_SPEED {
};
struct mlb_ringbuf {
- s8 *virt_bufs[TRANS_RING_NODES + 1];
- u32 phy_addrs[TRANS_RING_NODES + 1];
+ s8 *virt_bufs[TRANS_RING_NODES];
+ u32 phy_addrs[TRANS_RING_NODES];
s32 head;
s32 tail;
s32 unit_size;
@@ -1538,6 +1538,11 @@ static s32 mlb150_trans_complete_check(struct mlb_dev_info *pdevinfo)
return -ETIME;
}
+ /* Interrupt from TX can only inform that the data is sent
+ * to AHB bus, not mean that it is sent to MITB. Thus we add
+ * a delay here for data to be completed sent. */
+ udelay(1000);
+
return 0;
}
@@ -1902,24 +1907,27 @@ static int mxc_mlb150_open(struct inode *inode, struct file *filp)
pr_err("can not alloc rx/tx buffers: %d\n", buf_size);
return ret;
}
+ pr_debug("IRAM Range: Virt 0x%x - 0x%x, Phys 0x%x - 0x%x, size: 0x%x\n",
+ buf_addr, (buf_addr + buf_size - 1), phy_addr,
+ (phy_addr + buf_size - 1), buf_size);
pdevinfo->rbuf_base_virt = buf_addr;
pdevinfo->rbuf_base_phy = phy_addr;
memset(buf_addr, 0, buf_size);
- for (j = 0; j < (TRANS_RING_NODES + 1);
+ for (j = 0; j < (TRANS_RING_NODES);
++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) {
pdevinfo->rx_rbuf.virt_bufs[j] = buf_addr;
pdevinfo->rx_rbuf.phy_addrs[j] = phy_addr;
+ pr_debug("RX Ringbuf[%d]: 0x%x 0x%x\n", j, buf_addr, phy_addr);
}
pdevinfo->rx_rbuf.unit_size = ring_buf_size;
pdevinfo->rx_rbuf.total_size = buf_size;
- buf_addr += ring_buf_size;
- phy_addr += ring_buf_size;
for (j = 0; j < (TRANS_RING_NODES);
++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) {
pdevinfo->tx_rbuf.virt_bufs[j] = buf_addr;
pdevinfo->tx_rbuf.phy_addrs[j] = phy_addr;
+ pr_debug("TX Ringbuf[%d]: 0x%x 0x%x\n", j, buf_addr, phy_addr);
}
pdevinfo->tx_rbuf.unit_size = ring_buf_size;
@@ -2347,9 +2355,8 @@ static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf,
/* Set ADT for TX */
mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
- } else {
+ } else
read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
- }
ret = count;
out:
@@ -2670,10 +2677,10 @@ static int mxc_mlb150_resume(struct platform_device *pdev)
{
struct mlb_data *drvdata = platform_get_drvdata(pdev);
- mlb150_dev_init();
-
clk_enable(drvdata->clk_mlb6p);
+ mlb150_dev_init();
+
return 0;
}
#else
diff --git a/drivers/mxc/thermal/thermal.c b/drivers/mxc/thermal/thermal.c
index 4931ce1fa252..0cc5e5973271 100644
--- a/drivers/mxc/thermal/thermal.c
+++ b/drivers/mxc/thermal/thermal.c
@@ -277,6 +277,7 @@ static int anatop_thermal_get_temp(struct thermal_zone_device *thermal,
struct anatop_thermal *tz = thermal->devdata;
unsigned int tmp;
unsigned int reg;
+ unsigned int val;
if (!tz)
return -EINVAL;
@@ -311,11 +312,16 @@ static int anatop_thermal_get_temp(struct thermal_zone_device *thermal,
anatop_base + HW_ANADIG_TEMPSENSE0_SET);
tmp = 0;
+ val = jiffies;
/* read temperature values */
while ((__raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0)
- & BM_ANADIG_TEMPSENSE0_FINISHED) == 0)
+ & BM_ANADIG_TEMPSENSE0_FINISHED) == 0) {
+ if (time_after(jiffies, (unsigned long)(val + HZ / 2))) {
+ pr_info("Thermal sensor timeout, retry!\n");
+ return 0;
+ }
msleep(10);
-
+ }
reg = __raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0);
tmp = (reg & BM_ANADIG_TEMPSENSE0_TEMP_VALUE)
>> BP_ANADIG_TEMPSENSE0_TEMP_VALUE;
@@ -339,6 +345,11 @@ static int anatop_thermal_get_temp(struct thermal_zone_device *thermal,
*temp = (cooling_device_disable && tz->temperature >= KELVIN_TO_CEL(TEMP_CRITICAL, KELVIN_OFFSET)) ?
KELVIN_TO_CEL(TEMP_CRITICAL - 1, KELVIN_OFFSET) : tz->temperature;
+ /* Set alarm threshold if necessary */
+ if ((__raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0) &
+ BM_ANADIG_TEMPSENSE0_ALARM_VALUE) == 0)
+ anatop_update_alarm(raw_critical);
+
return 0;
}
@@ -883,7 +894,7 @@ static int anatop_thermal_counting_ratio(unsigned int fuse_data)
raw_hot = (fuse_data & 0xfff00) >> 8;
hot_temp = fuse_data & 0xff;
- if (!calibration_valid && !cpu_is_mx6sl())
+ if (!calibration_valid)
/*
* The universal equation for thermal sensor
* is slope = 0.4297157 - (0.0015976 * 25C fuse),
@@ -901,7 +912,6 @@ static int anatop_thermal_counting_ratio(unsigned int fuse_data)
/* Init default critical temp to set alarm */
raw_critical = raw_25c - ratio * (KELVIN_TO_CEL(TEMP_CRITICAL, KELVIN_OFFSET) - 25) / 100;
clk_enable(pll3_clk);
- anatop_update_alarm(raw_critical);
return ret;
}
diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c
index 708e8e97112a..8c36d6abf852 100644
--- a/drivers/mxc/vpu/mxc_vpu.c
+++ b/drivers/mxc/vpu/mxc_vpu.c
@@ -126,7 +126,7 @@ static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem)
mem->cpu_addr = (unsigned long)
dma_alloc_coherent(NULL, PAGE_ALIGN(mem->size),
(dma_addr_t *) (&mem->phy_addr),
- GFP_DMA | GFP_KERNEL);
+ GFP_DMA | GFP_KERNEL | __GFP_NOFAIL);
pr_debug("[ALLOC] mem alloc cpu_addr = 0x%x\n", mem->cpu_addr);
if ((void *)(mem->cpu_addr) == NULL) {
printk(KERN_ERR "Physical memory allocation error!\n");
@@ -258,7 +258,7 @@ static int vpu_open(struct inode *inode, struct file *filp)
#ifdef CONFIG_SOC_IMX6Q
clk_enable(vpu_clk);
if (READ_REG(BIT_CUR_PC))
- printk(KERN_DEBUG "Not power off before vpu open!\n");
+ pr_debug("Not power off before vpu open!\n");
clk_disable(vpu_clk);
#endif
}
@@ -528,6 +528,20 @@ static long vpu_ioctl(struct file *filp, u_int cmd,
}
break;
}
+ case VPU_IOC_LOCK_DEV:
+ {
+ u32 lock_en;
+
+ if (get_user(lock_en, (u32 __user *) arg))
+ return -EFAULT;
+
+ if (lock_en)
+ mutex_lock(&vpu_data.lock);
+ else
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
default:
{
printk(KERN_ERR "No such IOCTL, cmd is %d\n", cmd);
@@ -1055,6 +1069,16 @@ static void __exit vpu_exit(void)
vpu_free_dma_buffer(&pic_para_mem);
vpu_free_dma_buffer(&user_data_mem);
+ /* reset VPU state */
+ if (!IS_ERR(vpu_regulator))
+ regulator_enable(vpu_regulator);
+ clk_enable(vpu_clk);
+ if (vpu_plat->reset)
+ vpu_plat->reset();
+ clk_disable(vpu_clk);
+ if (!IS_ERR(vpu_regulator))
+ regulator_disable(vpu_regulator);
+
clk_put(vpu_clk);
platform_driver_unregister(&mxcvpu_driver);
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index ebb09eb9a6f2..d2fea018f927 100755
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -636,7 +636,7 @@ static int fec_rx_poll(struct napi_struct *napi, int budget)
data = (__u8 *)__va(bdp->cbd_bufaddr);
if (bdp->cbd_bufaddr)
- dma_unmap_single(&ndev->dev, bdp->cbd_bufaddr,
+ dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
@@ -664,7 +664,7 @@ static int fec_rx_poll(struct napi_struct *napi, int budget)
netif_receive_skb(skb);
}
- bdp->cbd_bufaddr = dma_map_single(&ndev->dev, data,
+ bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
rx_processing_done:
/* Clear the status flags for this buffer */
@@ -1873,32 +1873,33 @@ fec_probe(struct platform_device *pdev)
if (pdata)
fep->phy_interface = pdata->phy;
-#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO
- gpio_request(pdata->gpio_irq, "gpio_enet_irq");
- gpio_direction_input(pdata->gpio_irq);
+ if (pdata->gpio_irq < 0) {
+ gpio_request(pdata->gpio_irq, "gpio_enet_irq");
+ gpio_direction_input(pdata->gpio_irq);
- irq = gpio_to_irq(pdata->gpio_irq);
- ret = request_irq(irq, fec_enet_interrupt,
- IRQF_TRIGGER_RISING,
- pdev->name, ndev);
- if (ret)
- goto failed_irq;
-#else
- /* This device has up to three irqs on some platforms */
- for (i = 0; i < 3; i++) {
- irq = platform_get_irq(pdev, i);
- if (i && irq < 0)
- break;
- ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev);
- if (ret) {
- while (--i >= 0) {
- irq = platform_get_irq(pdev, i);
- free_irq(irq, ndev);
- }
+ irq = gpio_to_irq(pdata->gpio_irq);
+ ret = request_irq(irq, fec_enet_interrupt,
+ IRQF_TRIGGER_RISING,
+ pdev->name, ndev);
+ if (ret)
goto failed_irq;
+ } else {
+ /* This device has up to three irqs on some platforms */
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (i && irq < 0)
+ break;
+ ret = request_irq(irq, fec_enet_interrupt,
+ IRQF_DISABLED, pdev->name, ndev);
+ if (ret) {
+ while (--i >= 0) {
+ irq = platform_get_irq(pdev, i);
+ free_irq(irq, ndev);
+ }
+ goto failed_irq;
+ }
}
}
-#endif
fep->clk = clk_get(&pdev->dev, "fec_clk");
if (IS_ERR(fep->clk)) {
@@ -1949,15 +1950,15 @@ failed_init:
clk_disable(fep->clk);
clk_put(fep->clk);
failed_clk:
-#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO
- free_irq(irq, ndev);
-#else
- for (i = 0; i < 3; i++) {
- irq = platform_get_irq(pdev, i);
- if (irq > 0)
- free_irq(irq, ndev);
+ if (pdata->gpio_irq < 0)
+ free_irq(irq, ndev);
+ else {
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ free_irq(irq, ndev);
+ }
}
-#endif
failed_irq:
iounmap(fep->hwp);
failed_ioremap:
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 8ab80b70d276..bd356c40cec5 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -631,9 +631,9 @@ static int pfuze100_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
* 02: 8us,
* 03: 16us,
*/
- step_delay >>= 5;
+ step_delay >>= 6;
step_delay &= 0x3;
- step_delay <<= 1;
+ step_delay = 2 << step_delay;
if (pfuze100_regulators[id].voltages[old_sel] <
pfuze100_regulators[id].voltages[new_sel])
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index f3d3d3b4ee5a..e40a8ad0e460 100755
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -70,7 +70,6 @@
#endif
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
DEFINE_MUTEX(udc_resume_mutex);
-extern void usb_debounce_id_vbus(void);
static const char driver_name[] = "fsl-usb2-udc";
static const char driver_desc[] = DRIVER_DESC;
@@ -960,11 +959,8 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
(unsigned)EP_MAX_LENGTH_TRANSFER);
if (NEED_IRAM(req->ep))
*length = min(*length, g_iram_size);
-#ifdef CONFIG_FSL_UTP
+
dtd = dma_pool_alloc_nonbufferable(udc_controller->td_pool, GFP_ATOMIC, dma);
-#else
- dtd = dma_pool_alloc(udc_controller->td_pool, GFP_ATOMIC, dma);
-#endif
if (dtd == NULL)
return dtd;
@@ -3075,10 +3071,10 @@ static int __devinit fsl_udc_probe(struct platform_device *pdev)
* do platform specific init: check the clock, grab/config pins, etc.
*/
if (pdata->init && pdata->init(pdev)) {
- pdata->lowpower = false;
ret = -ENODEV;
goto err2a;
}
+ pdata->lowpower = false;
spin_lock_init(&pdata->lock);
@@ -3234,6 +3230,7 @@ err4:
err3:
free_irq(udc_controller->irq, udc_controller);
err2:
+ dr_phy_low_power_mode(udc_controller, true);
if (pdata->exit)
pdata->exit(pdata->pdev);
err2a:
@@ -3269,6 +3266,8 @@ static int fsl_udc_remove(struct platform_device *pdev)
dr_wake_up_enable(udc_controller, false);
dr_discharge_line(pdata, true);
+
+ dr_clk_gate(false);
/* DR has been stopped in usb_gadget_unregister_driver() */
remove_proc_file();
@@ -3303,9 +3302,9 @@ static int fsl_udc_remove(struct platform_device *pdev)
device_unregister(&udc_controller->gadget.dev);
/* free udc --wait for the release() finished */
wait_for_completion(&done);
+
/*
- * do platform specific un-initialization:
- * release iomux pins, etc.
+ * do platform specific un-initialization
*/
if (pdata->exit)
pdata->exit(pdata->pdev);
@@ -3449,7 +3448,6 @@ static int fsl_udc_resume(struct platform_device *pdev)
u32 temp;
if (udc_controller->stopped)
dr_clk_gate(true);
- usb_debounce_id_vbus();
if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) {
temp = fsl_readl(&dr_regs->otgsc);
/* if b_session_irq_en is cleared by otg */
@@ -3496,7 +3494,6 @@ static int fsl_udc_resume(struct platform_device *pdev)
dr_clk_gate(true);
dr_wake_up_enable(udc_controller, false);
dr_phy_low_power_mode(udc_controller, false);
- usb_debounce_id_vbus();
/* if in host mode, we need to do nothing */
if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) {
dr_phy_low_power_mode(udc_controller, true);
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c
index e2000bd2e635..dde47dd76e5f 100755
--- a/drivers/usb/host/ehci-arc.c
+++ b/drivers/usb/host/ehci-arc.c
@@ -246,10 +246,10 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
* do platform specific init: check the clock, grab/config pins, etc.
*/
if (pdata->init && pdata->init(pdev)) {
- pdata->lowpower = false;
retval = -ENODEV;
goto err4;
}
+ pdata->lowpower = false;
spin_lock_init(&pdata->lock);
@@ -315,6 +315,9 @@ err2:
usb_put_hcd(hcd);
err1:
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
+ fsl_usb_lowpower_mode(pdata, true);
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(false);
if (pdata->exit && pdata->pdev)
pdata->exit(pdata->pdev);
return retval;
@@ -333,7 +336,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;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
/* Need open clock for register access */
@@ -343,40 +345,44 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
/*disable the wakeup to avoid an abnormal wakeup interrupt*/
usb_host_set_wakeup(hcd->self.controller, false);
- tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
- if (tmp & PORT_PTS_PHCD) {
- tmp &= ~PORT_PTS_PHCD;
- ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
- msleep(100);
- }
+ /* Put the PHY out of low power mode */
+ fsl_usb_lowpower_mode(pdata, false);
}
+ /* disable the host wakeup */
+ usb_host_set_wakeup(hcd->self.controller, false);
+ /*free the ehci_fsl_pre_irq */
+ free_irq(hcd->irq, (void *)pdev);
+
+ usb_remove_hcd(hcd);
+
+ ehci_port_power(ehci, 0);
+
+ iounmap(hcd->regs);
+
if (ehci->transceiver) {
(void)otg_set_host(ehci->transceiver, 0);
otg_put_transceiver(ehci->transceiver);
} else {
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
}
- /*disable the host wakeup and put phy to low power mode */
- usb_host_set_wakeup(hcd->self.controller, false);
- /*free the ehci_fsl_pre_irq */
- free_irq(hcd->irq, (void *)pdev);
- usb_remove_hcd(hcd);
+
usb_put_hcd(hcd);
fsl_usb_lowpower_mode(pdata, true);
- /* DDD shouldn't we turn off the power here? */
- fsl_platform_set_vbus_power(pdata, 0);
+ /* Close the VBUS */
+ if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power)
+ pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, 0);
+
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(false);
/*
- * do platform specific un-initialization:
- * release iomux pins clocks, etc.
+ * do platform specific un-initialization
*/
if (pdata->exit && pdata->pdev)
pdata->exit(pdata->pdev);
-
- iounmap(hcd->regs);
}
static void fsl_setup_phy(struct ehci_hcd *ehci,
@@ -676,17 +682,32 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
/* Only handles OTG mode switch event, system suspend event will be done in bus suspend */
if (pdata->pmflags == 0) {
printk(KERN_DEBUG "%s, pm event \n", __func__);
+ disable_irq(hcd->irq);
if (!host_can_wakeup_system(pdev)) {
/* Need open clock for register access */
fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ /*
+ * Disable wakeup interrupt, since there is wakeup
+ * when phcd from 1->0 if wakeup interrupt is enabled
+ */
+ usb_host_set_wakeup(hcd->self.controller, false);
+
+ /*
+ * Open PHY's clock, then the wakeup settings
+ * can be wroten correctly
+ */
+ fsl_usb_lowpower_mode(pdata, false);
usb_host_set_wakeup(hcd->self.controller, false);
+ fsl_usb_lowpower_mode(pdata, true);
+
fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
} else {
if (pdata->platform_phy_power_on)
pdata->platform_phy_power_on();
}
+ enable_irq(hcd->irq);
printk(KERN_DEBUG "host suspend ends\n");
return 0;
@@ -758,13 +779,18 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
return 0;
}
+#define OTGSC_OFFSET 0x64
+#define OTGSC_ID_VALUE (1 << 8)
+#define OTGSC_ID_INT_STS (1 << 16)
static int ehci_fsl_drv_resume(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 tmp;
+ u32 tmp, otgsc;
+ bool id_changed;
+ int id_value;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
struct fsl_usb2_wakeup_platform_data *wake_up_pdata = pdata->wakeup_pdata;
/* Only handles OTG mode switch event */
@@ -772,29 +798,36 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
if (pdata->pmflags == 0) {
printk(KERN_DEBUG "%s,pm event, wait for wakeup irq if needed\n", __func__);
wait_event_interruptible(wake_up_pdata->wq, !wake_up_pdata->usb_wakeup_is_pending);
+ disable_irq(hcd->irq);
if (!host_can_wakeup_system(pdev)) {
/* Need open clock for register access */
fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ fsl_usb_lowpower_mode(pdata, false);
- usb_host_set_wakeup(hcd->self.controller, true);
-
-#ifndef NO_FIX_DISCONNECT_ISSUE
- /*Unplug&plug device during suspend without remote wakeup enabled
- For Low and full speed device, we should power on and power off
- the USB port to make sure USB internal state machine work well.
- */
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
- if ((tmp & PORT_CONNECT) && !(tmp & PORT_SUSPEND) &&
- ((tmp & (0x3<<26)) != (0x2<<26))) {
- printk(KERN_DEBUG "%s will do power off and power on port.\n", pdata->name);
- ehci_writel(ehci, tmp & ~(PORT_RWC_BITS | PORT_POWER),
- &ehci->regs->port_status[0]);
- ehci_writel(ehci, tmp | PORT_POWER,
- &ehci->regs->port_status[0]);
+ if (pdata->operating_mode == FSL_USB2_DR_OTG) {
+ otgsc = ehci_readl(ehci, (u32 __iomem *)ehci->regs + OTGSC_OFFSET / 4);
+ id_changed = !!(otgsc & OTGSC_ID_INT_STS);
+ id_value = !!(otgsc & OTGSC_ID_VALUE);
+ if (((tmp & PORT_CONNECT) && !id_value) || id_changed) {
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ } else if (!(tmp & PORT_CONNECT)) {
+ usb_host_set_wakeup(hcd->self.controller, true);
+ fsl_usb_lowpower_mode(pdata, true);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ }
+ } else {
+ if (tmp & PORT_CONNECT) {
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ } else {
+ usb_host_set_wakeup(hcd->self.controller, true);
+ fsl_usb_lowpower_mode(pdata, true);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ }
+
}
-#endif
- fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
}
+ enable_irq(hcd->irq);
return 0;
}
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index 9fd3c87babfb..00bd2e609525 100755
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -690,9 +690,16 @@ static int fsl_otg_set_peripheral(struct otg_transceiver *otg_p,
return -ENODEV;
if (!gadget) {
- if (!otg_dev->otg.default_a)
+ /*
+ * At i.mx platform, we still not implement fully
+ * OTG.
+ */
+ /*
+ if (!otg_dev->otg.default_a) {
otg_p->gadget->ops->vbus_draw(otg_p->gadget, 0);
- usb_gadget_vbus_disconnect(otg_dev->otg.gadget);
+ usb_gadget_vbus_disconnect(otg_dev->otg.gadget);
+ }
+ */
otg_dev->otg.gadget = 0;
otg_dev->fsm.b_bus_req = 0;
pdata->port_enables = 0;
diff --git a/drivers/video/mxc/mxc_edid.c b/drivers/video/mxc/mxc_edid.c
index a3e374bc5158..721ff88660df 100644
--- a/drivers/video/mxc/mxc_edid.c
+++ b/drivers/video/mxc/mxc_edid.c
@@ -207,7 +207,9 @@ int mxc_edid_fb_mode_is_equal(bool use_aspect,
mode1->upper_margin == mode2->upper_margin &&
mode1->lower_margin == mode2->lower_margin &&
mode1->sync == mode2->sync &&
- mode1->refresh == mode2->refresh &&
+ /* refresh check, 59.94Hz and 60Hz have the same parameter
+ * in struct of mxc_cea_mode */
+ abs(mode1->refresh - mode2->refresh) <= 1 &&
(mode1->vmode & mask) == (mode2->vmode & mask));
}
diff --git a/drivers/video/mxc/mxc_elcdif_fb.c b/drivers/video/mxc/mxc_elcdif_fb.c
index 0fd076537fb8..ebec7bcfcfa6 100644
--- a/drivers/video/mxc/mxc_elcdif_fb.c
+++ b/drivers/video/mxc/mxc_elcdif_fb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
*/
/*
@@ -940,14 +940,14 @@ static int mxc_elcdif_fb_set_par(struct fb_info *fbi)
setup_dotclk_panel((PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
fbi->var.vsync_len,
- fbi->var.upper_margin +
- fbi->var.yres + fbi->var.lower_margin,
- fbi->var.upper_margin,
+ fbi->var.upper_margin + fbi->var.yres +
+ fbi->var.lower_margin + fbi->var.vsync_len,
+ fbi->var.upper_margin + fbi->var.vsync_len,
fbi->var.yres,
fbi->var.hsync_len,
- fbi->var.left_margin +
- fbi->var.xres + fbi->var.right_margin,
- fbi->var.left_margin,
+ fbi->var.left_margin + fbi->var.xres +
+ fbi->var.right_margin + fbi->var.hsync_len,
+ fbi->var.left_margin + fbi->var.hsync_len,
fbi->var.xres,
bpp_to_pixfmt(fbi),
data->output_pix_fmt,
diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c
index 1122e219642b..4103498dc1b0 100644
--- a/drivers/video/mxc/mxc_epdc_fb.c
+++ b/drivers/video/mxc/mxc_epdc_fb.c
@@ -2253,7 +2253,7 @@ static int epdc_submit_merge(struct update_desc_list *upd_desc_list,
/* Merged update should take on the earliest order */
upd_desc_list->update_order =
(upd_desc_list->update_order > update_to_merge->update_order) ?
- update_to_merge->update_order : upd_desc_list->update_order;
+ upd_desc_list->update_order : update_to_merge->update_order;
return MERGE_OK;
}
diff --git a/drivers/video/mxc/mxcfb_sii902x_elcdif.c b/drivers/video/mxc/mxcfb_sii902x_elcdif.c
index ceab3e66e91c..ecba5b8b380d 100644
--- a/drivers/video/mxc/mxcfb_sii902x_elcdif.c
+++ b/drivers/video/mxc/mxcfb_sii902x_elcdif.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -238,11 +238,6 @@ static void det_worker(struct work_struct *work)
dev_dbg(&sii902x.pdev->dev, "EVENT=plugin\n");
sprintf(event_string, "EVENT=plugin");
- /* make sure fb is powerdown */
- console_lock();
- fb_blank(sii902x.fbi, FB_BLANK_POWERDOWN);
- console_unlock();
-
if (sii902x_read_edid(sii902x.fbi) < 0)
dev_err(&sii902x.client->dev,
"Sii902x: read edid fail\n");
@@ -286,18 +281,15 @@ static void det_worker(struct work_struct *work)
sii902x.fbi->flags &= ~FBINFO_MISC_USEREVENT;
console_unlock();
}
-
- console_lock();
- fb_blank(sii902x.fbi, FB_BLANK_UNBLANK);
- console_unlock();
+ /* Power on sii902x */
+ sii902x_poweron();
}
} else {
sii902x.cable_plugin = 0;
dev_dbg(&sii902x.pdev->dev, "EVENT=plugout\n");
sprintf(event_string, "EVENT=plugout");
- console_lock();
- fb_blank(sii902x.fbi, FB_BLANK_POWERDOWN);
- console_unlock();
+ /* Power off sii902x */
+ sii902x_poweroff();
}
kobject_uevent_env(&sii902x.pdev->dev.kobj, KOBJ_CHANGE, envp);
}
@@ -461,18 +453,6 @@ static int __devexit sii902x_remove(struct i2c_client *client)
return 0;
}
-static int sii902x_suspend(struct i2c_client *client, pm_message_t message)
-{
- /*TODO*/
- return 0;
-}
-
-static int sii902x_resume(struct i2c_client *client)
-{
- /*TODO*/
- return 0;
-}
-
static void sii902x_poweron(void)
{
struct fsl_mxc_lcd_platform_data *plat = sii902x.client->dev.platform_data;
@@ -522,8 +502,6 @@ static struct i2c_driver sii902x_i2c_driver = {
},
.probe = sii902x_probe,
.remove = sii902x_remove,
- .suspend = sii902x_suspend,
- .resume = sii902x_resume,
.id_table = sii902x_id,
};
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c
index 9c9620c67f1d..8902fb2b0b5e 100644
--- a/drivers/video/mxc_hdmi.c
+++ b/drivers/video/mxc_hdmi.c
@@ -54,6 +54,7 @@
#include <linux/types.h>
#include <linux/switch.h>
+#include "edid.h"
#include <mach/mxc_edid.h>
#include "mxc/mxc_dispdrv.h"
@@ -167,6 +168,7 @@ struct mxc_hdmi {
struct clk *hdmi_isfr_clk;
struct clk *hdmi_iahb_clk;
struct delayed_work hotplug_work;
+ struct delayed_work hdcp_hdp_work;
struct notifier_block nb;
struct hdmi_data_info hdmi_data;
@@ -192,7 +194,10 @@ struct mxc_hdmi {
struct switch_dev sdev_display;
};
+static int hdmi_major;
+static struct class *hdmi_class;
struct i2c_client *hdmi_i2c;
+struct mxc_hdmi *g_hdmi;
static bool hdmi_inited;
@@ -200,6 +205,8 @@ extern const struct fb_videomode mxc_cea_mode[64];
extern void mxc_hdmi_cec_handle(u16 cec_stat);
static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event);
+static void mxc_hdmi_enable_pins(struct mxc_hdmi *hdmi);
+static void mxc_hdmi_disable_pins(struct mxc_hdmi *hdmi);
#ifdef DEBUG
static void dump_fb_videomode(struct fb_videomode *m)
@@ -296,6 +303,51 @@ static DEVICE_ATTR(rgb_out_enable, S_IRUGO | S_IWUSR,
mxc_hdmi_show_rgb_out_enable,
mxc_hdmi_store_rgb_out_enable);
+static ssize_t mxc_hdmi_show_hdcp_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+
+ if (hdmi->hdmi_data.hdcp_enable == false)
+ strcpy(buf, "hdcp disable\n");
+ else
+ strcpy(buf, "hdcp enable\n");
+
+ return strlen(buf);
+}
+
+static ssize_t mxc_hdmi_store_hdcp_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+ unsigned long value;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ hdmi->hdmi_data.hdcp_enable = value;
+
+ /* Reconfig HDMI for HDCP */
+ mxc_hdmi_setup(hdmi, 0);
+
+ if (hdmi->hdmi_data.hdcp_enable == false) {
+ sprintf(event_string, "EVENT=hdcpdisable");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+ } else {
+ sprintf(event_string, "EVENT=hdcpenable");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+ }
+
+ return count;
+
+}
+
+static DEVICE_ATTR(hdcp_enable, S_IRUGO | S_IWUSR,
+ mxc_hdmi_show_hdcp_enable, mxc_hdmi_store_hdcp_enable);
/*!
* this submodule is responsible for the video data synchronization.
@@ -830,6 +882,45 @@ static int hdmi_phy_i2c_write_verify(struct mxc_hdmi *hdmi, unsigned short data,
}
#endif
+static bool hdmi_edid_wait_i2c_done(struct mxc_hdmi *hdmi, int msec)
+{
+ unsigned char val = 0;
+ val = hdmi_readb(HDMI_IH_I2CM_STAT0) & 0x2;
+ while (val == 0) {
+ udelay(1000);
+ if (msec-- == 0) {
+ dev_dbg(&hdmi->pdev->dev,
+ "HDMI EDID i2c operation time out!!\n");
+ return false;
+ }
+ val = hdmi_readb(HDMI_IH_I2CM_STAT0) & 0x2;
+ }
+ return true;
+}
+
+static u8 hdmi_edid_i2c_read(struct mxc_hdmi *hdmi,
+ u8 addr, u8 blockno)
+{
+ u8 spointer = blockno / 2;
+ u8 edidaddress = ((blockno % 2) * 0x80) + addr;
+ u8 data;
+
+ hdmi_writeb(0xFF, HDMI_IH_I2CM_STAT0);
+ hdmi_writeb(edidaddress, HDMI_I2CM_ADDRESS);
+ hdmi_writeb(spointer, HDMI_I2CM_SEGADDR);
+ if (spointer == 0)
+ hdmi_writeb(HDMI_I2CM_OPERATION_READ,
+ HDMI_I2CM_OPERATION);
+ else
+ hdmi_writeb(HDMI_I2CM_OPERATION_READ_EXT,
+ HDMI_I2CM_OPERATION);
+
+ hdmi_edid_wait_i2c_done(hdmi, 1000);
+ data = hdmi_readb(HDMI_I2CM_DATAI);
+ hdmi_writeb(0xFF, HDMI_IH_I2CM_STAT0);
+ return data;
+}
+
/* "Power-down enable (active low)"
* That mean that power up == 1! */
static void mxc_hdmi_phy_enable_power(u8 enable)
@@ -1174,28 +1265,13 @@ static void mxc_hdmi_phy_init(struct mxc_hdmi *hdmi)
static void hdmi_tx_hdcp_config(struct mxc_hdmi *hdmi)
{
- u8 de, val;
-
- if (hdmi->hdmi_data.video_mode.mDataEnablePolarity)
- de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
- else
- de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
-
- /* disable rx detect */
- val = hdmi_readb(HDMI_A_HDCPCFG0);
- val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
- val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
- hdmi_writeb(val, HDMI_A_HDCPCFG0);
-
- val = hdmi_readb(HDMI_A_VIDPOLCFG);
- val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
- val |= de;
- hdmi_writeb(val, HDMI_A_VIDPOLCFG);
-
- val = hdmi_readb(HDMI_A_HDCPCFG1);
- val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
- val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
- hdmi_writeb(val, HDMI_A_HDCPCFG1);
+ if (hdmi->hdmi_data.hdcp_enable) {
+ /* Enable HDMI DDC pin */
+ mxc_hdmi_enable_pins(hdmi);
+ } else {
+ /* Disable HDMI DDC pin */
+ mxc_hdmi_disable_pins(hdmi);
+ }
}
static void hdmi_config_AVI(struct mxc_hdmi *hdmi)
@@ -1422,19 +1498,131 @@ static void hdmi_av_composer(struct mxc_hdmi *hdmi)
dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
}
+static int mxc_edid_read_internal(struct mxc_hdmi *hdmi, unsigned char *edid,
+ struct mxc_edid_cfg *cfg, struct fb_info *fbi)
+{
+ int extblknum;
+ int i, j, ret;
+ unsigned char *ediddata = edid;
+ unsigned char tmpedid[EDID_LENGTH];
+
+ dev_info(&hdmi->pdev->dev, "%s\n", __func__);
+
+ if (!edid || !cfg || !fbi)
+ return -EINVAL;
+
+ /* init HDMI I2CM for read edid*/
+ hdmi_writeb(0x0, HDMI_I2CM_DIV);
+ hdmi_writeb(0x00, HDMI_I2CM_SS_SCL_HCNT_1_ADDR);
+ hdmi_writeb(0x79, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
+ hdmi_writeb(0x00, HDMI_I2CM_SS_SCL_LCNT_1_ADDR);
+ hdmi_writeb(0x91, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
+
+ hdmi_writeb(0x00, HDMI_I2CM_FS_SCL_HCNT_1_ADDR);
+ hdmi_writeb(0x0F, HDMI_I2CM_FS_SCL_HCNT_0_ADDR);
+ hdmi_writeb(0x00, HDMI_I2CM_FS_SCL_LCNT_1_ADDR);
+ hdmi_writeb(0x21, HDMI_I2CM_FS_SCL_LCNT_0_ADDR);
+
+ hdmi_writeb(0x50, HDMI_I2CM_SLAVE);
+ hdmi_writeb(0x30, HDMI_I2CM_SEGADDR);
+
+ /* Umask edid interrupt */
+ hdmi_writeb(HDMI_I2CM_INT_DONE_POL,
+ HDMI_I2CM_INT);
+
+ hdmi_writeb(HDMI_I2CM_CTLINT_NAC_POL |
+ HDMI_I2CM_CTLINT_ARBITRATION_POL,
+ HDMI_I2CM_CTLINT);
+
+ /* reset edid data zero */
+ memset(edid, 0, EDID_LENGTH*4);
+ memset(cfg, 0, sizeof(struct mxc_edid_cfg));
+
+ /* Check first three byte of EDID head */
+ if (!(hdmi_edid_i2c_read(hdmi, 0, 0) == 0x00) ||
+ !(hdmi_edid_i2c_read(hdmi, 1, 0) == 0xFF) ||
+ !(hdmi_edid_i2c_read(hdmi, 2, 0) == 0xFF)) {
+ dev_info(&hdmi->pdev->dev, "EDID head check failed!");
+ return -ENOENT;
+ }
+
+ for (i = 0; i < 128; i++) {
+ *ediddata = hdmi_edid_i2c_read(hdmi, i, 0);
+ ediddata++;
+ }
+
+ extblknum = edid[0x7E];
+ if (extblknum < 0)
+ return extblknum;
+
+ if (extblknum) {
+ ediddata = edid + EDID_LENGTH;
+ for (i = 0; i < 128; i++) {
+ *ediddata = hdmi_edid_i2c_read(hdmi, i, 1);
+ ediddata++;
+ }
+ }
+
+ /* edid first block parsing */
+ memset(&fbi->monspecs, 0, sizeof(fbi->monspecs));
+ fb_edid_to_monspecs(edid, &fbi->monspecs);
+
+ ret = mxc_edid_parse_ext_blk(edid + EDID_LENGTH,
+ cfg, &fbi->monspecs);
+ if (ret < 0)
+ return -ENOENT;
+
+ /* need read segment block? */
+ if (extblknum > 1) {
+ for (j = 1; j <= extblknum; j++) {
+ for (i = 0; i < 128; i++)
+ *(tmpedid + 1) = hdmi_edid_i2c_read(hdmi, i, j);
+
+ /* edid ext block parsing */
+ ret = mxc_edid_parse_ext_blk(tmpedid + EDID_LENGTH,
+ cfg, &fbi->monspecs);
+ if (ret < 0)
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
static int mxc_hdmi_read_edid(struct mxc_hdmi *hdmi)
{
int ret;
u8 edid_old[HDMI_EDID_LEN];
+ u8 clkdis;
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
/* save old edid */
memcpy(edid_old, hdmi->edid, HDMI_EDID_LEN);
- ret = mxc_edid_read(hdmi_i2c->adapter, hdmi_i2c->addr, hdmi->edid,
+ if (!hdmi->hdmi_data.hdcp_enable)
+ ret = mxc_edid_read(hdmi_i2c->adapter, hdmi_i2c->addr,
+ hdmi->edid, &hdmi->edid_cfg, hdmi->fbi);
+ else {
+
+ /* Disable HDCP clk */
+ if (hdmi->hdmi_data.hdcp_enable) {
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+ }
+
+ ret = mxc_edid_read_internal(hdmi, hdmi->edid,
&hdmi->edid_cfg, hdmi->fbi);
+ /* Enable HDCP clk */
+ if (hdmi->hdmi_data.hdcp_enable) {
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis &= ~HDMI_MC_CLKDIS_HDCPCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+ }
+
+ }
if (ret < 0)
return HDMI_EDID_FAIL;
@@ -1454,6 +1642,28 @@ static int mxc_hdmi_read_edid(struct mxc_hdmi *hdmi)
return HDMI_EDID_SUCCESS;
}
+static void mxc_hdmi_enable_pins(struct mxc_hdmi *hdmi)
+{
+ struct fsl_mxc_hdmi_platform_data *plat = hdmi->pdev->dev.platform_data;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* Enable pins to HDMI */
+ if (plat->enable_pins)
+ plat->enable_pins();
+}
+
+static void mxc_hdmi_disable_pins(struct mxc_hdmi *hdmi)
+{
+ struct fsl_mxc_hdmi_platform_data *plat = hdmi->pdev->dev.platform_data;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* Disable pins to HDMI */
+ if (plat->disable_pins)
+ plat->disable_pins();
+}
+
static void mxc_hdmi_phy_disable(struct mxc_hdmi *hdmi)
{
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
@@ -1696,7 +1906,7 @@ static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi)
return;
}
- /* If video mode same as previous, init HDMI PHY and return */
+ /* If video mode same as previous, init HDMI again */
if (fb_mode_is_equal(&hdmi->previous_non_vga_mode, mode)) {
dev_dbg(&hdmi->pdev->dev,
"%s: Video mode same as previous\n", __func__);
@@ -1707,7 +1917,6 @@ static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi)
} else {
dev_dbg(&hdmi->pdev->dev, "%s: New video mode\n", __func__);
mxc_hdmi_set_mode_to_vga_dvi(hdmi);
-
fb_videomode_to_var(&hdmi->fbi->var, mode);
dump_fb_videomode((struct fb_videomode *)mode);
mxc_hdmi_notify_fb(hdmi);
@@ -1779,10 +1988,13 @@ static void mxc_hdmi_cable_disconnected(struct mxc_hdmi *hdmi)
{
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
- hdmi_disable_overflow_interrupts();
+ /* Disable All HDMI clock */
+ hdmi_writeb(0xff, HDMI_MC_CLKDIS);
mxc_hdmi_phy_disable(hdmi);
+ hdmi_disable_overflow_interrupts();
+
hdmi->cable_plugin = false;
}
@@ -1794,7 +2006,7 @@ static void hotplug_worker(struct work_struct *work)
u32 phy_int_stat, phy_int_pol, phy_int_mask;
u8 val;
unsigned long flags;
- char event_string[16];
+ char event_string[32];
char *envp[] = { event_string, NULL };
phy_int_stat = hdmi->latest_intr_stat;
@@ -1869,6 +2081,21 @@ static void hotplug_worker(struct work_struct *work)
spin_unlock_irqrestore(&hdmi->irq_lock, flags);
}
+static void hdcp_hdp_worker(struct work_struct *work)
+{
+ struct delayed_work *delay_work = to_delayed_work(work);
+ struct mxc_hdmi *hdmi =
+ container_of(delay_work, struct mxc_hdmi, hdcp_hdp_work);
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+
+ /* HDCP interrupt */
+ sprintf(event_string, "EVENT=hdcpint");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+
+ /* Unmute interrupts in HDCP application*/
+}
+
static irqreturn_t mxc_hdmi_hotplug(int irq, void *data)
{
struct mxc_hdmi *hdmi = data;
@@ -1917,6 +2144,17 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data)
schedule_delayed_work(&(hdmi->hotplug_work), msecs_to_jiffies(20));
}
+ /* Check HDCP interrupt state */
+ if (hdmi->hdmi_data.hdcp_enable) {
+ val = hdmi_readb(HDMI_A_APIINTSTAT);
+ if (val != 0) {
+ /* Mute interrupts until interrupt handled */
+ val = 0xFF;
+ hdmi_writeb(val, HDMI_A_APIINTMSK);
+ schedule_delayed_work(&(hdmi->hdcp_hdp_work), msecs_to_jiffies(50));
+ }
+ }
+
spin_unlock_irqrestore(&hdmi->irq_lock, flags);
return IRQ_HANDLED;
}
@@ -1931,15 +2169,6 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event)
fb_var_to_videomode(&m, &hdmi->fbi->var);
dump_fb_videomode(&m);
- /* Exit the setup if we get mode change and are already set to
- * this video mode */
- if ((event == FB_EVENT_MODE_CHANGE) &&
- fb_mode_is_equal(&hdmi->previous_mode, &m)) {
- dev_dbg(&hdmi->pdev->dev,
- "%s video mode did not change.\n", __func__);
- mxc_hdmi_phy_init(hdmi);
- return;
- }
dev_dbg(&hdmi->pdev->dev, "%s - video mode changed\n", __func__);
/* Save mode as 'previous_mode' so that we can know if mode changed. */
@@ -1961,17 +2190,12 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event)
hdmi_disable_overflow_interrupts();
- if (hdmi->vic == 0) {
- dev_dbg(&hdmi->pdev->dev, "Non-CEA mode used in HDMI\n");
+ dev_dbg(&hdmi->pdev->dev, "CEA mode used vic=%d\n", hdmi->vic);
+ if (hdmi->edid_cfg.hdmi_cap)
+ hdmi->hdmi_data.video_mode.mDVI = false;
+ else {
+ dev_dbg(&hdmi->pdev->dev, "CEA mode vic=%d work in DVI\n", hdmi->vic);
hdmi->hdmi_data.video_mode.mDVI = true;
- } else {
- dev_dbg(&hdmi->pdev->dev, "CEA mode used vic=%d\n", hdmi->vic);
- if (hdmi->edid_cfg.hdmi_cap)
- hdmi->hdmi_data.video_mode.mDVI = false;
- else {
- dev_dbg(&hdmi->pdev->dev, "CEA mode vic=%d work in DVI\n", hdmi->vic);
- hdmi->hdmi_data.video_mode.mDVI = true;
- }
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
@@ -2013,7 +2237,6 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event)
/* IPU not support depth color output */
hdmi->hdmi_data.enc_color_depth = 8;
hdmi->hdmi_data.pix_repet_factor = 0;
- hdmi->hdmi_data.hdcp_enable = 0;
hdmi->hdmi_data.video_mode.mDataEnablePolarity = true;
/* HDMI Initialization Step B.1 */
@@ -2308,6 +2531,7 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp,
hdmi->edid_cfg.hdmi_cap = true;
INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_worker);
+ INIT_DELAYED_WORK(&hdmi->hdcp_hdp_work, hdcp_hdp_worker);
/* Configure registers related to HDMI interrupt
* generation before registering IRQ. */
@@ -2346,11 +2570,17 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp,
if (ret < 0)
dev_warn(&hdmi->pdev->dev,
"cound not create sys node for edid\n");
+
ret = device_create_file(&hdmi->pdev->dev, &dev_attr_rgb_out_enable);
if (ret < 0)
dev_warn(&hdmi->pdev->dev,
"cound not create sys node for rgb out enable\n");
+ ret = device_create_file(&hdmi->pdev->dev, &dev_attr_hdcp_enable);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev,
+ "cound not create sys node for hdcp enable\n");
+
dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
hdmi_inited = true;
@@ -2408,9 +2638,50 @@ static struct mxc_dispdrv_driver mxc_hdmi_drv = {
.disable = mxc_hdmi_power_off,
};
+
+static int mxc_hdmi_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static long mxc_hdmi_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int __user *argp = (void __user *)arg;
+ int ret = 0;
+
+ switch (cmd) {
+ case HDMI_IOC_GET_RESOURCE:
+ ret = copy_to_user(argp, &g_hdmi->hdmi_data,
+ sizeof(g_hdmi->hdmi_data)) ? -EFAULT : 0;
+ break;
+ case HDMI_IOC_GET_CPU_TYPE:
+ *argp = mxc_cpu_type;
+ break;
+ default:
+ pr_debug("Unsupport cmd %d\n", cmd);
+ break;
+ }
+ return ret;
+}
+
+static int mxc_hdmi_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations mxc_hdmi_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_hdmi_open,
+ .release = mxc_hdmi_release,
+ .unlocked_ioctl = mxc_hdmi_ioctl,
+};
+
+
static int __devinit mxc_hdmi_probe(struct platform_device *pdev)
{
struct mxc_hdmi *hdmi;
+ struct device *temp_class;
int ret = 0;
/* Check that I2C driver is loaded and available */
@@ -2423,6 +2694,28 @@ static int __devinit mxc_hdmi_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto ealloc;
}
+ g_hdmi = hdmi;
+
+ hdmi_major = register_chrdev(hdmi_major, "mxc_hdmi", &mxc_hdmi_fops);
+ if (hdmi_major < 0) {
+ printk(KERN_ERR "HDMI: unable to get a major for HDMI\n");
+ ret = -EBUSY;
+ goto ealloc;
+ }
+
+ hdmi_class = class_create(THIS_MODULE, "mxc_hdmi");
+ if (IS_ERR(hdmi_class)) {
+ ret = PTR_ERR(hdmi_class);
+ goto err_out_chrdev;
+ }
+
+ temp_class = device_create(hdmi_class, NULL, MKDEV(hdmi_major, 0),
+ NULL, "mxc_hdmi");
+ if (IS_ERR(temp_class)) {
+ ret = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
hdmi->pdev = pdev;
@@ -2460,6 +2753,11 @@ edispdrv:
platform_device_put(hdmi->core_pdev);
ecore:
kfree(hdmi);
+err_out_class:
+ device_destroy(hdmi_class, MKDEV(hdmi_major, 0));
+ class_destroy(hdmi_class);
+err_out_chrdev:
+ unregister_chrdev(hdmi_major, "mxc_hdmi");
ealloc:
return ret;
}
@@ -2479,6 +2777,7 @@ static int mxc_hdmi_remove(struct platform_device *pdev)
/* No new work will be scheduled, wait for running ISR */
free_irq(irq, hdmi);
kfree(hdmi);
+ g_hdmi = NULL;
return 0;
}
@@ -2500,6 +2799,13 @@ module_init(mxc_hdmi_init);
static void __exit mxc_hdmi_exit(void)
{
+ if (hdmi_major > 0) {
+ device_destroy(hdmi_class, MKDEV(hdmi_major, 0));
+ class_destroy(hdmi_class);
+ unregister_chrdev(hdmi_major, "mxc_hdmi");
+ hdmi_major = 0;
+ }
+
platform_driver_unregister(&mxc_hdmi_driver);
}
module_exit(mxc_hdmi_exit);