static int setup_disp_channel1(struct fb_info *fbi)
{
	ipu_channel_params_t params;
	struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;

	memset(&params, 0, sizeof(params));
	params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;

	debug("%s called\n", __func__);
	/*
	 * Assuming interlaced means yuv output, below setting also
	 * valid for mem_dc_sync. FG should have the same vmode as BG.
	 */
	if (fbi->var.vmode & FB_VMODE_INTERLACED) {
		params.mem_dp_bg_sync.interlaced = 1;
		params.mem_dp_bg_sync.out_pixel_fmt =
			IPU_PIX_FMT_YUV444;
	} else {
		if (mxc_fbi->ipu_di_pix_fmt) {
			params.mem_dp_bg_sync.out_pixel_fmt =
				mxc_fbi->ipu_di_pix_fmt;
		} else {
			params.mem_dp_bg_sync.out_pixel_fmt =
				IPU_PIX_FMT_RGB666;
		}
	}
	params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
	if (mxc_fbi->alpha_chan_en)
		params.mem_dp_bg_sync.alpha_chan_en = 1;

	ipu_init_channel(mxc_fbi->ipu_ch, &params);

	return 0;
}
static int setup_disp_channel2(struct fb_info *fbi)
{
	int retval = 0;
	struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;

	mxc_fbi->cur_ipu_buf = 1;
	if (mxc_fbi->alpha_chan_en)
		mxc_fbi->cur_ipu_alpha_buf = 1;

	fbi->var.xoffset = fbi->var.yoffset = 0;

	debug("%s: %x %d %d %d %lx %lx\n",
		__func__,
		mxc_fbi->ipu_ch,
		fbi->var.xres,
		fbi->var.yres,
		fbi->fix.line_length,
		fbi->fix.smem_start,
		fbi->fix.smem_start +
		(fbi->fix.line_length * fbi->var.yres));

	retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
					 bpp_to_pixfmt(fbi),
					 fbi->var.xres, fbi->var.yres,
					 fbi->fix.line_length,
					 fbi->fix.smem_start +
					 (fbi->fix.line_length * fbi->var.yres),
					 fbi->fix.smem_start,
					 0, 0);
	if (retval)
		printf("ipu_init_channel_buffer error %d\n", retval);

	return retval;
}
Beispiel #3
0
/*
 * This routine actually sets the video mode. It's in here where we
 * the hardware state info->par and fix which can be affected by the
 * change in par. For this driver it doesn't do much.
 *
 */
