int psb_gamma_set(struct drm_device *dev, void *data)
{
	uint16_t * lut_arg = data;

//      struct drm_mode_object *obj;
	struct drm_crtc *crtc;
	struct drm_connector *connector;
	struct psb_intel_crtc *psb_intel_crtc;
	struct drm_psb_private *dev_priv = dev->dev_private;
	int i = 0;

//      int32_t obj_id;

//      obj_id = lut_arg->output_id;
//      obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR);
//      if (!obj) {
//              printk(KERN_ERR "Invalid Connector object, id = %d\n", obj_id);
//              DRM_DEBUG("Invalid Connector object.\n");
//              return -EINVAL;
//      }
	connector = dev_priv->dpst_connector;	//= obj_to_connector(obj);
	crtc = connector->encoder->crtc;

	psb_intel_crtc = to_psb_intel_crtc(crtc);
	 for (i = 0; i < 256; i++) {
		psb_intel_crtc->lut_adj[i] = lut_arg[i];
	}
	 psb_intel_crtc_load_lut(crtc);

	return 0;
}
static void cdv_hdmi_mode_set(struct drm_encoder *encoder,
			struct drm_display_mode *mode,
			struct drm_display_mode *adjusted_mode)
{
	struct drm_device *dev = encoder->dev;
	struct psb_intel_encoder *psb_intel_encoder = to_psb_intel_encoder(encoder);
	struct mid_intel_hdmi_priv *hdmi_priv = psb_intel_encoder->dev_priv;
	u32 hdmib;
	struct drm_crtc *crtc = encoder->crtc;
	struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);

	hdmib = (2 << 10);

	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
		hdmib |= HDMI_VSYNC_ACTIVE_HIGH;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
		hdmib |= HDMI_HSYNC_ACTIVE_HIGH;

	if (intel_crtc->pipe == 1)
		hdmib |= HDMIB_PIPE_B_SELECT;

	if (hdmi_priv->has_hdmi_audio) {
		hdmib |= HDMI_AUDIO_ENABLE;
		hdmib |= HDMI_NULL_PACKETS_DURING_VSYNC;
	}

	REG_WRITE(hdmi_priv->hdmi_reg, hdmib);
	REG_READ(hdmi_priv->hdmi_reg);
}
static void dpst_save_gamma_settings(struct drm_device *dev)
{
    struct drm_psb_private *dev_priv = dev->dev_private;
    struct drm_connector *connector;
    struct mdfld_dsi_config *dsi_config;
    struct drm_crtc *crtc;
    struct psb_intel_crtc *psb_intel_crtc;
    int i = 0;

    if (!dev_priv)
        return;

    connector = dev_priv->dpst_connector;
    dsi_config = dev_priv->dsi_configs[0];

    crtc = connector->encoder->crtc;
    psb_intel_crtc = to_psb_intel_crtc(crtc);

    /*
    * FIXME: We need to force the Display to
    * turn on but on TNG OSPM how we can force PIPEA to do it?
    */
    if (!power_island_get(OSPM_DISPLAY_A))
    {
	return;
    }

    for (i = 0; i < 256; i++)
        lut_adj[i] = REG_READ((PALETTE_A + 4 * i));

    power_island_put(OSPM_DISPLAY_A);
}
static void dpst_restore_gamma_settings(struct drm_device *dev)
{
	struct drm_psb_private *dev_priv = dev->dev_private;
	struct mdfld_dsi_config *dsi_config;
	struct mdfld_dsi_hw_context *ctx;
	struct drm_connector *connector;
	struct drm_crtc *crtc;
	struct psb_intel_crtc *psb_intel_crtc;
	int i = 0;

	if (!dev_priv)
		return;

	connector = dev_priv->dpst_lvds_connector;
	dsi_config = dev_priv->dsi_configs[0];
	ctx = &dsi_config->dsi_hw_context;

	crtc = connector->encoder->crtc;
	psb_intel_crtc = to_psb_intel_crtc(crtc);

	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
				OSPM_UHB_FORCE_POWER_ON))
		return;
	mdfld_dsi_dsr_forbid(dsi_config);

	for (i = 0; i < 256; i++) {
		ctx->palette[i] = lut_adj[i];
		REG_WRITE((PALETTE_A + 4 * i), lut_adj[i]);
	}

	mdfld_dsi_dsr_allow(dsi_config);
	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
}
예제 #5
0
/*
 * Update the DBI MIPI Panel Frame Buffer.
 */
