int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
		    u8 *buf, int buflen)
{
	struct drm_encoder *encoder = &intel_dsi->base.base;
	struct drm_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
	enum pipe pipe = intel_crtc->pipe;
	u32 mask;
	int ret;

	/*
	 * XXX: should issue multiple read requests and reads if request is
	 * longer than MIPI_MAX_RETURN_PKT_SIZE
	 */

	I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL);

	ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd);
	if (ret)
		return ret;

	mask = GEN_READ_DATA_AVAIL;
	if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50))
		DRM_ERROR("Timeout waiting for read data.\n");

	ret = dsi_read_data_return(intel_dsi, buf, buflen);
	if (ret < 0)
		return ret;

	if (ret != buflen)
		return -EIO;

	return 0;
}
示例#2
0
/*
 * send a video mode command
 *
 * XXX: commands with data in MIPI_DPI_DATA?
 */
int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs)
{
	struct drm_encoder *encoder = &intel_dsi->base.base;
	struct drm_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
	enum pipe pipe = intel_crtc->pipe;
	u32 mask;

	/* XXX: pipe, hs */
	if (hs)
		cmd &= ~DPI_LP_MODE;
	else
		cmd |= DPI_LP_MODE;

	/* clear bit */
	I915_WRITE(MIPI_INTR_STAT(pipe), SPL_PKT_SENT_INTERRUPT);

	/* XXX: old code skips write if control unchanged */
	if (cmd == I915_READ(MIPI_DPI_CONTROL(pipe)))
		DRM_ERROR("Same special packet %02x twice in a row.\n", cmd);

	I915_WRITE(MIPI_DPI_CONTROL(pipe), cmd);

	mask = SPL_PKT_SENT_INTERRUPT;
	if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 100))
		DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);

	return 0;
}
static void print_stat(struct intel_dsi *intel_dsi)
{
	struct drm_encoder *encoder = &intel_dsi->base.base;
	struct drm_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
	enum pipe pipe = intel_crtc->pipe;
	u32 val;

	val = I915_READ(MIPI_INTR_STAT(pipe));

#define STAT_BIT(val, bit) (val) & (bit) ? " " #bit : ""
	DRM_DEBUG_KMS("MIPI_INTR_STAT(%d) = %08x"
		      "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
		      "\n", pipe, val,
		      STAT_BIT(val, TEARING_EFFECT),
		      STAT_BIT(val, SPL_PKT_SENT_INTERRUPT),
		      STAT_BIT(val, GEN_READ_DATA_AVAIL),
		      STAT_BIT(val, LP_GENERIC_WR_FIFO_FULL),
		      STAT_BIT(val, HS_GENERIC_WR_FIFO_FULL),
		      STAT_BIT(val, RX_PROT_VIOLATION),
		      STAT_BIT(val, RX_INVALID_TX_LENGTH),
		      STAT_BIT(val, ACK_WITH_NO_ERROR),
		      STAT_BIT(val, TURN_AROUND_ACK_TIMEOUT),
		      STAT_BIT(val, LP_RX_TIMEOUT),
		      STAT_BIT(val, HS_TX_TIMEOUT),
		      STAT_BIT(val, DPI_FIFO_UNDERRUN),
		      STAT_BIT(val, LOW_CONTENTION),
		      STAT_BIT(val, HIGH_CONTENTION),
		      STAT_BIT(val, TXDSI_VC_ID_INVALID),
		      STAT_BIT(val, TXDSI_DATA_TYPE_NOT_RECOGNISED),
		      STAT_BIT(val, TXCHECKSUM_ERROR),
		      STAT_BIT(val, TXECC_MULTIBIT_ERROR),
		      STAT_BIT(val, TXECC_SINGLE_BIT_ERROR),
		      STAT_BIT(val, TXFALSE_CONTROL_ERROR),
		      STAT_BIT(val, RXDSI_VC_ID_INVALID),
		      STAT_BIT(val, RXDSI_DATA_TYPE_NOT_REGOGNISED),
		      STAT_BIT(val, RXCHECKSUM_ERROR),
		      STAT_BIT(val, RXECC_MULTIBIT_ERROR),
		      STAT_BIT(val, RXECC_SINGLE_BIT_ERROR),
		      STAT_BIT(val, RXFALSE_CONTROL_ERROR),
		      STAT_BIT(val, RXHS_RECEIVE_TIMEOUT_ERROR),
		      STAT_BIT(val, RX_LP_TX_SYNC_ERROR),
		      STAT_BIT(val, RXEXCAPE_MODE_ENTRY_ERROR),
		      STAT_BIT(val, RXEOT_SYNC_ERROR),
		      STAT_BIT(val, RXSOT_SYNC_ERROR),
		      STAT_BIT(val, RXSOT_ERROR));
#undef STAT_BIT
}
示例#4
0
static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
{
	struct drm_encoder *encoder = &intel_encoder->base;
	struct drm_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
	struct drm_display_mode *adjusted_mode =
		&intel_crtc->config.adjusted_mode;
	int pipe = intel_crtc->pipe;
	unsigned int bpp = intel_crtc->config.pipe_bpp;
	u32 val, tmp;

	DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));

	/* XXX: Location of the call */
	band_gap_reset(dev_priv);

	/* escape clock divider, 20MHz, shared for A and C. device ready must be
	 * off when doing this! txclkesc? */
	tmp = I915_READ(MIPI_CTRL(0));
	tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
	I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1);

	/* read request priority is per pipe */
	tmp = I915_READ(MIPI_CTRL(pipe));
	tmp &= ~READ_REQUEST_PRIORITY_MASK;
	I915_WRITE(MIPI_CTRL(pipe), tmp | READ_REQUEST_PRIORITY_HIGH);

	/* XXX: why here, why like this? handling in irq handler?! */
	I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff);
	I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff);

	I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg);

	I915_WRITE(MIPI_DPI_RESOLUTION(pipe),
		   adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
		   adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT);

	set_dsi_timings(encoder, adjusted_mode);

	val = intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT;
	if (is_cmd_mode(intel_dsi)) {
		val |= intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT;
		val |= CMD_MODE_DATA_WIDTH_8_BIT; /* XXX */
	} else {
		val |= intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT;

		/* XXX: cross-check bpp vs. pixel format? */
		val |= intel_dsi->pixel_format;
	}
	I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);

	/* timeouts for recovery. one frame IIUC. if counter expires, EOT and
	 * stop state. */

	/*
	 * In burst mode, value greater than one DPI line Time in byte clock
	 * (txbyteclkhs) To timeout this timer 1+ of the above said value is
	 * recommended.
	 *
	 * In non-burst mode, Value greater than one DPI frame time in byte
	 * clock(txbyteclkhs) To timeout this timer 1+ of the above said value
	 * is recommended.
	 *
	 * In DBI only mode, value greater than one DBI frame time in byte
	 * clock(txbyteclkhs) To timeout this timer 1+ of the above said value
	 * is recommended.
	 */

	if (is_vid_mode(intel_dsi) &&
	    intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
		I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
			   txbyteclkhs(adjusted_mode->htotal, bpp,
				       intel_dsi->lane_count) + 1);
	} else {
		I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
			   txbyteclkhs(adjusted_mode->vtotal *
				       adjusted_mode->htotal,
				       bpp, intel_dsi->lane_count) + 1);
	}
	I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
	I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val);
	I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val);

	/* dphy stuff */

	/* in terms of low power clock */
	I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(ESCAPE_CLOCK_DIVIDER_1, 100));

	/* recovery disables */
	I915_WRITE(MIPI_EOT_DISABLE(pipe), intel_dsi->eot_disable);

	/* in terms of txbyteclkhs. actual high to low switch +
	 * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
	 *
	 * XXX: write MIPI_STOP_STATE_STALL?
	 */
	I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe),
						intel_dsi->hs_to_lp_count);

	/* XXX: low power clock equivalence in terms of byte clock. the number
	 * of byte clocks occupied in one low power clock. based on txbyteclkhs
	 * and txclkesc. txclkesc time / txbyteclk time * (105 +
	 * MIPI_STOP_STATE_STALL) / 105.???
	 */
	I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk);

	/* the bw essential for transmitting 16 long packets containing 252
	 * bytes meant for dcs write memory command is programmed in this
	 * register in terms of byte clocks. based on dsi transfer rate and the
	 * number of lanes configured the time taken to transmit 16 long packets
	 * in a dsi stream varies. */
	I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer);

	I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe),
		   intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
		   intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);

	if (is_vid_mode(intel_dsi))
		I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
				intel_dsi->video_frmt_cfg_bits |
				intel_dsi->video_mode_format);
}
static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
{
	struct drm_encoder *encoder = &intel_encoder->base;
	struct drm_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
	int pipe = intel_crtc->pipe;
	unsigned int bpp = intel_crtc->config.pipe_bpp;
	struct drm_display_mode *adjusted_mode = &intel_crtc->config.adjusted_mode;
	u32 val;

	intel_dsi_device_ready(intel_encoder);

	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0);

	dsi_config(encoder);

	I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
	I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe),
					intel_dsi->turn_arnd_val);
	I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe),
					intel_dsi->rst_timer_val);
	/* in terms of low power clock */
	I915_WRITE(MIPI_INIT_COUNT(pipe), intel_dsi->init_count);

	I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), \
					intel_dsi->hs_to_lp_count);
	I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk);

	I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe),
		((u32)intel_dsi->clk_lp_to_hs_count
		<< LP_HS_SSW_CNT_SHIFT) |
		(intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT));

	if (is_vid_mode(intel_dsi)) {
		I915_WRITE(MIPI_DPI_RESOLUTION(pipe),
			(adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT) |
			(adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT));

		set_dsi_timings(encoder, adjusted_mode);

		if (intel_dsi->video_mode_type == DSI_VIDEO_BURST) {
			I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
				txbyteclkhs(adjusted_mode->htotal, bpp,
				intel_dsi->lane_count) + 1);
		}
		else {
			I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
			   txbyteclkhs(adjusted_mode->vtotal *
				   adjusted_mode->htotal,
				   bpp, intel_dsi->lane_count) + 1);
		}
	} else {
		val = intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT |
			intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT |
			intel_dsi->data_width;
		I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);

		I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
			txbyteclkhs(adjusted_mode->hdisplay *
			adjusted_mode->vdisplay,
			bpp, intel_dsi->lane_count) + 1);

		I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer);
	}

	I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP);

	val = I915_READ(MIPI_DSI_FUNC_PRG(pipe));
	val &= ~VID_MODE_FORMAT_MASK;
	I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);

	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1);