static int mxc_elcdif_fb_set_par(struct fb_info *fbi)
{
	struct mxc_elcdif_fb_data *data = (struct mxc_elcdif_fb_data *)fbi->par;
	struct elcdif_signal_cfg sig_cfg;
	int mem_len;

	dev_dbg(fbi->device, "Reconfiguring framebuffer\n");

	/* If parameter no change, don't reconfigure. */
	if (mxc_elcdif_fb_par_equal(fbi, data))
	    return 0;

	sema_init(&data->flip_sem, 1);

	/* release prev panel */
	if (!g_elcdif_pix_clk_enable) {
		clk_enable(g_elcdif_pix_clk);
		g_elcdif_pix_clk_enable = true;
	}
	mxc_elcdif_blank_panel(FB_BLANK_POWERDOWN);
	mxc_elcdif_stop();
	release_dotclk_panel();
	mxc_elcdif_dma_release();
	mxc_elcdif_fb_set_fix(fbi);
	if (g_elcdif_pix_clk_enable) {
		clk_disable(g_elcdif_pix_clk);
		g_elcdif_pix_clk_enable = false;
	}

	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)
			mxc_elcdif_fb_unmap_video_memory(fbi);

		if (mxc_elcdif_fb_map_video_memory(fbi) < 0)
			return -ENOMEM;
	}

	if (data->next_blank != FB_BLANK_UNBLANK)
		return 0;

	/* init next panel */
	if (!g_elcdif_pix_clk_enable) {
		clk_enable(g_elcdif_pix_clk);
		g_elcdif_pix_clk_enable = true;
	}
	mxc_init_elcdif();
	mxc_elcdif_init_panel();

	dev_dbg(fbi->device, "pixclock = %u Hz\n",
		(u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));

	memset(&sig_cfg, 0, sizeof(sig_cfg));
	if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
		sig_cfg.Hsync_pol = true;
	if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
		sig_cfg.Vsync_pol = true;
	if (fbi->var.sync & FB_SYNC_CLK_LAT_FALL)
		sig_cfg.clk_pol = true;
	if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
		sig_cfg.enable_pol = true;

	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.yres,
			   fbi->var.hsync_len,
			   fbi->var.left_margin +
			   fbi->var.xres + fbi->var.right_margin,
			   fbi->var.left_margin,
			   fbi->var.xres,
			   bpp_to_pixfmt(fbi),
			   data->output_pix_fmt,
			   sig_cfg,
			   1);
	mxc_elcdif_frame_addr_setup(fbi->fix.smem_start);
	mxc_elcdif_run();
	mxc_elcdif_blank_panel(FB_BLANK_UNBLANK);

	fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
							 &fbi->modelist);
	data->var = fbi->var;

	return 0;
}
Beispiel #4
0
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, &params);

		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, &params);

		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;
			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, &params);

		/* 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;
}
Beispiel #5
0
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, &params);

	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;
}
Beispiel #6
0
static int __set_par(struct fb_info *fbi, bool lock)
{
	u32 mem_len;
	struct ipu_di_signal_cfg sig_cfg;
	enum ipu_panel mode = IPU_PANEL_TFT;
	struct mx3fb_info *mx3_fbi = fbi->par;
	struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
	struct idmac_channel *ichan = mx3_fbi->idmac_channel;
	struct idmac_video_param *video = &ichan->params.video;
	struct scatterlist *sg = mx3_fbi->sg;

	/* Total cleanup */
	if (mx3_fbi->txd)
		sdc_disable_channel(mx3_fbi);

	mx3fb_set_fix(fbi);

	mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
	if (mem_len > fbi->fix.smem_len) {
		if (fbi->fix.smem_start)
			mx3fb_unmap_video_memory(fbi);

		if (mx3fb_map_video_memory(fbi, mem_len, lock) < 0)
			return -ENOMEM;
	}

	sg_init_table(&sg[0], 1);
	sg_init_table(&sg[1], 1);

	sg_dma_address(&sg[0]) = fbi->fix.smem_start;
	sg_set_page(&sg[0], virt_to_page(fbi->screen_base),
		    fbi->fix.smem_len,
		    offset_in_page(fbi->screen_base));

	if (mx3_fbi->ipu_ch == IDMAC_SDC_0) {
		memset(&sig_cfg, 0, sizeof(sig_cfg));
		if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
			sig_cfg.Hsync_pol = true;
		if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
			sig_cfg.Vsync_pol = true;
		if (fbi->var.sync & FB_SYNC_CLK_INVERT)
			sig_cfg.clk_pol = true;
		if (fbi->var.sync & FB_SYNC_DATA_INVERT)
			sig_cfg.data_pol = true;
		if (fbi->var.sync & FB_SYNC_OE_ACT_HIGH)
			sig_cfg.enable_pol = true;
		if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
			sig_cfg.clkidle_en = true;
		if (fbi->var.sync & FB_SYNC_CLK_SEL_EN)
			sig_cfg.clksel_en = true;
		if (fbi->var.sync & FB_SYNC_SHARP_MODE)
			mode = IPU_PANEL_SHARP_TFT;

		dev_dbg(fbi->device, "pixclock = %ul Hz\n",
			(u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));

		if (sdc_init_panel(mx3fb, mode,
				   (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
				   fbi->var.xres, fbi->var.yres,
				   (fbi->var.sync & FB_SYNC_SWAP_RGB) ?
				   IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666,
				   fbi->var.left_margin,
				   fbi->var.hsync_len,
				   fbi->var.right_margin +
				   fbi->var.hsync_len,
				   fbi->var.upper_margin,
				   fbi->var.vsync_len,
				   fbi->var.lower_margin +
				   fbi->var.vsync_len, sig_cfg) != 0) {
			dev_err(fbi->device,
				"mx3fb: Error initializing panel.\n");
			return -EINVAL;
		}
	}

	sdc_set_window_pos(mx3fb, mx3_fbi->ipu_ch, 0, 0);

	mx3_fbi->cur_ipu_buf	= 0;

	video->out_pixel_fmt	= bpp_to_pixfmt(fbi->var.bits_per_pixel);
	video->out_width	= fbi->var.xres;
	video->out_height	= fbi->var.yres;
	video->out_stride	= fbi->var.xres_virtual;

	if (mx3_fbi->blank == FB_BLANK_UNBLANK)
		sdc_enable_channel(mx3_fbi);

	return 0;
}
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, &params);

	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);
}