static void mdfld_dsi_dbi_update_fb(struct mdfld_dsi_dbi_output *dbi_output,
								int pipe)
{
	struct mdfld_dsi_pkg_sender *sender =
		mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base);
	struct drm_device *dev = dbi_output->dev;
	struct drm_crtc *crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc *psb_crtc = (crtc) ?
					to_psb_intel_crtc(crtc) : NULL;
	u32 dpll_reg = MRST_DPLL_A;
	u32 dspcntr_reg = DSPACNTR;
	u32 pipeconf_reg = PIPEACONF;
	u32 dsplinoff_reg = DSPALINOFF;
	u32 dspsurf_reg = DSPASURF;
	u32 reg_offset = 0;

	/* If mode setting on-going, back off */
	if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
		(psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING) ||
		!(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE))
		return;

	if (pipe == 2) {
		dspcntr_reg = DSPCCNTR;
		pipeconf_reg = PIPECCONF;
		dsplinoff_reg = DSPCLINOFF;
		dspsurf_reg = DSPCSURF;
		reg_offset = MIPIC_REG_OFFSET;
	}

	if (!gma_power_begin(dev, true)) {
		dev_err(dev->dev, "hw begin failed\n");
		return;
	}

	/* Check DBI FIFO status */
	if (!(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) ||
	   !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) ||
	   !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE))
		goto update_fb_out0;

	/* Refresh plane changes */
	REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg));
	REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg));
	REG_READ(dspsurf_reg);

	mdfld_dsi_send_dcs(sender,
			   DCS_WRITE_MEM_START,
			   NULL,
			   0,
			   CMD_DATA_SRC_PIPE,
			   MDFLD_DSI_SEND_PACKAGE);

	dbi_output->dsr_fb_update_done = true;
