/*! * function to update physical buffer address for encorder IDMA channel * * @param eba physical buffer address for encorder IDMA channel * @param buffer_num int buffer 0 or buffer 1 * * @return status */ static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num) { int err = 0; pr_debug("eba %x\n", eba); if (grotation >= IPU_ROTATE_90_RIGHT) { err = ipu_update_channel_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); } else { err = ipu_update_channel_buffer(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); } if (err != 0) { printk(KERN_ERR "err %d buffer_num %d\n", err, *buffer_num); return err; } if (grotation >= IPU_ROTATE_90_RIGHT) { ipu_select_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num); } else { ipu_select_buffer(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num); } *buffer_num = (*buffer_num == 0) ? 1 : 0; return 0; }
/*! * function to update physical buffer address for encorder IDMA channel * * @param eba physical buffer address for encorder IDMA channel * @param buffer_num int buffer 0 or buffer 1 * * @return status */ static int csi_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba, int *buffer_num) { int err = 0; pr_debug("eba %x\n", eba); err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); if (err != 0) { ipu_clear_buffer_ready(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); if (err != 0) { pr_err("ERROR: v4l2 capture: fail to update " "buf%d\n", *buffer_num); return err; } } ipu_select_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); *buffer_num = (*buffer_num == 0) ? 1 : 0; return 0; }
/*! * function to update physical buffer address for encorder IDMA channel * * @param eba physical buffer address for encorder IDMA channel * @param buffer_num int buffer 0 or buffer 1 * * @return status */ static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num) { int err = 0; pr_debug("eba %x\n", eba); if (grotation >= IPU_ROTATE_90_RIGHT) { err = ipu_update_channel_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); } else { err = ipu_update_channel_buffer(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); } if (err != 0) { if (grotation >= IPU_ROTATE_90_RIGHT) { ipu_clear_buffer_ready(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num); err = ipu_update_channel_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); } else { ipu_clear_buffer_ready(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num); err = ipu_update_channel_buffer(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); } if (err != 0) { pr_err("ERROR: v4l2 capture: fail to update " "buf%d\n", *buffer_num); return err; } } if (grotation >= IPU_ROTATE_90_RIGHT) { ipu_select_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num); } else { ipu_select_buffer(CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num); } *buffer_num = (*buffer_num == 0) ? 1 : 0; return 0; }
static void mxc_v4l2out_timer_handler(unsigned long arg) { int index; unsigned long timeout; vout_data *vout = (vout_data *) arg; /* DPRINTK("timer handler:\n"); */ /* If timer occurs before IPU h/w is ready, then set the state to paused and the timer will be set again when next buffer is queued. */ if (vout->ipu_buf[vout->next_rdy_ipu_buf] != -1) { DPRINTK("IPU buffer busy\n"); vout->state = STATE_STREAM_PAUSED; return; } /* Dequeue buffer and pass to IPU */ index = dequeue_buf(&vout->ready_q); if (index == -1) { /* no buffers ready, should never occur */ printk("mxc_v4l2out: timer - no queued buffers ready\n"); return; } g_buf_dq_cnt++; vout->ipu_buf[vout->next_rdy_ipu_buf] = index; if (ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, vout->next_rdy_ipu_buf, vout->queue_buf_paddr[index]) < 0) { DPRINTK("unable to update buffer %d address\n", vout->next_rdy_ipu_buf); return; } if (ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, vout->next_rdy_ipu_buf) < 0) { DPRINTK("unable to set IPU buffer ready\n"); } vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; /* Setup timer for next buffer */ index = peek_next_buf(&vout->ready_q); if (index != -1) { timeout = timeval_to_jiffies(&vout->v4l2_bufs[index].timestamp); if (!timeout) { /* if timestamp is 0, then default to 30fps */ timeout = vout->start_jiffies + msecs_to_jiffies(vout->frame_count * 33); } else { /* Adjust time from time of day to jiffies */ timeout -= vout->start_tod_jiffies; } if (mod_timer(&vout->output_timer, timeout)) DPRINTK("warning: timer was already set\n"); vout->frame_count++; } else { vout->state = STATE_STREAM_PAUSED; } }
/*! * function to update physical buffer address for encorder IDMA channel * * @param eba physical buffer address for encorder IDMA channel * @param buffer_num int buffer 0 or buffer 1 * * @return status */ static int csi_enc_eba_update(dma_addr_t eba, int *buffer_num) { int err = 0; //printf("csi_enc_eba_update, addr: 0x%x, buffer_num: %d\n", eba, *buffer_num); err = ipu_update_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); if (err != 0) { ipu_clear_buffer_ready(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); err = ipu_update_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); if (err != 0) { printf("ERROR: v4l2 capture: fail to update buf %d\n", *buffer_num); return err; } } ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); *buffer_num = (*buffer_num == 0) ? 1 : 0; return 0; }
/*! * function to update physical buffer address for encorder IDMA channel * * @param eba physical buffer address for encorder IDMA channel * @param buffer_num int buffer 0 or buffer 1 * * @return status */ static int csi_enc_eba_update(dma_addr_t eba, int *buffer_num) { int err = 0; pr_debug("eba %x\n", eba); err = ipu_update_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num, eba); if (err != 0) { printk(KERN_ERR "err %d buffer_num %d\n", err, *buffer_num); return err; } ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); *buffer_num = (*buffer_num == 0) ? 1 : 0; return 0; }
static int mxc_ipu_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; switch (cmd) { case IPU_INIT_CHANNEL: { ipu_channel_parm parm; if (copy_from_user (&parm, (ipu_channel_parm *) arg, sizeof(ipu_channel_parm))) { return -EFAULT; } if (!parm.flag) { ret = ipu_init_channel(parm.channel, &parm.params); } else { ret = ipu_init_channel(parm.channel, NULL); } } break; case IPU_UNINIT_CHANNEL: { ipu_channel_t ch; int __user *argp = (void __user *)arg; if (get_user(ch, argp)) return -EFAULT; ipu_uninit_channel(ch); } break; case IPU_INIT_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) { return -EFAULT; } ret = ipu_init_channel_buffer(parm.channel, parm.type, parm.pixel_fmt, parm.width, parm.height, parm.stride, parm.rot_mode, parm.phyaddr_0, parm.phyaddr_1, parm.u_offset, parm.v_offset); } break; case IPU_UPDATE_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) { return -EFAULT; } if ((parm.phyaddr_0 != (dma_addr_t) NULL) && (parm.phyaddr_1 == (dma_addr_t) NULL)) { ret = ipu_update_channel_buffer(parm.channel, parm.type, parm.bufNum, parm.phyaddr_0); } else if ((parm.phyaddr_0 == (dma_addr_t) NULL) && (parm.phyaddr_1 != (dma_addr_t) NULL)) { ret = ipu_update_channel_buffer(parm.channel, parm.type, parm.bufNum, parm.phyaddr_1); } else { ret = -1; } } break; case IPU_SELECT_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) { return -EFAULT; } ret = ipu_select_buffer(parm.channel, parm.type, parm.bufNum); } break; case IPU_LINK_CHANNELS: { ipu_channel_link link; if (copy_from_user (&link, (ipu_channel_link *) arg, sizeof(ipu_channel_link))) { return -EFAULT; } ret = ipu_link_channels(link.src_ch, link.dest_ch); } break; case IPU_UNLINK_CHANNELS: { ipu_channel_link link; if (copy_from_user (&link, (ipu_channel_link *) arg, sizeof(ipu_channel_link))) { return -EFAULT; } ret = ipu_unlink_channels(link.src_ch, link.dest_ch); } break; case IPU_ENABLE_CHANNEL: { ipu_channel_t ch; int __user *argp = (void __user *)arg; if (get_user(ch, argp)) return -EFAULT; ipu_enable_channel(ch); } break; case IPU_DISABLE_CHANNEL: { ipu_channel_info info; if (copy_from_user (&info, (ipu_channel_info *) arg, sizeof(ipu_channel_info))) { return -EFAULT; } ret = ipu_disable_channel(info.channel, info.stop); } break; case IPU_ENABLE_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_enable_irq(irq); } break; case IPU_DISABLE_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_disable_irq(irq); } break; case IPU_CLEAR_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_clear_irq(irq); } break; case IPU_FREE_IRQ: { ipu_irq_info info; if (copy_from_user (&info, (ipu_irq_info *) arg, sizeof(ipu_irq_info))) { return -EFAULT; } ipu_free_irq(info.irq, info.dev_id); } break; case IPU_REQUEST_IRQ_STATUS: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ret = ipu_get_irq_status(irq); } break; case IPU_SDC_INIT_PANEL: { ipu_sdc_panel_info sinfo; if (copy_from_user (&sinfo, (ipu_sdc_panel_info *) arg, sizeof(ipu_sdc_panel_info))) { return -EFAULT; } ret = ipu_sdc_init_panel(sinfo.panel, sinfo.pixel_clk, sinfo.width, sinfo.height, sinfo.pixel_fmt, sinfo.hStartWidth, sinfo.hSyncWidth, sinfo.hEndWidth, sinfo.vStartWidth, sinfo.vSyncWidth, sinfo.vEndWidth, sinfo.signal); } break; case IPU_SDC_SET_WIN_POS: { ipu_sdc_window_pos pos; if (copy_from_user (&pos, (ipu_sdc_window_pos *) arg, sizeof(ipu_sdc_window_pos))) { return -EFAULT; } ret = ipu_sdc_set_window_pos(pos.channel, pos.x_pos, pos.y_pos); } break; case IPU_SDC_SET_GLOBAL_ALPHA: { ipu_sdc_global_alpha g; if (copy_from_user (&g, (ipu_sdc_global_alpha *) arg, sizeof(ipu_sdc_global_alpha))) { return -EFAULT; } ret = ipu_sdc_set_global_alpha(g.enable, g.alpha); } break; case IPU_SDC_SET_COLOR_KEY: { ipu_sdc_color_key c; if (copy_from_user (&c, (ipu_sdc_color_key *) arg, sizeof(ipu_sdc_color_key))) { return -EFAULT; } ret = ipu_sdc_set_color_key(c.channel, c.enable, c.colorKey); } break; case IPU_SDC_SET_BRIGHTNESS: { uint8_t b; int __user *argp = (void __user *)arg; if (get_user(b, argp)) return -EFAULT; ret = ipu_sdc_set_brightness(b); } break; case IPU_REGISTER_GENERIC_ISR: { ipu_event_info info; if (copy_from_user (&info, (ipu_event_info *) arg, sizeof(ipu_event_info))) { return -EFAULT; } ret = ipu_request_irq(info.irq, mxc_ipu_generic_handler, 0, "video_sink", info.dev); } break; case IPU_GET_EVENT: /* User will have to allocate event_type structure and pass the pointer in arg */ { event_type ev; int r = -1; r = get_events(&ev); if (r == -1) { wait_event_interruptible(waitq, (pending_events != 0)); r = get_events(&ev); } ret = -1; if (r == 0) { if (!copy_to_user((event_type *) arg, &ev, sizeof(event_type))) { ret = 0; } } } break; case IPU_ADC_WRITE_TEMPLATE: { ipu_adc_template temp; if (copy_from_user (&temp, (ipu_adc_template *) arg, sizeof(temp))) { return -EFAULT; } ret = ipu_adc_write_template(temp.disp, temp.pCmd, temp.write); } break; case IPU_ADC_UPDATE: { ipu_adc_update update; if (copy_from_user (&update, (ipu_adc_update *) arg, sizeof(update))) { return -EFAULT; } ret = ipu_adc_set_update_mode(update.channel, update.mode, update.refresh_rate, update.addr, update.size); } break; case IPU_ADC_SNOOP: { ipu_adc_snoop snoop; if (copy_from_user (&snoop, (ipu_adc_snoop *) arg, sizeof(snoop))) { return -EFAULT; } ret = ipu_adc_get_snooping_status(snoop.statl, snoop.stath); } break; case IPU_ADC_CMD: { ipu_adc_cmd cmd; if (copy_from_user (&cmd, (ipu_adc_cmd *) arg, sizeof(cmd))) { return -EFAULT; } ret = ipu_adc_write_cmd(cmd.disp, cmd.type, cmd.cmd, cmd.params, cmd.numParams); } break; case IPU_ADC_INIT_PANEL: { ipu_adc_panel panel; if (copy_from_user (&panel, (ipu_adc_panel *) arg, sizeof(panel))) { return -EFAULT; } ret = ipu_adc_init_panel(panel.disp, panel.width, panel.height, panel.pixel_fmt, panel.stride, panel.signal, panel.addr, panel.vsync_width, panel.mode); } break; case IPU_ADC_IFC_TIMING: { ipu_adc_ifc_timing t; if (copy_from_user (&t, (ipu_adc_ifc_timing *) arg, sizeof(t))) { return -EFAULT; } ret = ipu_adc_init_ifc_timing(t.disp, t.read, t.cycle_time, t.up_time, t.down_time, t.read_latch_time, t.pixel_clk); } break; case IPU_CSI_INIT_INTERFACE: { ipu_csi_interface c; if (copy_from_user (&c, (ipu_csi_interface *) arg, sizeof(c))) return -EFAULT; ret = ipu_csi_init_interface(c.width, c.height, c.pixel_fmt, c.signal); } break; case IPU_CSI_ENABLE_MCLK: { ipu_csi_mclk m; if (copy_from_user(&m, (ipu_csi_mclk *) arg, sizeof(m))) return -EFAULT; ret = ipu_csi_enable_mclk(m.src, m.flag, m.wait); } break; case IPU_CSI_READ_MCLK_FLAG: { ret = ipu_csi_read_mclk_flag(); } break; case IPU_CSI_FLASH_STROBE: { bool strobe; int __user *argp = (void __user *)arg; if (get_user(strobe, argp)) return -EFAULT; ipu_csi_flash_strobe(strobe); } break; case IPU_CSI_GET_WIN_SIZE: { ipu_csi_window_size w; ipu_csi_get_window_size(&w.width, &w.height); if (copy_to_user ((ipu_csi_window_size *) arg, &w, sizeof(w))) return -EFAULT; } break; case IPU_CSI_SET_WIN_SIZE: { ipu_csi_window_size w; if (copy_from_user (&w, (ipu_csi_window_size *) arg, sizeof(w))) return -EFAULT; ipu_csi_set_window_size(w.width, w.height); } break; case IPU_CSI_SET_WINDOW: { ipu_csi_window p; if (copy_from_user (&p, (ipu_csi_window *) arg, sizeof(p))) return -EFAULT; ipu_csi_set_window_pos(p.left, p.top); } break; case IPU_PF_SET_PAUSE_ROW: { uint32_t p; int __user *argp = (void __user *)arg; if (get_user(p, argp)) return -EFAULT; ret = ipu_pf_set_pause_row(p); } break; default: break; } return ret; }
static long mxc_ipu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; switch (cmd) { case IPU_INIT_CHANNEL: { ipu_channel_parm parm; if (copy_from_user (&parm, (ipu_channel_parm *) arg, sizeof(ipu_channel_parm))) return -EFAULT; if (!parm.flag) { ret = ipu_init_channel(parm.channel, &parm.params); } else { ret = ipu_init_channel(parm.channel, NULL); } } break; case IPU_UNINIT_CHANNEL: { ipu_channel_t ch; int __user *argp = (void __user *)arg; if (get_user(ch, argp)) return -EFAULT; ipu_uninit_channel(ch); } break; case IPU_INIT_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; ret = ipu_init_channel_buffer( parm.channel, parm.type, parm.pixel_fmt, parm.width, parm.height, parm.stride, parm.rot_mode, parm.phyaddr_0, parm.phyaddr_1, parm.u_offset, parm.v_offset); } break; case IPU_UPDATE_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; if ((parm.phyaddr_0 != (dma_addr_t) NULL) && (parm.phyaddr_1 == (dma_addr_t) NULL)) { ret = ipu_update_channel_buffer( parm.channel, parm.type, parm.bufNum, parm.phyaddr_0); } else if ((parm.phyaddr_0 == (dma_addr_t) NULL) && (parm.phyaddr_1 != (dma_addr_t) NULL)) { ret = ipu_update_channel_buffer( parm.channel, parm.type, parm.bufNum, parm.phyaddr_1); } else { ret = -1; } } break; case IPU_SELECT_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; ret = ipu_select_buffer(parm.channel, parm.type, parm.bufNum); } break; case IPU_SELECT_MULTI_VDI_BUFFER: { uint32_t parm; if (copy_from_user (&parm, (uint32_t *) arg, sizeof(uint32_t))) return -EFAULT; ret = ipu_select_multi_vdi_buffer(parm); } break; case IPU_LINK_CHANNELS: { ipu_channel_link link; if (copy_from_user (&link, (ipu_channel_link *) arg, sizeof(ipu_channel_link))) return -EFAULT; ret = ipu_link_channels(link.src_ch, link.dest_ch); } break; case IPU_UNLINK_CHANNELS: { ipu_channel_link link; if (copy_from_user (&link, (ipu_channel_link *) arg, sizeof(ipu_channel_link))) return -EFAULT; ret = ipu_unlink_channels(link.src_ch, link.dest_ch); } break; case IPU_ENABLE_CHANNEL: { ipu_channel_t ch; int __user *argp = (void __user *)arg; if (get_user(ch, argp)) return -EFAULT; ipu_enable_channel(ch); } break; case IPU_DISABLE_CHANNEL: { ipu_channel_info info; if (copy_from_user (&info, (ipu_channel_info *) arg, sizeof(ipu_channel_info))) return -EFAULT; ret = ipu_disable_channel(info.channel, info.stop); } break; case IPU_ENABLE_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_enable_irq(irq); } break; case IPU_DISABLE_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_disable_irq(irq); } break; case IPU_CLEAR_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_clear_irq(irq); } break; case IPU_FREE_IRQ: { ipu_irq_info info; if (copy_from_user (&info, (ipu_irq_info *) arg, sizeof(ipu_irq_info))) return -EFAULT; ipu_free_irq(info.irq, info.dev_id); irq_info[info.irq].irq_pending = 0; } break; case IPU_REQUEST_IRQ_STATUS: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ret = ipu_get_irq_status(irq); } break; case IPU_REGISTER_GENERIC_ISR: { ipu_event_info info; if (copy_from_user (&info, (ipu_event_info *) arg, sizeof(ipu_event_info))) return -EFAULT; ret = ipu_request_irq(info.irq, mxc_ipu_generic_handler, 0, "video_sink", info.dev); if (ret == 0) init_waitqueue_head(&(irq_info[info.irq].waitq)); } break; case IPU_GET_EVENT: /* User will have to allocate event_type structure and pass the pointer in arg */ { ipu_event_info info; int r = -1; if (copy_from_user (&info, (ipu_event_info *) arg, sizeof(ipu_event_info))) return -EFAULT; r = get_events(&info); if (r == -1) { if ((file->f_flags & O_NONBLOCK) && (irq_info[info.irq].irq_pending == 0)) return -EAGAIN; wait_event_interruptible_timeout(irq_info[info.irq].waitq, (irq_info[info.irq].irq_pending != 0), 2 * HZ); r = get_events(&info); } ret = -1; if (r == 0) { if (!copy_to_user((ipu_event_info *) arg, &info, sizeof(ipu_event_info))) ret = 0; } } break; case IPU_ALOC_MEM: { ipu_mem_info info; if (copy_from_user (&info, (ipu_mem_info *) arg, sizeof(ipu_mem_info))) return -EFAULT; info.vaddr = dma_alloc_coherent(0, PAGE_ALIGN(info.size), &info.paddr, GFP_DMA | GFP_KERNEL); if (info.vaddr == 0) { printk(KERN_ERR "dma alloc failed!\n"); return -ENOBUFS; } if (copy_to_user((ipu_mem_info *) arg, &info, sizeof(ipu_mem_info)) > 0) return -EFAULT; } break; case IPU_FREE_MEM: { ipu_mem_info info; if (copy_from_user (&info, (ipu_mem_info *) arg, sizeof(ipu_mem_info))) return -EFAULT; if (info.vaddr) dma_free_coherent(0, PAGE_ALIGN(info.size), info.vaddr, info.paddr); else return -EFAULT; } break; case IPU_IS_CHAN_BUSY: { ipu_channel_t chan; if (copy_from_user (&chan, (ipu_channel_t *)arg, sizeof(ipu_channel_t))) return -EFAULT; if (ipu_is_channel_busy(chan)) ret = 1; else ret = 0; } break; case IPU_CALC_STRIPES_SIZE: { ipu_stripe_parm stripe_parm; if (copy_from_user (&stripe_parm, (ipu_stripe_parm *)arg, sizeof(ipu_stripe_parm))) return -EFAULT; ipu_calc_stripes_sizes(stripe_parm.input_width, stripe_parm.output_width, stripe_parm.maximal_stripe_width, stripe_parm.cirr, stripe_parm.equal_stripes, stripe_parm.input_pixelformat, stripe_parm.output_pixelformat, &stripe_parm.left, &stripe_parm.right); if (copy_to_user((ipu_stripe_parm *) arg, &stripe_parm, sizeof(ipu_stripe_parm)) > 0) return -EFAULT; } break; case IPU_UPDATE_BUF_OFFSET: { ipu_buf_offset_parm offset_parm; if (copy_from_user (&offset_parm, (ipu_buf_offset_parm *)arg, sizeof(ipu_buf_offset_parm))) return -EFAULT; ret = ipu_update_channel_offset(offset_parm.channel, offset_parm.type, offset_parm.pixel_fmt, offset_parm.width, offset_parm.height, offset_parm.stride, offset_parm.u_offset, offset_parm.v_offset, offset_parm.vertical_offset, offset_parm.horizontal_offset); } break; case IPU_CSC_UPDATE: { int param[5][3]; ipu_csc_update csc; if (copy_from_user(&csc, (void *) arg, sizeof(ipu_csc_update))) return -EFAULT; if (copy_from_user(¶m[0][0], (void *) csc.param, sizeof(param))) return -EFAULT; ipu_set_csc_coefficients(csc.channel, param); } break; default: break; } return ret; }
static int mxc_ipu_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; switch (cmd) { case IPU_INIT_CHANNEL: { ipu_channel_parm parm; if (copy_from_user (&parm, (ipu_channel_parm *) arg, sizeof(ipu_channel_parm))) return -EFAULT; if (!parm.flag) { ret = ipu_init_channel(parm.channel, &parm.params); } else { ret = ipu_init_channel(parm.channel, NULL); } } break; case IPU_UNINIT_CHANNEL: { ipu_channel_t ch; int __user *argp = (void __user *)arg; if (get_user(ch, argp)) return -EFAULT; ipu_uninit_channel(ch); } break; case IPU_INIT_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; ret = ipu_init_channel_buffer( parm.channel, parm.type, parm.pixel_fmt, parm.width, parm.height, parm.stride, parm.rot_mode, parm.phyaddr_0, parm.phyaddr_1, parm.u_offset, parm.v_offset); } break; case IPU_UPDATE_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; if ((parm.phyaddr_0 != (dma_addr_t) NULL) && (parm.phyaddr_1 == (dma_addr_t) NULL)) { ret = ipu_update_channel_buffer( parm.channel, parm.type, parm.bufNum, parm.phyaddr_0); } else if ((parm.phyaddr_0 == (dma_addr_t) NULL) && (parm.phyaddr_1 != (dma_addr_t) NULL)) { ret = ipu_update_channel_buffer( parm.channel, parm.type, parm.bufNum, parm.phyaddr_1); } else { ret = -1; } } break; case IPU_SELECT_CHANNEL_BUFFER: { ipu_channel_buf_parm parm; if (copy_from_user (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; ret = ipu_select_buffer(parm.channel, parm.type, parm.bufNum); } break; case IPU_LINK_CHANNELS: { ipu_channel_link link; if (copy_from_user (&link, (ipu_channel_link *) arg, sizeof(ipu_channel_link))) return -EFAULT; ret = ipu_link_channels(link.src_ch, link.dest_ch); } break; case IPU_UNLINK_CHANNELS: { ipu_channel_link link; if (copy_from_user (&link, (ipu_channel_link *) arg, sizeof(ipu_channel_link))) return -EFAULT; ret = ipu_unlink_channels(link.src_ch, link.dest_ch); } break; case IPU_ENABLE_CHANNEL: { ipu_channel_t ch; int __user *argp = (void __user *)arg; if (get_user(ch, argp)) return -EFAULT; ipu_enable_channel(ch); } break; case IPU_DISABLE_CHANNEL: { ipu_channel_info info; if (copy_from_user (&info, (ipu_channel_info *) arg, sizeof(ipu_channel_info))) return -EFAULT; ret = ipu_disable_channel(info.channel, info.stop); } break; case IPU_ENABLE_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_enable_irq(irq); } break; case IPU_DISABLE_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_disable_irq(irq); } break; case IPU_CLEAR_IRQ: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ipu_clear_irq(irq); } break; case IPU_FREE_IRQ: { ipu_irq_info info; int i; if (copy_from_user (&info, (ipu_irq_info *) arg, sizeof(ipu_irq_info))) return -EFAULT; ipu_free_irq(info.irq, info.dev_id); for (i = 0; i < MAX_Q_SIZE; i++) { if (events[i].irq == info.irq) events[i].irq = 0; } } break; case IPU_REQUEST_IRQ_STATUS: { uint32_t irq; int __user *argp = (void __user *)arg; if (get_user(irq, argp)) return -EFAULT; ret = ipu_get_irq_status(irq); } break; case IPU_REGISTER_GENERIC_ISR: { ipu_event_info info; if (copy_from_user (&info, (ipu_event_info *) arg, sizeof(ipu_event_info))) return -EFAULT; ret = ipu_request_irq(info.irq, mxc_ipu_generic_handler, 0, "video_sink", info.dev); } break; case IPU_GET_EVENT: /* User will have to allocate event_type structure and pass the pointer in arg */ { ipu_event_info info; int r = -1; if (copy_from_user (&info, (ipu_event_info *) arg, sizeof(ipu_event_info))) return -EFAULT; r = get_events(&info); if (r == -1) { wait_event_interruptible_timeout(waitq, (pending_events != 0), HZ/10); r = get_events(&info); } ret = -1; if (r == 0) { if (!copy_to_user((ipu_event_info *) arg, &info, sizeof(ipu_event_info))) ret = 0; } } break; case IPU_ALOC_MEM: { ipu_mem_info info; if (copy_from_user (&info, (ipu_mem_info *) arg, sizeof(ipu_mem_info))) return -EFAULT; info.vaddr = dma_alloc_coherent(0, PAGE_ALIGN(info.size), &info.paddr, GFP_DMA | GFP_KERNEL); if (info.vaddr == 0) { printk(KERN_ERR "dma alloc failed!\n"); return -ENOBUFS; } if (copy_to_user((ipu_mem_info *) arg, &info, sizeof(ipu_mem_info)) > 0) return -EFAULT; } break; case IPU_FREE_MEM: { ipu_mem_info info; if (copy_from_user (&info, (ipu_mem_info *) arg, sizeof(ipu_mem_info))) return -EFAULT; if (info.vaddr) dma_free_coherent(0, PAGE_ALIGN(info.size), info.vaddr, info.paddr); else return -EFAULT; } break; case IPU_IS_CHAN_BUSY: { ipu_channel_t chan; if (copy_from_user (&chan, (ipu_channel_t *)arg, sizeof(ipu_channel_t))) return -EFAULT; if (ipu_is_channel_busy(chan)) ret = 1; else ret = 0; } break; default: break; } return ret; }
/*! * This function handles PP_IOCTL_START calls. It sets the PP channel buffers * addresses and starts the channels * * @return This function returns 0 on success or negative error code on * error. */ static int mxc_pp_start(pp_buf * in, pp_buf * in_comb, pp_buf * mid, pp_buf * out) { int err = 0; FUNC_START; pp_data.done_flag = 0; if(pp_data.mode >= PP_PP_ROT) ipu_enable_irq(IPU_IRQ_PP_OUT_EOF); if(pp_data.mode <= PP_PP_ROT) ipu_enable_irq(IPU_IRQ_PP_ROT_OUT_EOF); if(pp_data.mode == PP_PP) { err = ipu_update_channel_buffer(MEM_PP_MEM, IPU_INPUT_BUFFER, 0, (void*)in->addr); if(err < 0) { printk("mxc_ipu_pp: error PP_PP input buffer\n"); goto err0; } err = ipu_update_channel_buffer(MEM_PP_MEM, IPU_OUTPUT_BUFFER, 0, (void*)out->addr); if(err < 0) { printk("mxc_ipu_pp: error PP_PP output buffer\n"); goto err0; } if(pp_data.ic_combine_en != 0) { err = ipu_update_channel_buffer(MEM_PP_MEM, IPU_SEC_INPUT_BUFFER, 0, (void*)in_comb->addr); if(err < 0) { printk("mxc_ipu_pp: error PP_PP second input buffer\n"); goto err0; } ipu_select_buffer(MEM_PP_MEM, IPU_SEC_INPUT_BUFFER, 0); } ipu_select_buffer(MEM_PP_MEM, IPU_INPUT_BUFFER, 0); ipu_select_buffer(MEM_PP_MEM, IPU_OUTPUT_BUFFER, 0); } else if(pp_data.mode == PP_PP_ROT) { err = ipu_update_channel_buffer(MEM_PP_MEM, IPU_INPUT_BUFFER, 0, (void*)in->addr); if(err < 0) { printk("mxc_ipu_pp: error PP_PP_ROT input buffer\n"); goto err0; } err = ipu_update_channel_buffer(MEM_PP_MEM, IPU_OUTPUT_BUFFER, 0, (void*)mid->addr); if(err < 0) { printk("mxc_ipu_pp: error setting PP_PP_ROT middle output buffer\n"); goto err0; } err = ipu_update_channel_buffer(MEM_ROT_PP_MEM, IPU_INPUT_BUFFER, 0, (void*)mid->addr); if(err < 0) { printk("mxc_ipu_pp: error setting PP_PP_ROT middle input buffer\n"); goto err0; } err = ipu_update_channel_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0, (void*)out->addr); if(err < 0) { printk("mxc_ipu_pp: error setting PP_PP_ROT output buffer\n"); goto err0; } if(pp_data.ic_combine_en != 0) { err = ipu_update_channel_buffer(MEM_PP_MEM, IPU_SEC_INPUT_BUFFER, 0, (void*)in_comb->addr); if(err < 0) { printk("mxc_ipu_pp: error PP_PP_ROT second input buffer\n"); goto err0; } ipu_select_buffer(MEM_PP_MEM, IPU_SEC_INPUT_BUFFER, 0); } ipu_select_buffer(MEM_PP_MEM, IPU_INPUT_BUFFER, 0); ipu_select_buffer(MEM_PP_MEM, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0); } else if(pp_data.mode == PP_ROT) { err = ipu_update_channel_buffer(MEM_ROT_PP_MEM, IPU_INPUT_BUFFER, 0, (void*)in->addr); if(err < 0) { printk("mxc_ipu_pp: error setting PP_ROT input buffer\n"); goto err0; } err = ipu_update_channel_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0, (void*)out->addr); if(err < 0) { printk("mxc_ipu_pp: error setting PP_ROT output buffer\n"); goto err0; } ipu_select_buffer(MEM_ROT_PP_MEM, IPU_INPUT_BUFFER, 0); ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0); } if(!pp_data.pp_enabled) { pp_data.pp_enabled = 1; if(pp_data.mode == PP_PP) ipu_enable_channel(MEM_PP_MEM); else if(pp_data.mode == PP_PP_ROT) { ipu_enable_channel(MEM_PP_MEM); ipu_enable_channel(MEM_ROT_PP_MEM); } else if(pp_data.mode == PP_ROT) { ipu_enable_channel(MEM_ROT_PP_MEM); } } FUNC_END; return 0; err0: return err; }