#if 0
//in dual display config, dsi 0 is not init. so this function may not
    //be called with pipe0. set this flag for pipe0 so that pipe b can work
    #ifdef BYT_DUAL_MIPI_DSI  
    if(pipe != 0)
    {

        I915_WRITE_BITS(MIPI_PORT_CTRL(0), LP_OUTPUT_HOLD,
                LP_OUTPUT_HOLD);

        usleep_range(1000, 1500);
    }
    #endif
#endif
    
	if (intel_dsi->dev.dev_ops->send_otp_cmds)
		intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev);

	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0);

	set_dsi_timings(encoder, adjusted_mode);

	/* Some panels might have resolution which is not a multiple of
	 * 64 like 1366 x 768. Enable RANDOM resolution support for such
	 * panels by default */
	I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
				intel_dsi->video_frmt_cfg_bits |
				intel_dsi->video_mode_type |
				IP_TG_CONFIG |
				RANDOM_DPI_DISPLAY_RESOLUTION);

	val = 0;
	if (intel_dsi->eotp_pkt == 0)
		val |= EOT_DISABLE;

	if (intel_dsi->clock_stop)
		val |= CLOCKSTOP;

	I915_WRITE(MIPI_EOT_DISABLE(pipe), val);

	val = intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT |
		intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT |
		intel_dsi->pixel_format;
	I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);

	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1);

	I915_WRITE(MIPI_INTR_STAT(pipe), 0xFFFFFFFF);
	/* Max packet return size limits the size of returning
	* packet so that host processor can prevent buffer overflow
	* condition when receiving data from peripheral. DCS read
	* need this to be set.*/
	I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 0xff);
}