update_fb_out0:
	gma_power_end(dev);
}
예제 #6
0
static int mdfld_intel_crtc_cursor_set(struct drm_crtc *crtc,
				 struct drm_file *file_priv,
				 uint32_t handle,
				 uint32_t width, uint32_t height)
{
	struct drm_device *dev = crtc->dev;
	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
	int pipe = psb_intel_crtc->pipe;
	uint32_t control = CURACNTR;
	uint32_t base = CURABASE;
	uint32_t temp;
	size_t addr = 0;
	struct gtt_range *gt;
	struct drm_gem_object *obj;
	int ret;

	switch (pipe) {
	case 0:
		break;
	case 1:
		control = CURBCNTR;
		base = CURBBASE;
		break;
	case 2:
		control = CURCCNTR;
		base = CURCBASE;
		break;
	default:
		dev_err(dev->dev, "Illegal Pipe Number. \n");
		return -EINVAL;
	}
	
#if 1 /* FIXME_JLIU7 can't enalbe cursorB/C HW issue. need to remove after HW fix */
	if (pipe != 0)
		return 0;
#endif 
	/* if we want to turn of the cursor ignore width and height */
	if (!handle) {
		dev_dbg(dev->dev, "cursor off\n");
		/* turn off the cursor */
		temp = 0;
		temp |= CURSOR_MODE_DISABLE;

		if (gma_power_begin(dev, true)) {
			REG_WRITE(control, temp);
			REG_WRITE(base, 0);
			gma_power_end(dev);
		}
		/* Unpin the old GEM object */
		if (psb_intel_crtc->cursor_obj) {
			gt = container_of(psb_intel_crtc->cursor_obj,
							struct gtt_range, gem);
			psb_gtt_unpin(gt);
			drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
			psb_intel_crtc->cursor_obj = NULL;
		}
static int cdv_hdmi_set_property(struct drm_connector *connector,
				       struct drm_property *property,
				       uint64_t value)
{
	struct drm_encoder *encoder = connector->encoder;

	if (!strcmp(property->name, "scaling mode") && encoder) {
		struct psb_intel_crtc *crtc = to_psb_intel_crtc(encoder->crtc);
		bool centre;
		uint64_t curValue;

		if (!crtc)
			return -1;

		switch (value) {
		case DRM_MODE_SCALE_FULLSCREEN:
			break;
		case DRM_MODE_SCALE_NO_SCALE:
			break;
		case DRM_MODE_SCALE_ASPECT:
			break;
		default:
			return -1;
		}

		if (drm_connector_property_get_value(connector,
							property, &curValue))
			return -1;

		if (curValue == value)
			return 0;

		if (drm_connector_property_set_value(connector,
							property, value))
			return -1;

		centre = (curValue == DRM_MODE_SCALE_NO_SCALE) ||
			(value == DRM_MODE_SCALE_NO_SCALE);

		if (crtc->saved_mode.hdisplay != 0 &&
		    crtc->saved_mode.vdisplay != 0) {
			if (centre) {
				if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
					    encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
					return -1;
			} else {
				struct drm_encoder_helper_funcs *helpers
						    = encoder->helper_private;
				helpers->mode_set(encoder, &crtc->saved_mode,
					     &crtc->saved_adjusted_mode);
			}
		}
	}
	return 0;
}
예제 #8
0
static void cdv_intel_crt_mode_set(struct drm_encoder *encoder,
			       struct drm_display_mode *mode,
			       struct drm_display_mode *adjusted_mode)
{

	struct drm_device *dev = encoder->dev;
	struct drm_crtc *crtc = encoder->crtc;
	struct psb_intel_crtc *psb_intel_crtc =
					to_psb_intel_crtc(crtc);
	int dpll_md_reg;
	u32 adpa, dpll_md;
	u32 adpa_reg;

	if (psb_intel_crtc->pipe == 0)
		dpll_md_reg = DPLL_A_MD;
	else
		dpll_md_reg = DPLL_B_MD;

	adpa_reg = ADPA;

	/*
	 * Disable separate mode multiplier used when cloning SDVO to CRT
	 * XXX this needs to be adjusted when we really are cloning
	 */
	{
		dpll_md = REG_READ(dpll_md_reg);
		REG_WRITE(dpll_md_reg,
			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
	}

	adpa = 0;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
		adpa |= ADPA_VSYNC_ACTIVE_HIGH;

	if (psb_intel_crtc->pipe == 0)
		adpa |= ADPA_PIPE_A_SELECT;
	else
		adpa |= ADPA_PIPE_B_SELECT;

	REG_WRITE(adpa_reg, adpa);
}
int psb_gamma_set(struct drm_device *dev, void *data)
{
	uint16_t *lut_arg = data;
	struct drm_crtc *crtc;
	struct drm_connector *connector;
	struct psb_intel_crtc *psb_intel_crtc;
	struct drm_psb_private *dev_priv = dev->dev_private;
	int i = 0;

	connector = dev_priv->dpst_lvds_connector;

	crtc = connector->encoder->crtc;
	psb_intel_crtc = to_psb_intel_crtc(crtc);

	for (i = 0; i < 256; i++)
		psb_intel_crtc->lut_adj[i] = lut_arg[i];

	psb_intel_crtc_load_lut(crtc);

	return 0;
}
static void cdv_intel_crt_mode_set(struct drm_encoder *encoder,
			       struct drm_display_mode *mode,
			       struct drm_display_mode *adjusted_mode)
{

	struct drm_device *dev = encoder->dev;
	struct drm_crtc *crtc = encoder->crtc;
	struct psb_intel_crtc *psb_intel_crtc =
					to_psb_intel_crtc(crtc);
	int dpll_md_reg;
	u32 adpa, dpll_md;
	u32 adpa_reg;

	if (psb_intel_crtc->pipe == 0)
		dpll_md_reg = DPLL_A_MD;
	else
		dpll_md_reg = DPLL_B_MD;

	adpa_reg = ADPA;

	{
		dpll_md = REG_READ(dpll_md_reg);
		REG_WRITE(dpll_md_reg,
			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
	}

	adpa = 0;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
		adpa |= ADPA_VSYNC_ACTIVE_HIGH;

	if (psb_intel_crtc->pipe == 0)
		adpa |= ADPA_PIPE_A_SELECT;
	else
		adpa |= ADPA_PIPE_B_SELECT;

	REG_WRITE(adpa_reg, adpa);
}
예제 #11
0
/*
 * Enter DSR
 */
void mdfld_dsi_dbi_enter_dsr(struct mdfld_dsi_dbi_output *dbi_output, int pipe)
{
	u32 reg_val;
	struct drm_device *dev = dbi_output->dev;
	struct drm_psb_private *dev_priv = dev->dev_private;
	struct drm_crtc *crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc *psb_crtc = (crtc) ?
					to_psb_intel_crtc(crtc) : NULL;
	u32 dpll_reg = MRST_DPLL_A;
	u32 pipeconf_reg = PIPEACONF;
	u32 dspcntr_reg = DSPACNTR;

	if (!dbi_output)
		return;

	/* FIXME check if can go */
	dev_priv->is_in_idle = true;

	gdbi_output = dbi_output;
	if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
		(psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING))
		return;

	if (pipe == 2) {
		dpll_reg = MRST_DPLL_A;
		pipeconf_reg = PIPECCONF;
		dspcntr_reg = DSPCCNTR;
	}

	if (!gma_power_begin(dev, true)) {
		dev_err(dev->dev, "hw begin failed\n");
		return;
	}
	/* Disable te interrupts */
	mdfld_disable_te(dev, pipe);

	/* Disable plane */
	reg_val = REG_READ(dspcntr_reg);
	if (!(reg_val & DISPLAY_PLANE_ENABLE)) {
		REG_WRITE(dspcntr_reg, reg_val & ~DISPLAY_PLANE_ENABLE);
		REG_READ(dspcntr_reg);
	}

	/* Disable pipe */
	reg_val = REG_READ(pipeconf_reg);
	if (!(reg_val & DISPLAY_PLANE_ENABLE)) {
		reg_val &= ~DISPLAY_PLANE_ENABLE;
		reg_val |= (PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF);
		REG_WRITE(pipeconf_reg, reg_val);
		REG_READ(pipeconf_reg);
		mdfldWaitForPipeDisable(dev, pipe);
	}

	/* Disable DPLL */
	reg_val = REG_READ(dpll_reg);
	if (!(reg_val & DPLL_VCO_ENABLE)) {
		reg_val &= ~DPLL_VCO_ENABLE;
		REG_WRITE(dpll_reg, reg_val);
		REG_READ(dpll_reg);
		udelay(500);
	}

	gma_power_end(dev);
	dbi_output->mode_flags |= MODE_SETTING_IN_DSR;
	if (pipe == 2) {
		enter_dsr = 1;
		/* pm_schedule_suspend(&dev->pdev->dev, gfxrtdelay); */
	}
}
예제 #12
0
/* Unlike most Intel display engines, on Cedarview the DPLL registers
 * are behind this sideband bus.  They must be programmed while the
 * DPLL reference clock is on in the DPLL control register, but before
 * the DPLL is enabled in the DPLL control register.
 */
int
psb_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
		       struct psb_intel_clock_t *clock, bool is_lvds, u32 ddi_select)
{
	struct psb_intel_crtc *psb_crtc =
				to_psb_intel_crtc(crtc);
	int pipe = psb_crtc->pipe;
	u32 m, n_vco, p;
	int ret = 0;
	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
	int ref_sfr = (pipe == 0) ? SB_REF_DPLLA : SB_REF_DPLLB;
	u32 ref_value;
	u32 lane_reg, lane_value;

	psb_print_clock(clock);

	psb_sb_reset(dev);

	REG_WRITE(dpll_reg, DPLL_SYNCLOCK_ENABLE | DPLL_VGA_MODE_DIS);

	udelay(100);

	/* Follow the BIOS and write the REF/SFR Register. Hardcoded value */
	psb_sb_read(dev, SB_REF_SFR(pipe), &ref_value);
	ref_value = 0x68A701;
	psb_sb_write(dev, SB_REF_SFR(pipe), ref_value);
	
	/* We don't know what the other fields of these regs are, so
	 * leave them in place.
	 */
	/* 
	 * The BIT 14:13 of 0x8010/0x8030 is used to select the ref clk
	 * for the pipe A/B. Display spec 1.06 has wrong definition.
	 * Correct definition is like below:
	 *
	 * refclka mean use clock from same PLL
	 *
	 * if DPLLA sets 01 and DPLLB sets 01, they use clock from their pll
	 *
	 * if DPLLA sets 01 and DPLLB sets 02, both use clk from DPLLA
	 *
	 */  
	ret = psb_sb_read(dev, ref_sfr, &ref_value);
	if (ret)
		return ret;
	ref_value &= ~(REF_CLK_MASK);

	/* use DPLL_A for pipeB on CRT/HDMI */

	if (pipe == 1 && !is_lvds && !(ddi_select & DP_MASK)) {
		DRM_DEBUG_KMS("use DPLLA for pipe B\n");
		ref_value |= REF_CLK_DPLLA;
	} else {
		DRM_DEBUG_KMS("use their DPLL for pipe A/B\n");
		ref_value |= REF_CLK_DPLL;
	}
	ret = psb_sb_write(dev, ref_sfr, ref_value);
	if (ret)
		return ret;
	
	ret = psb_sb_read(dev, SB_M(pipe), &m);
	if (ret)
		return ret;
	m &= ~SB_M_DIVIDER_MASK;
	m |= ((clock->m2) << SB_M_DIVIDER_SHIFT);
	ret = psb_sb_write(dev, SB_M(pipe), m);
	if (ret)
		return ret;

	ret = psb_sb_read(dev, SB_N_VCO(pipe), &n_vco);
	if (ret)
		return ret;

	/* Follow the BIOS to program the N_DIVIDER REG */
	n_vco &= 0xFFFF;
	n_vco |= 0x107;
	n_vco &= ~(SB_N_VCO_SEL_MASK |
		   SB_N_DIVIDER_MASK |
		   SB_N_CB_TUNE_MASK);

	n_vco |= ((clock->n) << SB_N_DIVIDER_SHIFT);

	if (clock->vco < 2250000) {
		n_vco |= (2 << SB_N_CB_TUNE_SHIFT);
		n_vco |= (0 << SB_N_VCO_SEL_SHIFT);
	} else if (clock->vco < 2750000) {
		n_vco |= (1 << SB_N_CB_TUNE_SHIFT);
		n_vco |= (1 << SB_N_VCO_SEL_SHIFT);
	} else if (clock->vco < 3300000) {
		n_vco |= (0 << SB_N_CB_TUNE_SHIFT);
		n_vco |= (2 << SB_N_VCO_SEL_SHIFT);
	} else {
		n_vco |= (0 << SB_N_CB_TUNE_SHIFT);
		n_vco |= (3 << SB_N_VCO_SEL_SHIFT);
	}

	ret = psb_sb_write(dev, SB_N_VCO(pipe), n_vco);
	if (ret)
		return ret;

	ret = psb_sb_read(dev, SB_P(pipe), &p);
	if (ret)
		return ret;
	p &= ~(SB_P2_DIVIDER_MASK | SB_P1_DIVIDER_MASK);
	p |= SET_FIELD(clock->p1, SB_P1_DIVIDER);
	switch (clock->p2) {
	case 5:
		p |= SET_FIELD(SB_P2_5, SB_P2_DIVIDER);
		break;
	case 10:
		p |= SET_FIELD(SB_P2_10, SB_P2_DIVIDER);
		break;
	case 14:
		p |= SET_FIELD(SB_P2_14, SB_P2_DIVIDER);
		break;
	case 7:
		p |= SET_FIELD(SB_P2_7, SB_P2_DIVIDER);
		break;
	default:
		DRM_ERROR("Bad P2 clock: %d\n", clock->p2);
		return -EINVAL;
	}
	ret = psb_sb_write(dev, SB_P(pipe), p);
	if (ret)
		return ret;

	/* Issue Title: 
	 *     DP/HDMI lanes were dead during cold temperature.
	 *
	 * Reason for this failure: 
	 *     Reference Clk required to power these lanes were not sufficient enough
	 *     and hence in cold temperature the lanes were failing. Now EV team came
	 *     up with a work around which utilizes a different alt ref path and to 
	 *     disable Op Amp (which was previously generating reference clk) and 
	 *     enable Alt_Ref Path.
	 */
	ref_value = 0x14100300;
	ret = psb_sb_write(dev, SB_ALT_REF(pipe), ref_value);
	if (ret)
		return ret;

	ref_value = 0x1FFB0010;
	ret = psb_sb_write(dev, SB_MISC_DFX(pipe), ref_value);
	if (ret)
		return ret;

	ref_value = 0x10100300;
	ret = psb_sb_write(dev, SB_ALT_REF(pipe), ref_value);
	if (ret)
		return ret;

	if (ddi_select) {
		if ((ddi_select & DDI_MASK) == DDI0_SELECT) {
			lane_reg = PSB_LANE0;
			psb_sb_read(dev, lane_reg, &lane_value);
			lane_value &= ~(LANE_PLL_MASK);
			lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
			psb_sb_write(dev, lane_reg, lane_value);

			lane_reg = PSB_LANE1;
			psb_sb_read(dev, lane_reg, &lane_value);
			lane_value &= ~(LANE_PLL_MASK);
			lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
			psb_sb_write(dev, lane_reg, lane_value);
		} else {
			lane_reg = PSB_LANE2;
			psb_sb_read(dev, lane_reg, &lane_value);
			lane_value &= ~(LANE_PLL_MASK);
			lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
			psb_sb_write(dev, lane_reg, lane_value);

			lane_reg = PSB_LANE3;
			psb_sb_read(dev, lane_reg, &lane_value);
			lane_value &= ~(LANE_PLL_MASK);
			lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
			psb_sb_write(dev, lane_reg, lane_value);
		}
	}

	return 0;
}
void mdfld_panel_generic_dsi_dbi_update_fb(
	struct mdfld_dsi_dbi_output *dbi_output,
	int pipe)
{
	struct mdfld_dsi_pkg_sender *sender =
		mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base);
	struct drm_device *dev = dbi_output->dev;
	struct drm_psb_private *dev_priv = dev->dev_private;
	struct drm_crtc *crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc *psb_crtc =
		(crtc) ? to_psb_intel_crtc(crtc) : NULL;
	u32 dpll_reg = MRST_DPLL_A;
	u32 dspcntr_reg = DSPACNTR;
	u32 pipeconf_reg = PIPEACONF;
	u32 dsplinoff_reg = DSPALINOFF;
	u32 dspsurf_reg = DSPASURF;

	if (!dev_priv->dsi_init_done)
		return;

	/* if mode setting on-going, back off */
	if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
			(psb_crtc &&
			 (psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) ||
			!(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE))
		return;

	if (pipe == 2) {
		dspcntr_reg = DSPCCNTR;
		pipeconf_reg = PIPECCONF;
		dsplinoff_reg = DSPCLINOFF;
		dspsurf_reg = DSPCSURF;
	}

	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
				OSPM_UHB_FORCE_POWER_ON)) {
		DRM_ERROR("hw begin failed\n");
		return;
	}

	/* check DBI FIFO status */
	if (!(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) ||
	   !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) ||
	   !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) {
		goto update_fb_out0;
	}

	/* refresh plane changes */
	REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg));
	REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg));
	REG_READ(dspsurf_reg);

	mdfld_dsi_send_dcs(sender,
			   write_mem_start,
			   NULL,
			   0,
			   CMD_DATA_SRC_PIPE,
			   MDFLD_DSI_SEND_PACKAGE);

	dbi_output->dsr_fb_update_done = true;


