Exemple #1
0
/**
 * sdc_set_color_key() - set the transparent color key for SDC graphic plane.
 * @mx3fb:	mx3fb context.
 * @channel:	IPU DMAC channel ID.
 * @enable:	boolean to enable or disable color keyl.
 * @color_key:	24-bit RGB color to use as transparent color key.
 * @return:	0 on success or negative error code on failure.
 */
static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,
			     bool enable, uint32_t color_key)
{
	uint32_t reg, sdc_conf;
	unsigned long lock_flags;

	spin_lock_irqsave(&mx3fb->lock, lock_flags);

	sdc_conf = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
	if (channel == IDMAC_SDC_0)
		sdc_conf &= ~SDC_COM_GWSEL;
	else
		sdc_conf |= SDC_COM_GWSEL;

	if (enable) {
		reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0xFF000000L;
		mx3fb_write_reg(mx3fb, reg | (color_key & 0x00FFFFFFL),
			     SDC_GW_CTRL);

		sdc_conf |= SDC_COM_KEY_COLOR_G;
	} else {
		sdc_conf &= ~SDC_COM_KEY_COLOR_G;
	}
	mx3fb_write_reg(mx3fb, sdc_conf, SDC_COM_CONF);

	spin_unlock_irqrestore(&mx3fb->lock, lock_flags);

	return 0;
}
Exemple #2
0
static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value)
{
	dev_dbg(mx3fb->dev, "%s: value = %d\n", __func__, value);
	/* This might be board-specific */
	mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL);
	return;
}
Exemple #3
0
static void sdc_fb_init(struct mx3fb_info *fbi)
{
	struct mx3fb_data *mx3fb = fbi->mx3fb;
	uint32_t reg;

	reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);

	mx3fb_write_reg(mx3fb, reg | SDC_COM_BG_EN, SDC_COM_CONF);
}
Exemple #4
0
/* Returns enabled flag before uninit */
static uint32_t sdc_fb_uninit(struct mx3fb_info *fbi)
{
	struct mx3fb_data *mx3fb = fbi->mx3fb;
	uint32_t reg;

	reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);

	mx3fb_write_reg(mx3fb, reg & ~SDC_COM_BG_EN, SDC_COM_CONF);

	return reg & SDC_COM_BG_EN;
}
Exemple #5
0
/**
 * sdc_set_window_pos() - set window position of the respective plane.
 * @mx3fb:	mx3fb context.
 * @channel:	IPU DMAC channel ID.
 * @x_pos:	X coordinate relative to the top left corner to place window at.
 * @y_pos:	Y coordinate relative to the top left corner to place window at.
 * @return:	0 on success or negative error code on failure.
 */
static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel,
			      int16_t x_pos, int16_t y_pos)
{
	if (channel != IDMAC_SDC_0)
		return -EINVAL;

	x_pos += mx3fb->h_start_width;
	y_pos += mx3fb->v_start_width;

	mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
	return 0;
}
Exemple #6
0
/**
 * sdc_set_global_alpha() - set global alpha blending modes.
 * @mx3fb:	mx3fb context.
 * @enable:	boolean to enable or disable global alpha blending. If disabled,
 *		per pixel blending is used.
 * @alpha:	global alpha value.
 * @return:	0 on success or negative error code on failure.
 */
static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t alpha)
{
	uint32_t reg;
	unsigned long lock_flags;

	spin_lock_irqsave(&mx3fb->lock, lock_flags);

	if (enable) {
		reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0x00FFFFFFL;
		mx3fb_write_reg(mx3fb, reg | ((uint32_t) alpha << 24), SDC_GW_CTRL);

		reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
		mx3fb_write_reg(mx3fb, reg | SDC_COM_GLB_A, SDC_COM_CONF);
	} else {
		reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
		mx3fb_write_reg(mx3fb, reg & ~SDC_COM_GLB_A, SDC_COM_CONF);
	}

	spin_unlock_irqrestore(&mx3fb->lock, lock_flags);

	return 0;
}
Exemple #7
0
/**
 * sdc_init_panel() - initialize a synchronous LCD panel.
 * @mx3fb:		mx3fb context.
 * @panel:		panel type.
 * @pixel_clk:		desired pixel clock frequency in Hz.
 * @width:		width of panel in pixels.
 * @height:		height of panel in pixels.
 * @pixel_fmt:		pixel format of buffer as FOURCC ASCII code.
 * @h_start_width:	number of pixel clocks between the HSYNC signal pulse
 *			and the start of valid data.
 * @h_sync_width:	width of the HSYNC signal in units of pixel clocks.
 * @h_end_width:	number of pixel clocks between the end of valid data
 *			and the HSYNC signal for next line.
 * @v_start_width:	number of lines between the VSYNC signal pulse and the
 *			start of valid data.
 * @v_sync_width:	width of the VSYNC signal in units of lines
 * @v_end_width:	number of lines between the end of valid data and the
 *			VSYNC signal for next frame.
 * @sig:		bitfield of signal polarities for LCD interface.
 * @return:		0 on success or negative error code on failure.
 */
static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
			  uint32_t pixel_clk,
			  uint16_t width, uint16_t height,
			  enum pixel_fmt pixel_fmt,
			  uint16_t h_start_width, uint16_t h_sync_width,
			  uint16_t h_end_width, uint16_t v_start_width,
			  uint16_t v_sync_width, uint16_t v_end_width,
			  struct ipu_di_signal_cfg sig)
{
	unsigned long lock_flags;
	uint32_t reg;
	uint32_t old_conf;
	uint32_t div;
	struct clk *ipu_clk;

	dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height);

	if (v_sync_width == 0 || h_sync_width == 0)
		return -EINVAL;

	/* Init panel size and blanking periods */
	reg = ((uint32_t) (h_sync_width - 1) << 26) |
		((uint32_t) (width + h_start_width + h_end_width - 1) << 16);
	mx3fb_write_reg(mx3fb, reg, SDC_HOR_CONF);

#ifdef DEBUG
	printk(KERN_CONT " hor_conf %x,", reg);
#endif

	reg = ((uint32_t) (v_sync_width - 1) << 26) | SDC_V_SYNC_WIDTH_L |
	    ((uint32_t) (height + v_start_width + v_end_width - 1) << 16);
	mx3fb_write_reg(mx3fb, reg, SDC_VER_CONF);

#ifdef DEBUG
	printk(KERN_CONT " ver_conf %x\n", reg);
#endif

	mx3fb->h_start_width = h_start_width;
	mx3fb->v_start_width = v_start_width;

	switch (panel) {
	case IPU_PANEL_SHARP_TFT:
		mx3fb_write_reg(mx3fb, 0x00FD0102L, SDC_SHARP_CONF_1);
		mx3fb_write_reg(mx3fb, 0x00F500F4L, SDC_SHARP_CONF_2);
		mx3fb_write_reg(mx3fb, SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
		break;
	case IPU_PANEL_TFT:
		mx3fb_write_reg(mx3fb, SDC_COM_TFT_COLOR, SDC_COM_CONF);
		break;
	default:
		return -EINVAL;
	}

	/* Init clocking */

	/*
	 * Calculate divider: fractional part is 4 bits so simply multiple by
	 * 2^4 to get fractional part, as long as we stay under ~250MHz and on
	 * i.MX31 it (HSP_CLK) is <= 178MHz. Currently 128.267MHz
	 */
	ipu_clk = clk_get(mx3fb->dev, NULL);
	if (!IS_ERR(ipu_clk)) {
		div = clk_get_rate(ipu_clk) * 16 / pixel_clk;
		clk_put(ipu_clk);
	} else {
		div = 0;
	}

	if (div < 0x40) {	/* Divider less than 4 */
		dev_dbg(mx3fb->dev,
			"InitPanel() - Pixel clock divider less than 4\n");
		div = 0x40;
	}

	dev_dbg(mx3fb->dev, "pixel clk = %u, divider %u.%u\n",
		pixel_clk, div >> 4, (div & 7) * 125);

	spin_lock_irqsave(&mx3fb->lock, lock_flags);

	/*
	 * DISP3_IF_CLK_DOWN_WR is half the divider value and 2 fraction bits
	 * fewer. Subtract 1 extra from DISP3_IF_CLK_DOWN_WR based on timing
	 * debug. DISP3_IF_CLK_UP_WR is 0
	 */
	mx3fb_write_reg(mx3fb, (((div / 8) - 1) << 22) | div, DI_DISP3_TIME_CONF);

	/* DI settings */
	old_conf = mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF) & 0x78FFFFFF;
	old_conf |= sig.datamask_en << DI_D3_DATAMSK_SHIFT |
		sig.clksel_en << DI_D3_CLK_SEL_SHIFT |
		sig.clkidle_en << DI_D3_CLK_IDLE_SHIFT;
	mx3fb_write_reg(mx3fb, old_conf, DI_DISP_IF_CONF);

	old_conf = mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL) & 0xE0FFFFFF;
	old_conf |= sig.data_pol << DI_D3_DATA_POL_SHIFT |
		sig.clk_pol << DI_D3_CLK_POL_SHIFT |
		sig.enable_pol << DI_D3_DRDY_SHARP_POL_SHIFT |
		sig.Hsync_pol << DI_D3_HSYNC_POL_SHIFT |
		sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT;
	mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL);

	switch (pixel_fmt) {
	case IPU_PIX_FMT_RGB24:
		mx3fb_write_reg(mx3fb, di_mappings[0], DI_DISP3_B0_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[1], DI_DISP3_B1_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[2], DI_DISP3_B2_MAP);
		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
			     ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC);
		break;
	case IPU_PIX_FMT_RGB666:
		mx3fb_write_reg(mx3fb, di_mappings[4], DI_DISP3_B0_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[5], DI_DISP3_B1_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[6], DI_DISP3_B2_MAP);
		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
			     ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC);
		break;
	case IPU_PIX_FMT_BGR666:
		mx3fb_write_reg(mx3fb, di_mappings[8], DI_DISP3_B0_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[9], DI_DISP3_B1_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[10], DI_DISP3_B2_MAP);
		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
			     ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC);
		break;
	default:
		mx3fb_write_reg(mx3fb, di_mappings[12], DI_DISP3_B0_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[13], DI_DISP3_B1_MAP);
		mx3fb_write_reg(mx3fb, di_mappings[14], DI_DISP3_B2_MAP);
		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
			     ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC);
		break;
	}

	spin_unlock_irqrestore(&mx3fb->lock, lock_flags);

	dev_dbg(mx3fb->dev, "DI_DISP_IF_CONF = 0x%08X\n",
		mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF));
	dev_dbg(mx3fb->dev, "DI_DISP_SIG_POL = 0x%08X\n",
		mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL));
	dev_dbg(mx3fb->dev, "DI_DISP3_TIME_CONF = 0x%08X\n",
		mx3fb_read_reg(mx3fb, DI_DISP3_TIME_CONF));

	return 0;
}
Exemple #8
0
static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value)
{
	/* This might be board-specific */
	mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL);
	return;
}