/*! * Shut down the voutera * * @param vout structure vout_data * * * @return status 0 Success */ static int mxc_v4l2out_streamoff(vout_data * vout) { int retval = 0; u32 lockflag = 0; if (!vout) return -EINVAL; if (vout->state == STATE_STREAM_OFF) { return 0; } spin_lock_irqsave(&g_lock, lockflag); del_timer(&vout->output_timer); if (vout->state == STATE_STREAM_ON) { vout->state = STATE_STREAM_STOPPING; } ipu_disable_irq(IPU_IRQ_PP_IN_EOF); spin_unlock_irqrestore(&g_lock, lockflag); if (vout->post_proc_ch == MEM_PP_MEM) { /* SDC or ADC with Rotation */ ipu_disable_channel(MEM_PP_MEM, true); if (vout->rotate >= IPU_ROTATE_90_RIGHT) { ipu_disable_channel(MEM_ROT_PP_MEM, true); ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM); ipu_unlink_channels(MEM_ROT_PP_MEM, vout->display_ch); } else { ipu_unlink_channels(MEM_PP_MEM, vout->display_ch); } ipu_disable_channel(vout->display_ch, true); ipu_uninit_channel(vout->display_ch); ipu_uninit_channel(MEM_PP_MEM); ipu_uninit_channel(MEM_ROT_PP_MEM); } else { /* ADC Direct */ ipu_disable_channel(MEM_PP_ADC, true); ipu_uninit_channel(MEM_PP_ADC); } vout->ready_q.head = vout->ready_q.tail = 0; vout->state = STATE_STREAM_OFF; #ifdef CONFIG_FB_MXC_ASYNC_PANEL if (vout->cur_disp_output != DISP3) { mxcfb_set_refresh_mode(registered_fb [vout-> output_fb_num[vout->cur_disp_output]], MXCFB_REFRESH_PARTIAL, 0); } #endif return retval; }
/*! * This function handles PP_IOCTL_UNINIT calls. It uninitializes the PP channels * and interrupt handlers. * * @return This function returns 0 on success or negative error code on error */ static int mxc_pp_uninit(void) { pp_data.pp_enabled = 0; ipu_disable_irq(IPU_IRQ_PP_ROT_OUT_EOF); ipu_disable_irq(IPU_IRQ_PP_OUT_EOF); ipu_disable_channel(MEM_PP_MEM, true); ipu_disable_channel(MEM_ROT_PP_MEM, true); ipu_uninit_channel(MEM_PP_MEM); ipu_uninit_channel(MEM_ROT_PP_MEM); /* ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM); */ return 0; }
/* * Send Power Off commands to L4F00242T03 * */ static void lcd_poweroff(void) { const u16 slpin = 0x10; const u16 disoff = 0x28; ipu_channel_params_t param; if (!lcd_on) return; dev_dbg(lcd_dev, "turning off LCD\n"); if (lcd_spi) { msleep(60); spi_write(lcd_spi, (const u8 *)&disoff, 1); msleep(60); spi_write(lcd_spi, (const u8 *)&slpin, 1); } else { memset(¶m, 0, sizeof(param)); ipu_init_channel(DIRECT_ASYNC1, ¶m); ipu_disp_direct_write(DIRECT_ASYNC1, disoff, 0); msleep(60); ipu_disp_direct_write(DIRECT_ASYNC1, slpin, 0); msleep(1); ipu_uninit_channel(DIRECT_ASYNC1); } lcd_on = 0; }
int cleanup_before_linux(void) { unsigned int i; #ifdef CONFIG_CMD_IMX_DOWNLOAD_MODE extern void clear_mfgmode_mem(void); clear_mfgmode_mem(); #endif #ifdef CONFIG_VIDEO_MX5 ipu_disable_channel(MEM_BG_SYNC); ipu_uninit_channel(MEM_BG_SYNC); #endif /* * this function is called just before we call linux * it prepares the processor for linux * * we turn off caches etc ... */ disable_interrupts(); /* flush cache */ cache_flush(); /* turn off I/D-cache */ icache_disable(); /* invalidate D-cache */ dcache_disable(); #ifndef CONFIG_L2_OFF /* turn off L2 cache */ l2_cache_disable(); /* invalidate L2 cache also */ v7_flush_dcache_all(get_device_type()); #endif i = 0; /* mem barrier to sync up things */ asm("mcr p15, 0, %0, c7, c10, 4": :"r"(i)); /* turn off MMU */ MMU_OFF(); #ifndef CONFIG_L2_OFF l2_cache_enable(); #endif return 0; }
/* * Send init commands to L4F00242T03 * */ static void lcd_init(void) { const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) }; dev_dbg(lcd_dev, "initializing LCD\n"); if (lcd_spi) { spi_write(lcd_spi, (const u8 *)cmd, ARRAY_SIZE(cmd)); } else { ipu_disp_direct_write(DIRECT_ASYNC1, 0x36, 0); ipu_disp_direct_write(DIRECT_ASYNC1, 0x100, 0); ipu_disp_direct_write(DIRECT_ASYNC1, 0x3A, 0); ipu_disp_direct_write(DIRECT_ASYNC1, 0x160, 0); msleep(1); ipu_uninit_channel(DIRECT_ASYNC1); } }
void ipuv3_fb_shutdown(void) { int i; struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT; for (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) { struct fb_info *fbi = mxcfb_info[i]; if (fbi) { struct mxcfb_info *mxc_fbi = fbi->par; ipu_disable_channel(mxc_fbi->ipu_ch); ipu_uninit_channel(mxc_fbi->ipu_ch); } } for (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) { __raw_writel(__raw_readl(&stat->int_stat[i]), &stat->int_stat[i]); } }
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; }
/* * Set framebuffer parameters and change the operating mode. * * @param info framebuffer information pointer */ static int mxcfb_set_par(struct fb_info *fbi) { int retval = 0; u32 mem_len; ipu_di_signal_cfg_t sig_cfg; struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; uint32_t out_pixel_fmt; ipu_disable_channel(mxc_fbi->ipu_ch); ipu_uninit_channel(mxc_fbi->ipu_ch); mxcfb_set_fix(fbi); mem_len = fbi->var.yres_virtual * fbi->fix.line_length; if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) { if (fbi->fix.smem_start) mxcfb_unmap_video_memory(fbi); if (mxcfb_map_video_memory(fbi) < 0) return -ENOMEM; } setup_disp_channel1(fbi); memset(&sig_cfg, 0, sizeof(sig_cfg)); if (fbi->var.vmode & FB_VMODE_INTERLACED) { sig_cfg.interlaced = 1; out_pixel_fmt = IPU_PIX_FMT_YUV444; } else { if (mxc_fbi->ipu_di_pix_fmt) out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt; else out_pixel_fmt = IPU_PIX_FMT_RGB666; } if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */ sig_cfg.odd_field_first = 1; if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used) sig_cfg.ext_clk = 1; if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) sig_cfg.Hsync_pol = 1; if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) sig_cfg.Vsync_pol = 1; if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL)) sig_cfg.clk_pol = 1; if (fbi->var.sync & FB_SYNC_DATA_INVERT) sig_cfg.data_pol = 1; if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT)) sig_cfg.enable_pol = 1; if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN) sig_cfg.clkidle_en = 1; debug("pixclock = %lu Hz\n", PICOS2KHZ(fbi->var.pixclock) * 1000UL); if (ipu_init_sync_panel(mxc_fbi->ipu_di, (PICOS2KHZ(fbi->var.pixclock)) * 1000UL, fbi->var.xres, fbi->var.yres, out_pixel_fmt, fbi->var.left_margin, fbi->var.hsync_len, fbi->var.right_margin, fbi->var.upper_margin, fbi->var.vsync_len, fbi->var.lower_margin, 0, sig_cfg) != 0) { puts("mxcfb: Error initializing panel.\n"); return -EINVAL; } retval = setup_disp_channel2(fbi); if (retval) return retval; if (mxc_fbi->blank == FB_BLANK_UNBLANK) ipu_enable_channel(mxc_fbi->ipu_ch); return retval; }
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; }
int mxcfb_set_refresh_mode(struct fb_info *fbi, int mode, struct mxcfb_rect *update_region) { unsigned long start_addr; int ret_mode; uint32_t dummy; ipu_channel_params_t params; struct mxcfb_rect rect; struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; uint32_t stride_pixels = (fbi->fix.line_length * 8) / fbi->var.bits_per_pixel; uint32_t memsize = fbi->fix.smem_len; if (mxc_fbi->cur_update_mode == mode) return mode; ret_mode = mxc_fbi->cur_update_mode; ipu_disable_irq(IPU_IRQ_ADC_SYS1_EOF); ipu_adc_set_update_mode(ADC_SYS1, IPU_ADC_REFRESH_NONE, 0, 0, 0); #ifdef PARTIAL_REFRESH ipu_disable_irq(IPU_IRQ_ADC_SYS2_EOF); ipu_adc_set_update_mode(ADC_SYS2, IPU_ADC_REFRESH_NONE, 0, 0, 0); #endif ipu_disable_channel(ADC_SYS1, true); ipu_clear_irq(IPU_IRQ_ADC_SYS1_EOF); #ifdef PARTIAL_REFRESH ipu_disable_channel(ADC_SYS2, true); ipu_clear_irq(IPU_IRQ_ADC_SYS2_EOF); #endif ipu_adc_get_snooping_status(&dummy, &dummy); mxc_fbi->cur_update_mode = mode; switch (mode) { case MXCFB_REFRESH_OFF: if (ipu_adc_set_update_mode(ADC_SYS1, IPU_ADC_REFRESH_NONE, 0, 0, 0) < 0) dev_err(fbi->device, "Error enabling auto refesh.\n"); if (ipu_adc_set_update_mode(ADC_SYS2, IPU_ADC_REFRESH_NONE, 0, 0, 0) < 0) dev_err(fbi->device, "Error enabling auto refesh.\n"); #if 0 ipu_init_channel_buffer(ADC_SYS2, IPU_INPUT_BUFFER, bpp_to_pixfmt(fbi->var.bits_per_pixel), 1, 1, 4, IPU_ROTATE_NONE, fbi->fix.smem_start, fbi->fix.smem_start, 0, 0); ipu_enable_channel(ADC_SYS2); ipu_select_buffer(ADC_SYS2, IPU_INPUT_BUFFER, 0); ipu_select_buffer(ADC_SYS2, IPU_INPUT_BUFFER, 1); msleep(10); #endif ipu_uninit_channel(ADC_SYS1); #ifdef PARTIAL_REFRESH ipu_uninit_channel(ADC_SYS2); #endif break; case MXCFB_REFRESH_PARTIAL: #ifdef PARTIAL_REFRESH ipu_adc_get_snooping_status(&dummy, &dummy); params.adc_sys2.disp = DISP0; params.adc_sys2.ch_mode = WriteTemplateNonSeq; params.adc_sys2.out_left = 0; params.adc_sys2.out_top = 0; ipu_init_channel(ADC_SYS2, ¶ms); if (ipu_adc_set_update_mode(ADC_SYS1, IPU_ADC_REFRESH_NONE, 0, 0, 0) < 0) { dev_err(fbi->device, "Error enabling auto refesh.\n"); } if (ipu_adc_set_update_mode (ADC_SYS2, IPU_ADC_AUTO_REFRESH_SNOOP, 30, fbi->fix.smem_start, &memsize) < 0) { dev_err(fbi->device, "Error enabling auto refesh.\n"); } mxc_fbi->snoop_window_size = memsize; ipu_init_channel_buffer(ADC_SYS2, IPU_INPUT_BUFFER, bpp_to_pixfmt(fbi->var.bits_per_pixel), 1, 1, 4, IPU_ROTATE_NONE, fbi->fix.smem_start, 0, 0, 0); params.adc_sys1.disp = mxc_fbi->disp_num; params.adc_sys1.ch_mode = WriteTemplateNonSeq; params.adc_sys1.out_left = MXCFB_SCREEN_LEFT_OFFSET; params.adc_sys1.out_top = MXCFB_SCREEN_TOP_OFFSET; ipu_init_channel(ADC_SYS1, ¶ms); ipu_init_channel_buffer(ADC_SYS1, IPU_INPUT_BUFFER, bpp_to_pixfmt(fbi->var.bits_per_pixel), MXCFB_SCREEN_WIDTH, MXCFB_SCREEN_HEIGHT, stride_pixels, IPU_ROTATE_NONE, fbi->fix.smem_start, 0, 0, 0); ipu_enable_channel(ADC_SYS1); ipu_select_buffer(ADC_SYS1, IPU_INPUT_BUFFER, 0); ipu_enable_irq(IPU_IRQ_ADC_SYS1_EOF); break; #endif case MXCFB_REFRESH_AUTO: if (update_region == NULL) { update_region = ▭ rect.top = 0; rect.left = 0; rect.height = MXCFB_SCREEN_HEIGHT; rect.width = MXCFB_SCREEN_WIDTH; } params.adc_sys1.disp = mxc_fbi->disp_num; params.adc_sys1.ch_mode = WriteTemplateNonSeq; params.adc_sys1.out_left = MXCFB_SCREEN_LEFT_OFFSET + update_region->left; params.adc_sys1.out_top = MXCFB_SCREEN_TOP_OFFSET + update_region->top; ipu_init_channel(ADC_SYS1, ¶ms); /* Address aligned to line */ start_addr = update_region->top * fbi->fix.line_length; start_addr += fbi->fix.smem_start; start_addr += update_region->left * fbi->var.bits_per_pixel / 8; ipu_init_channel_buffer(ADC_SYS1, IPU_INPUT_BUFFER, bpp_to_pixfmt(fbi->var.bits_per_pixel), update_region->width, update_region->height, stride_pixels, IPU_ROTATE_NONE, start_addr, 0, 0, 0); ipu_enable_channel(ADC_SYS1); ipu_select_buffer(ADC_SYS1, IPU_INPUT_BUFFER, 0); if (ipu_adc_set_update_mode (ADC_SYS1, IPU_ADC_AUTO_REFRESH_SNOOP, 30, fbi->fix.smem_start, &memsize) < 0) dev_err(fbi->device, "Error enabling auto refesh.\n"); mxc_fbi->snoop_window_size = memsize; break; } return ret_mode; }
static irqreturn_t mxcfb_sys2_eof_irq_handler(int irq, void *dev_id) { ipu_channel_params_t params; struct fb_info *fbi = dev_id; struct mxcfb_info *mxc_fbi = fbi->par; uint32_t stat[2], seg_size; uint32_t lsb, msb; uint32_t update_height, start_line, start_addr, end_line, end_addr; uint32_t stride_pixels = (fbi->fix.line_length * 8) / fbi->var.bits_per_pixel; ipu_adc_get_snooping_status(&stat[0], &stat[1]); if (!stat[0] && !stat[1]) { dev_err(fbi->device, "error no bus snooping bits set\n"); return IRQ_HANDLED; } ipu_disable_irq(IPU_IRQ_ADC_SYS2_EOF); lsb = ffs(stat[0]); if (lsb) { lsb--; } else { lsb = ffs(stat[1]); lsb += 32 - 1; } msb = fls(stat[1]); if (msb) { msb += 32; } else { msb = fls(stat[0]); } seg_size = mxc_fbi->snoop_window_size / 64; start_addr = lsb * seg_size; /* starting address offset */ start_line = start_addr / fbi->fix.line_length; start_addr = start_line * fbi->fix.line_length; /* Addr aligned to line */ start_addr += fbi->fix.smem_start; end_addr = msb * seg_size; /* ending address offset */ end_line = end_addr / fbi->fix.line_length; end_line++; if (end_line > fbi->var.yres) { end_line = fbi->var.yres; } update_height = end_line - start_line; dev_dbg(fbi->device, "updating rows %d to %d, start addr = 0x%08X\n", start_line, end_line, start_addr); ipu_uninit_channel(ADC_SYS1); params.adc_sys1.disp = mxc_fbi->disp_num; params.adc_sys1.ch_mode = WriteTemplateNonSeq; params.adc_sys1.out_left = MXCFB_SCREEN_LEFT_OFFSET; params.adc_sys1.out_top = start_line; ipu_init_channel(ADC_SYS1, ¶ms); ipu_init_channel_buffer(ADC_SYS1, IPU_INPUT_BUFFER, bpp_to_pixfmt(fbi->var.bits_per_pixel), MXCFB_SCREEN_WIDTH, update_height, stride_pixels, IPU_ROTATE_NONE, (dma_addr_t) start_addr, 0, 0, 0); ipu_enable_channel(ADC_SYS1); ipu_select_buffer(ADC_SYS1, IPU_INPUT_BUFFER, 0); ipu_enable_irq(IPU_IRQ_ADC_SYS1_EOF); return IRQ_HANDLED; }
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; }
static void mxcfb_update_region(struct fb_info *fbi, uint32_t statl, uint32_t stath) { ipu_channel_params_t params; struct mxcfb_info *mxc_fbi = fbi->par; uint32_t seg_size; uint32_t lsb, msb; uint32_t update_height, start_line, start_addr, end_line, end_addr; uint32_t stride_pixels = (fbi->fix.line_length * 8) / fbi->var.bits_per_pixel; lsb = ffs(statl); if (lsb) { lsb--; } else { lsb = ffs(stath); lsb += 32 - 1; } msb = fls(stath); if (msb) { msb += 32; } else { msb = fls(statl); } seg_size = mxc_fbi->snoop_window_size / 64; start_addr = lsb * seg_size; // starting address offset start_line = start_addr / fbi->fix.line_length; start_addr = start_line * fbi->fix.line_length; // Addr aligned to line start_addr += fbi->fix.smem_start; end_addr = msb * seg_size; // ending address offset end_line = end_addr / fbi->fix.line_length; end_line++; if (end_line > fbi->var.yres) { end_line = fbi->var.yres; } update_height = end_line - start_line; dev_dbg(fbi->device, "updating rows %d to %d, start addr = 0x%08X\n", start_line, end_line, start_addr); ipu_uninit_channel(ADC_SYS1); params.adc_sys1.disp = mxc_fbi->disp_num; params.adc_sys1.ch_mode = WriteTemplateNonSeq; params.adc_sys1.out_left = MXCFB_SCREEN_LEFT_OFFSET; params.adc_sys1.out_top = start_line; ipu_init_channel(ADC_SYS1, ¶ms); ipu_init_channel_buffer(ADC_SYS1, IPU_INPUT_BUFFER, bpp_to_pixfmt(fbi->var.bits_per_pixel), MXCFB_SCREEN_WIDTH, update_height, stride_pixels, IPU_ROTATE_NONE, (dma_addr_t) start_addr, 0, 0, 0); ipu_enable_channel(ADC_SYS1); ipu_select_buffer(ADC_SYS1, IPU_INPUT_BUFFER, 0); ipu_enable_irq(IPU_IRQ_ADC_SYS1_EOF); }