update_fb_out0:
	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
}
예제 #14
0
static int __mdfld_dbi_exit_dsr(struct mdfld_dsi_dbi_output * dbi_output, int pipe)
{
	struct drm_device * dev = dbi_output->dev;
	struct drm_crtc * crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc * psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL; 
	u32 reg_val;
	u32 dpll_reg = PSB_DSI_PLL_CTRL;
	u32 pipeconf_reg = PSB_PIPECONF(PSB_PIPE_A);
	u32 dspcntr_reg = PSB_DSPCNTR(PSB_PIPE_A);
	u32 dspbase_reg = PSB_DSPBASE(PSB_PIPE_A);
	u32 dspsurf_reg = PSB_DSPSURF(PSB_PIPE_A);

	PSB_DEBUG_ENTRY("\n");

	if(!dbi_output) {
		return 0;
	}

	/*if mode setting on-going, back off*/
	if((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
		(psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) 
		return -EAGAIN;
		
	if(pipe == 2) {
		dpll_reg = PSB_DSI_PLL_CTRL;
		pipeconf_reg = PSB_PIPECONF(PSB_PIPE_C);
		dspcntr_reg = PSB_DSPCNTR(PSB_PIPE_C);
		dspbase_reg = MDFLD_DSPCBASE;
		dspsurf_reg = PSB_DSPSURF(PSB_PIPE_C);
	}

	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, true))
		return -EAGAIN;

	/*enable DPLL*/
	reg_val = REG_READ(dpll_reg);
	if(!(reg_val & DPLL_VCO_ENABLE)) {
		
		if(reg_val & MDFLD_PWR_GATE_EN) {
			reg_val &= ~MDFLD_PWR_GATE_EN;
			REG_WRITE(dpll_reg, reg_val);
			REG_READ(dpll_reg);
			udelay(500);
		}
		
		reg_val |= DPLL_VCO_ENABLE;
		REG_WRITE(dpll_reg, reg_val);
		REG_READ(dpll_reg);
		udelay(500);
		
		/*FIXME: add timeout*/
		while (!(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK));
	}
	
	/*enable pipe*/
	reg_val = REG_READ(pipeconf_reg);
	if(!(reg_val & PIPEACONF_ENABLE)) {
		reg_val |= PIPEACONF_ENABLE;
		REG_WRITE(pipeconf_reg, reg_val);
		REG_READ(pipeconf_reg);
		udelay(500);
		mdfldWaitForPipeEnable(dev, pipe);
	}
	
	/*enable plane*/
	reg_val = REG_READ(dspcntr_reg);
	if(!(reg_val & DISPLAY_PLANE_ENABLE)) {
		reg_val |= DISPLAY_PLANE_ENABLE;
		REG_WRITE(dspcntr_reg, reg_val);
		REG_READ(dspcntr_reg);
		udelay(500);
	}
	
	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
	
	/*clean IN_DSR flag*/
	dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR;
	
	return 0;
}
예제 #15
0
static int mdfld_dpu_update_fb(struct drm_device * dev) {
	struct drm_crtc * crtc;
	struct psb_intel_crtc * psb_crtc;
	struct mdfld_dsi_dbi_output ** dbi_output;
	struct drm_psb_private * dev_priv = dev->dev_private;
	struct mdfld_dbi_dpu_info * dpu_info = dev_priv->dbi_dpu_info;
	bool pipe_updated[2];
	unsigned long irq_flags;
	u32 dpll_reg = PSB_DSI_PLL_CTRL;
	u32 dspcntr_reg = PSB_DSPCNTR(PSB_PIPE_A);
	u32 pipeconf_reg = PSB_PIPECONF(PSB_PIPE_A);
	u32 dsplinoff_reg = PSB_DSPLINOFF(PSB_PIPE_A);
	u32 dspsurf_reg = PSB_DSPSURF(PSB_PIPE_A);
	int pipe;
	int i;
	int ret;

	dbi_output = dpu_info->dbi_outputs;
	pipe_updated[0] = pipe_updated[1] = false;
	
	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, true))
		return -EAGAIN;

	/*try to prevent any new damage reports*/	
	if(!spin_trylock_irqsave(&dpu_info->dpu_update_lock, irq_flags)) {
		return -EAGAIN;
	}

	for(i=0; i<dpu_info->dbi_output_num; i++) {
		crtc = dbi_output[i]->base.base.crtc;
		psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL; 

                pipe = dbi_output[i]->channel_num ? 2 : 0;

                if(pipe == 2) {
			dspcntr_reg = PSB_DSPCNTR(PSB_PIPE_C);
			pipeconf_reg = PSB_PIPECONF(PSB_PIPE_C);
			dsplinoff_reg = PSB_DSPLINOFF(PSB_PIPE_C);
			dspsurf_reg = PSB_DSPSURF(PSB_PIPE_C);
                }

                if (!(REG_READ(MIPI_GEN_FIFO_STAT_REG(pipe)) & BIT(27)) ||
                   !(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) ||
                   !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) ||
                   !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) {
                        PSB_DEBUG_ENTRY("DBI FIFO is busy, DSI %d state %x\n",
                                        pipe,
                                        REG_READ(MIPI_INTR_STAT_REG(pipe)));
                        continue;
                }

		/*if dbi output is in a exclusive state, pipe change won't be updated*/
		if(dbi_output[i]->dbi_panel_on &&
		   !(dbi_output[i]->mode_flags & MODE_SETTING_ON_GOING) &&
		   !(psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING) &&
		   !(dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR)) {
			ret = mdfld_dpu_update_pipe(dbi_output[i], dpu_info, dbi_output[i]->channel_num ? 2 : 0);
			if(!ret) {
				pipe_updated[i] = true;
			}
		} 
	}
	
	for(i=0; i<dpu_info->dbi_output_num; i++) {
		if(pipe_updated[i]) {
			mdfld_dbi_flush_cb(dbi_output[i], dbi_output[i]->channel_num ? 2 : 0);
		}
	}

	spin_unlock_irqrestore(&dpu_info->dpu_update_lock, irq_flags);
	
	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
	
	return 0;
}
static
void intel_dsi_dbi_update_fb(struct mdfld_dsi_dbi_output *dbi_output)
{
	struct mdfld_dsi_pkg_sender *sender;
	struct drm_device *dev = dbi_output->dev;
	struct drm_crtc *crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc *psb_crtc =
		(crtc) ? to_psb_intel_crtc(crtc) : NULL;
	int pipe = dbi_output->channel_num ? 2 : 0;
	u32 dpll_reg = MRST_DPLL_A;
	u32 dspcntr_reg = DSPACNTR;
	u32 pipeconf_reg = PIPEACONF;
	u32 dsplinoff_reg = DSPALINOFF;
	u32 dspsurf_reg = DSPASURF;

	sender = mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base);
	if (!sender) {
		DRM_ERROR("pkg sender is NULL\n");
		return;
	}

	/* if mode setting on-going, back off */

	if (!IS_ANN_A0(dev)) {
		if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
				(psb_crtc && (psb_crtc->mode_flags & MODE_SETTING_ON_GOING)) ||
				!(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE))
			return;
	}

	if (pipe == 2) {
		dspcntr_reg = DSPCCNTR;
		pipeconf_reg = PIPECCONF;
		dsplinoff_reg = DSPCLINOFF;
		dspsurf_reg = DSPCSURF;
	}

	/* check DBI FIFO status */
	if (is_panel_vid_or_cmd(dev) == MDFLD_DSI_ENCODER_DBI) {
		if (!(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) ||
		   !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE))
			return;
	} else if (!(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) ||
	   !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) ||
	   !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE))
		return;

	if (!IS_ANN_A0(dev)) {
		/* refresh plane changes */

		REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg));
		REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg));
		REG_READ(dspsurf_reg);
	}

	mdfld_dsi_send_dcs(sender,
			   write_mem_start,
			   NULL,
			   0,
			   CMD_DATA_SRC_PIPE,
			   MDFLD_DSI_SEND_PACKAGE);
	dbi_output->dsr_fb_update_done = true;
	mdfld_dsi_cmds_kick_out(sender);
}
예제 #17
0
/**
 * Update the DBI MIPI Panel Frame Buffer.
 */
