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