static void pyr_dsi_dbi_update_fb (struct mdfld_dsi_dbi_output * dbi_output, int pipe)
{
	struct mdfld_dsi_pkg_sender * sender =
		mdfld_dsi_encoder_get_pkg_sender(&dbi_output->base);
	struct drm_device * dev = dbi_output->dev;
	struct drm_crtc * crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc * psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL; 

	u32 dpll_reg = MRST_DPLL_A;
	u32 dspcntr_reg = DSPACNTR;
	u32 pipeconf_reg = PIPEACONF;
	u32 dsplinoff_reg = DSPALINOFF;
	u32 dspsurf_reg = DSPASURF;
	/*u32 mipi_state_reg = MIPIA_INTR_STAT_REG;*/
	u32 hs_gen_ctrl_reg = HS_GEN_CTRL_REG;
	u32 gen_fifo_stat_reg = GEN_FIFO_STAT_REG;
	u32 reg_offset = 0;

	u32 intr_status;
	u32 fifo_stat_reg_val;
	u32 dpll_reg_val;
	u32 dspcntr_reg_val;
	u32 pipeconf_reg_val;

	/*if mode setting on-going, back off*/
	if((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
		(psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING) ||
		!(dbi_output->mode_flags & MODE_SETTING_ENCODER_DONE))
		return;

	/*
	 * Look for errors here.  In particular we're checking for whatever
 	 * error status might have appeared during the last frame transmit
 	 * (memory write).
 	 *
 	 * Normally, the bits we're testing here would be set infrequently,
 	 * if at all.  However, the Pyrenees panel (at least) returns
 	 * at least one error bit on most frames.  So we've disabled the
 	 * kernel message for now.
 	 *
 	 * Still clear whatever error bits are set, except don't clear the
 	 * ones that would make the Penwell DSI controller reset if we
 	 * cleared them.
 	 */
	intr_status = REG_READ(INTR_STAT_REG);
	if ((intr_status & 0x26FFFFFF) != 0) {
		/* DRM_ERROR("DSI status: 0x%08X\n", intr_status); */
		intr_status &= 0x26F3FFFF;
	        REG_WRITE(INTR_STAT_REG, intr_status);
	}
		
	if(pipe == 2) {
		dspcntr_reg = DSPCCNTR;
		pipeconf_reg = PIPECCONF;
		dsplinoff_reg = DSPCLINOFF;
		dspsurf_reg = DSPCSURF;

		hs_gen_ctrl_reg = HS_GEN_CTRL_REG + MIPIC_REG_OFFSET;
		gen_fifo_stat_reg = GEN_FIFO_STAT_REG + MIPIC_REG_OFFSET,

		reg_offset = MIPIC_REG_OFFSET;
	}

	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, OSPM_UHB_FORCE_POWER_ON)) {
		DRM_ERROR("hw begin failed\n");
		return;
	}

	fifo_stat_reg_val = REG_READ(MIPIA_GEN_FIFO_STAT_REG + reg_offset);
	dpll_reg_val = REG_READ(dpll_reg);
	dspcntr_reg_val = REG_READ(dspcntr_reg);
	pipeconf_reg_val = REG_READ(pipeconf_reg);

	if(!(fifo_stat_reg_val & BIT27) ||
	   !(dpll_reg_val & DPLL_VCO_ENABLE) ||
	   !(dspcntr_reg_val & DISPLAY_PLANE_ENABLE) ||
	   !(pipeconf_reg_val & DISPLAY_PLANE_ENABLE)) {
		goto update_fb_out0;
	}
	
	/*refresh plane changes*/
	REG_WRITE(dsplinoff_reg, REG_READ(dsplinoff_reg));
	REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg));
	REG_READ(dspsurf_reg);

	mdfld_dsi_send_dcs(sender,
			   write_mem_start,
			   NULL,
			   0,
			   CMD_DATA_SRC_PIPE,
			   MDFLD_DSI_SEND_PACKAGE);

	/*
	* The idea here is to transmit a Generic Read command after the
	* Write Memory Start/Continue commands finish.  This asks for
	* the panel to return an "ACK No Errors," or (if it has errors
	* to report) an Error Report.  This allows us to monitor the
	* panel's perception of the health of the DSI.
	*/

	mdfld_dsi_gen_fifo_ready (dev, gen_fifo_stat_reg, HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
	REG_WRITE(hs_gen_ctrl_reg, (1 << WORD_COUNTS_POS) | GEN_READ_0);

	dbi_output->dsr_fb_update_done = true;
update_fb_out0:
	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
}
예제 #18
0
static void mdfld_dbi_output_exit_dsr(struct mdfld_dsi_dbi_output *dbi_output,
			int pipe)
{
	struct drm_device *dev = dbi_output->dev;
	struct drm_crtc *crtc = dbi_output->base.base.crtc;
	struct psb_intel_crtc *psb_crtc = (crtc) ?
					to_psb_intel_crtc(crtc) : NULL;
	u32 reg_val;
	u32 dpll_reg = MRST_DPLL_A;
	u32 pipeconf_reg = PIPEACONF;
	u32 dspcntr_reg = DSPACNTR;
	u32 reg_offset = 0;

	/*if mode setting on-going, back off*/
	if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
		(psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING))
		return;

	if (pipe == 2) {
		dpll_reg = MRST_DPLL_A;
		pipeconf_reg = PIPECCONF;
		dspcntr_reg = DSPCCNTR;
		reg_offset = MIPIC_REG_OFFSET;
	}

	if (!gma_power_begin(dev, true)) {
		dev_err(dev->dev, "hw begin failed\n");
		return;
	}

	/* Enable DPLL */
	reg_val = REG_READ(dpll_reg);
	if (!(reg_val & DPLL_VCO_ENABLE)) {
		if (reg_val & MDFLD_PWR_GATE_EN) {
			reg_val &= ~MDFLD_PWR_GATE_EN;
			REG_WRITE(dpll_reg, reg_val);
			REG_READ(dpll_reg);
			udelay(500);
		}

		reg_val |= DPLL_VCO_ENABLE;
		REG_WRITE(dpll_reg, reg_val);
		REG_READ(dpll_reg);
		udelay(500);

		/* Add timeout */
		while (!(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK))
			cpu_relax();
	}

	/* Enable pipe */
	reg_val = REG_READ(pipeconf_reg);
	if (!(reg_val & PIPEACONF_ENABLE)) {
		reg_val |= PIPEACONF_ENABLE;
		REG_WRITE(pipeconf_reg, reg_val);
		REG_READ(pipeconf_reg);
		udelay(500);
		mdfldWaitForPipeEnable(dev, pipe);
	}

	/* Enable plane */
	reg_val = REG_READ(dspcntr_reg);
	if (!(reg_val & DISPLAY_PLANE_ENABLE)) {
		reg_val |= DISPLAY_PLANE_ENABLE;
		REG_WRITE(dspcntr_reg, reg_val);
		REG_READ(dspcntr_reg);
		udelay(500);
	}

	/* Enable TE interrupt on this pipe */
	mdfld_enable_te(dev, pipe);
	gma_power_end(dev);

	/*clean IN_DSR flag*/
	dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR;
}