static void intel_dsi_disable(struct intel_encoder *encoder) { #ifndef BYT_DUAL_MIPI_DSI struct drm_encoder *drm_encoder = &encoder->base; struct drm_device *dev = encoder->base.dev; #endif //struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; //struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); DRM_DEBUG_KMS("\n"); //XXX dual display use mipi backlight for debug only #ifndef BYT_DUAL_MIPI_DSI intel_panel_disable_backlight(dev); #endif if (intel_dsi->backlight_off_delay >= 20) msleep(intel_dsi->backlight_off_delay); else usleep_range(intel_dsi->backlight_off_delay * 1000, (intel_dsi->backlight_off_delay * 1000) + 500); if (is_cmd_mode(intel_dsi)) { /* XXX Impementation TBD */ } else { /* Send Shutdown command to the panel in LP mode */ intel_dsi->hs = 1; dpi_send_cmd(intel_dsi, SHUTDOWN); usleep_range(1000, 1500); } }
u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, struct intel_crtc_state *config) { u32 pclk; u32 dsi_clk; u32 dsi_ratio; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); /* Divide by zero */ if (!pipe_bpp) { DRM_ERROR("Invalid BPP(0)\n"); return 0; } config->dsi_pll.ctrl = I915_READ(BXT_DSI_PLL_CTL); dsi_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK; dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2; /* pixel_format and pipe_bpp should agree */ assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp); pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, pipe_bpp); DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk); return pclk; }
static void intel_dsi_pre_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; DRM_DEBUG_KMS("\n"); intel_enable_dsi_pll(intel_dsi); if (is_cmd_mode(intel_dsi)) { /* XXX: Implement me */ I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); } else { intel_dsi->hs = 0; dpi_send_cmd(intel_dsi, TURN_ON); usleep_range(1000, 1500); if (intel_dsi->dev.dev_ops->enable) intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); intel_dsi_port_enable(encoder); } }
static void intel_dsi_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 temp; DRM_DEBUG_KMS("\n"); if (is_cmd_mode(intel_dsi)) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); else { msleep(20); /* XXX */ dpi_send_cmd(intel_dsi, TURN_ON); msleep(100); /* assert ip_tg_enable signal */ temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK; temp = temp | intel_dsi->port_bits; I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } if (intel_dsi->dev.dev_ops->enable) intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); }
static void dsi_config(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); int pipe = intel_crtc->pipe; u32 tmp; DRM_DEBUG_KMS("\n"); /* 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_EN(pipe), 0xffffffff); /* why here, was elsewhere... also 2a, 0c, 60, 08 for values */ I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg); }
static void intel_dsi_disable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 temp; DRM_DEBUG_KMS("\n"); if (is_vid_mode(intel_dsi)) { dpi_send_cmd(intel_dsi, SHUTDOWN); msleep(10); /* de-assert ip_tg_enable signal */ temp = I915_READ(MIPI_PORT_CTRL(pipe)); I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); msleep(2); } /* if disable packets are sent before sending shutdown packet then in * some next enable sequence send turn on packet error is observed */ if (intel_dsi->dev.dev_ops->disable) intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); }
static void bxt_enable_dsi_pll(struct intel_encoder *encoder, const struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; u32 val; DRM_DEBUG_KMS("\n"); /* Configure PLL vales */ I915_WRITE(BXT_DSI_PLL_CTL, config->dsi_pll.ctrl); POSTING_READ(BXT_DSI_PLL_CTL); /* Program TX, RX, Dphy clocks */ for_each_dsi_port(port, intel_dsi->ports) bxt_dsi_program_clocks(encoder->base.dev, port, config); /* Enable DSI PLL */ val = I915_READ(BXT_DSI_PLL_ENABLE); val |= BXT_DSI_PLL_DO_ENABLE; I915_WRITE(BXT_DSI_PLL_ENABLE, val); /* Timeout and fail if PLL not locked */ if (intel_wait_for_register(dev_priv, BXT_DSI_PLL_ENABLE, BXT_DSI_PLL_LOCKED, BXT_DSI_PLL_LOCKED, 1)) { DRM_ERROR("Timed out waiting for DSI PLL to lock\n"); return; } DRM_DEBUG_KMS("DSI PLL locked\n"); }
static void intel_dsi_disable(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 temp; DRM_DEBUG_KMS("\n"); intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); if (is_vid_mode(intel_dsi)) { dpi_send_cmd(intel_dsi, SHUTDOWN); msleep(10); /* de-assert ip_tg_enable signal */ temp = I915_READ(MIPI_PORT_CTRL(pipe)); I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); msleep(2); } temp = I915_READ(MIPI_DEVICE_READY(pipe)); if (temp & DEVICE_READY) { temp &= ~DEVICE_READY; temp &= ~ULPS_STATE_MASK; I915_WRITE(MIPI_DEVICE_READY(pipe), temp); } }
/* * XXX: The muxing and gating is hard coded for now. Need to add support for * sharing PLLs with two DSI outputs. */ int vlv_dsi_pll_compute(struct intel_encoder *encoder, struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int ret; u32 dsi_clk; dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, intel_dsi->lane_count); ret = dsi_calc_mnp(dev_priv, config, dsi_clk); if (ret) { DRM_DEBUG_KMS("dsi_calc_mnp failed\n"); return ret; } if (intel_dsi->ports & (1 << PORT_A)) config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; if (intel_dsi->ports & (1 << PORT_C)) config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL; config->dsi_pll.ctrl |= DSI_PLL_VCO_EN; DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n", config->dsi_pll.div, config->dsi_pll.ctrl); return 0; }
void intel_dsi_port_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 val, port_control = 0; if (intel_dsi->dual_link) { port_control = (intel_dsi->dual_link - 1) << DUAL_LINK_MODE_SHIFT; if (pipe == PIPE_A) port_control |= LANE_CONFIGURATION_DUAL_LINK_A; else port_control |= LANE_CONFIGURATION_DUAL_LINK_B; /*Pixel overlap count; only for VLV CO stepping */ if (IS_VALLEYVIEW_C0(dev) && (intel_dsi->dual_link & MIPI_DUAL_LINK_FRONT_BACK)) { val = I915_READ(VLV_CHICKEN_3); val &= ~PIXEL_OVERLAP_CNT_MASK | intel_dsi->pixel_overlap << PIXEL_OVERLAP_CNT_SHIFT; I915_WRITE(VLV_CHICKEN_3, val); } /* Port A */ val = I915_READ(MIPI_PORT_CTRL(0)); val = val | port_control; I915_WRITE(MIPI_PORT_CTRL(0), val | DPI_ENABLE); if (!IS_VALLEYVIEW_C0(dev)) { /* for stepping before C0; we need to enable * PORTC explicitly. From C0 onwards enable PORT A * also enabled PORT C for dual link */ val = I915_READ(MIPI_PORT_CTRL(1)); I915_WRITE(MIPI_PORT_CTRL(1), val | DPI_ENABLE); } else { if (intel_crtc->config.dither) { val = I915_READ(MIPI_PORT_CTRL(0)); val = val | DITHERING_ENABLE; I915_WRITE(MIPI_PORT_CTRL(0), val); val = I915_READ(MIPI_PORT_CTRL(1)); val = val | DITHERING_ENABLE; I915_WRITE(MIPI_PORT_CTRL(1), val); } } usleep_range(2000, 2500); } else { val = I915_READ(MIPI_PORT_CTRL(pipe)); val = val | port_control; if (intel_crtc->config.dither && IS_VALLEYVIEW_C0(dev)) val |= DITHERING_ENABLE; I915_WRITE(MIPI_PORT_CTRL(pipe), val | DPI_ENABLE); usleep_range(2000, 2500); } }
static void set_dsi_timings(struct drm_encoder *encoder, const struct drm_display_mode *mode) { 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; unsigned int lane_count = intel_dsi->lane_count; u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp; hactive = mode->hdisplay; hfp = mode->hsync_start - mode->hdisplay; hsync = mode->hsync_end - mode->hsync_start; hbp = mode->htotal - mode->hsync_end; vfp = mode->vsync_start - mode->vdisplay; vsync = mode->vsync_end - mode->vsync_start; vbp = mode->vtotal - mode->vsync_end; /* horizontal values are in terms of high speed byte clock */ hactive = txbyteclkhs(hactive, bpp, lane_count); hfp = txbyteclkhs(hfp, bpp, lane_count); hsync = txbyteclkhs(hsync, bpp, lane_count); hbp = txbyteclkhs(hbp, bpp, lane_count); /* FIXME: Find better way to do this */ /* For 7x10 panel we need to have BLLP added to active */ /* Trying to find optimal BLLP Multiplier */ /* 2.875 - Original multiplier, Works with flicker */ /* 2.000 - works but still some flicker */ /* 1.500 - Works, No Flicker */ /* 1.250 - Works, No Flicker */ /* 1.100 - Doesn't work */ /* FIXME: Acer Mango spec requires to run the DSI clock at 500 to * 560Mbps. Recomendation is to run at 513 Mbps. The addition dsi * clock is to be filled with NULL packets. Refer to acer panel * spec for more details. */ if (dev_priv->mipi_panel_id == MIPI_DSI_AUO_B080XAT_PANEL_ID) hactive = (hactive * 10) / 8; I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); I915_WRITE(MIPI_HFP_COUNT(pipe), hfp); /* meaningful for video mode non-burst sync pulse mode only, can be zero * for non-burst sync events and burst modes */ I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync); I915_WRITE(MIPI_HBP_COUNT(pipe), hbp); /* vertical values are in terms of lines */ I915_WRITE(MIPI_VFP_COUNT(pipe), vfp); I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync); I915_WRITE(MIPI_VBP_COUNT(pipe), vbp); }
void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 val; DRM_DEBUG_KMS("\n"); I915_WRITE_BITS(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER | DEVICE_READY, ULPS_STATE_MASK | DEVICE_READY); usleep_range(2000, 2500); I915_WRITE_BITS(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT | DEVICE_READY, ULPS_STATE_MASK | DEVICE_READY); usleep_range(2000, 2500); I915_WRITE_BITS(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER | DEVICE_READY, ULPS_STATE_MASK | DEVICE_READY); usleep_range(2000, 2500); if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & 0x20000) == 0x00000), 30)) DRM_ERROR("DSI LP not going Low\n"); I915_WRITE_BITS(MIPI_PORT_CTRL(pipe), 0, LP_OUTPUT_HOLD); usleep_range(1000, 1500); I915_WRITE_BITS(MIPI_DEVICE_READY(pipe), 0x00, DEVICE_READY); usleep_range(2000, 2500); intel_disable_dsi_pll(intel_dsi); val = I915_READ(DSPCLK_GATE_D); val &= ~VSUNIT_CLOCK_GATE_DISABLE; I915_WRITE(DSPCLK_GATE_D, val); if (intel_dsi->dev.dev_ops->disable_panel_power) intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); #ifdef CONFIG_CRYSTAL_COVE if (BYT_CR_CONFIG) { /* Disable Panel */ vlv_gpio_nc_write(dev_priv, GPIO_NC_11_PCONF0, 0x2000CC00); vlv_gpio_nc_write(dev_priv, GPIO_NC_11_PAD, 0x00000004); udelay(500); } else intel_mid_pmic_writeb(PMIC_PANEL_EN, 0x00); #else /* need to code for BYT-CR for example where things have changed */ DRM_ERROR("PANEL Disable to supported yet\n"); #endif msleep(intel_dsi->panel_off_delay); msleep(intel_dsi->panel_pwr_cycle_delay); }
static void intel_dsi_post_disable(struct intel_encoder *encoder) { struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); DRM_DEBUG_KMS("\n"); intel_dsi_clear_device_ready(encoder); if (intel_dsi->dev.dev_ops->disable_panel_power) intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); }
void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) { u32 temp; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); temp = I915_READ(MIPI_CTRL(port)); temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; I915_WRITE(MIPI_CTRL(port), temp | intel_dsi->escape_clk_div << ESCAPE_CLOCK_DIVIDER_SHIFT); }
static void intel_dsi_pre_disable(struct intel_encoder *encoder) { struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); DRM_DEBUG_KMS("\n"); if (is_vid_mode(intel_dsi)) { /* Send Shutdown command to the panel in LP mode */ dpi_send_cmd(intel_dsi, SHUTDOWN, DPI_LP_MODE_EN); msleep(10); } }
static void intel_dsi_post_disable(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 tmp; int count = 1; wait_for_dsi_fifo_empty(intel_dsi); intel_dsi_port_disable(encoder); /* Panel commands can be sent when clock is in LP11 */ if (intel_dsi->dual_link) count = 2; do { tmp = I915_READ(MIPI_DEVICE_READY(pipe)); tmp &= ~DEVICE_READY; I915_WRITE(MIPI_DEVICE_READY(pipe), tmp); tmp = I915_READ(MIPI_CTRL(pipe)); tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK; I915_WRITE(MIPI_CTRL(pipe), tmp | intel_dsi->escape_clk_div << ESCAPE_CLOCK_DIVIDER_SHIFT); tmp = I915_READ(MIPI_DSI_FUNC_PRG(pipe)); tmp &= ~VID_MODE_FORMAT_MASK; I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), tmp); I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP); tmp = I915_READ(MIPI_DSI_FUNC_PRG(pipe)); tmp &= ~VID_MODE_FORMAT_MASK; I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), tmp); tmp = I915_READ(MIPI_DEVICE_READY(pipe)); tmp &= DEVICE_READY; I915_WRITE(MIPI_DEVICE_READY(pipe), tmp); pipe = PIPE_B; } while (--count > 0); /* if disable packets are sent before sending shutdown packet then in * some next enable sequence send turn on packet error is observed */ if (intel_dsi->dev.dev_ops->disable) intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); wait_for_dsi_fifo_empty(intel_dsi); intel_dsi_clear_device_ready(encoder); }
static void intel_dsi_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; /* Adjust backlight timing for specific panel */ if (intel_dsi->backlight_on_delay >= 20) msleep(intel_dsi->backlight_on_delay); else usleep_range(intel_dsi->backlight_on_delay * 1000, (intel_dsi->backlight_on_delay * 1000) + 500); intel_panel_enable_backlight(dev, pipe); }
static void intel_dsi_pre_enable(struct intel_encoder *encoder) { struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); DRM_DEBUG_KMS("\n"); if (intel_dsi->dev.dev_ops->panel_reset) intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); /* put device in ready state */ intel_dsi_device_ready(encoder); if (intel_dsi->dev.dev_ops->send_otp_cmds) intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); }
int bxt_dsi_pll_compute(struct intel_encoder *encoder, struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); u8 dsi_ratio, dsi_ratio_min, dsi_ratio_max; u32 dsi_clk; dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, intel_dsi->lane_count); /* * From clock diagram, to get PLL ratio divider, divide double of DSI * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to * round 'up' the result */ dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ); if (IS_BROXTON(dev_priv)) { dsi_ratio_min = BXT_DSI_PLL_RATIO_MIN; dsi_ratio_max = BXT_DSI_PLL_RATIO_MAX; } else { dsi_ratio_min = GLK_DSI_PLL_RATIO_MIN; dsi_ratio_max = GLK_DSI_PLL_RATIO_MAX; } if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) { DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n"); return -ECHRNG; } else DRM_DEBUG_KMS("DSI PLL calculation is Done!!\n"); /* * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x * Spec says both have to be programmed, even if one is not getting * used. Configure MIPI_CLOCK_CTL dividers in modeset */ config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2; /* As per recommendation from hardware team, * Prog PVD ratio =1 if dsi ratio <= 50 */ if (IS_BROXTON(dev_priv) && dsi_ratio <= 50) config->dsi_pll.ctrl |= BXT_DSI_PLL_PVD_RATIO_1; return 0; }
static void intel_dsi_disable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 temp; DRM_DEBUG_KMS("\n"); if (is_vid_mode(intel_dsi)) { wait_for_dsi_fifo_empty(intel_dsi); /* de-assert ip_tg_enable signal */ temp = I915_READ(MIPI_PORT_CTRL(pipe)); I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); msleep(2); } /* Panel commands can be sent when clock is in LP11 */ I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0); temp = I915_READ(MIPI_CTRL(pipe)); temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; I915_WRITE(MIPI_CTRL(pipe), temp | intel_dsi->escape_clk_div << ESCAPE_CLOCK_DIVIDER_SHIFT); I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP); temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe)); temp &= ~VID_MODE_FORMAT_MASK; I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp); I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1); /* if disable packets are sent before sending shutdown packet then in * some next enable sequence send turn on packet error is observed */ if (intel_dsi->dev.dev_ops->disable) intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); wait_for_dsi_fifo_empty(intel_dsi); }
static void set_dsi_timings(struct drm_encoder *encoder, const struct drm_display_mode *mode) { 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; unsigned int lane_count = intel_dsi->lane_count; u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp; hactive = mode->hdisplay; hfp = mode->hsync_start - mode->hdisplay; hsync = mode->hsync_end - mode->hsync_start; hbp = mode->htotal - mode->hsync_end; vfp = mode->vsync_start - mode->vdisplay; vsync = mode->vsync_end - mode->vsync_start; vbp = mode->vtotal - mode->vsync_end; /* horizontal values are in terms of high speed byte clock */ hactive = txbyteclkhs(hactive, bpp, lane_count, intel_dsi->burst_mode_ratio); hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio); hsync = txbyteclkhs(hsync, bpp, lane_count, intel_dsi->burst_mode_ratio); hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); I915_WRITE(MIPI_HFP_COUNT(pipe), hfp); /* meaningful for video mode non-burst sync pulse mode only, can be zero * for non-burst sync events and burst modes */ I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync); I915_WRITE(MIPI_HBP_COUNT(pipe), hbp); /* vertical values are in terms of lines */ I915_WRITE(MIPI_VFP_COUNT(pipe), vfp); I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync); I915_WRITE(MIPI_VBP_COUNT(pipe), vbp); }
static void intel_dsi_pre_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); enum pipe pipe = intel_crtc->pipe; u32 tmp; DRM_DEBUG_KMS("\n"); /* Disable DPOunit clock gating, can stall pipe * and we need DPLL REFA always enabled */ tmp = I915_READ(DPLL(pipe)); tmp |= DPLL_REFA_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), tmp); /* update the hw state for DPLL */ intel_crtc->config.dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV | DPLL_REFA_CLK_ENABLE_VLV; tmp = I915_READ(DSPCLK_GATE_D); tmp |= DPOUNIT_CLOCK_GATE_DISABLE; I915_WRITE(DSPCLK_GATE_D, tmp); /* put device in ready state */ intel_dsi_device_ready(encoder); msleep(intel_dsi->panel_on_delay); if (intel_dsi->dev.dev_ops->panel_reset) intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); if (intel_dsi->dev.dev_ops->send_otp_cmds) intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); wait_for_dsi_fifo_empty(intel_dsi); /* Enable port in pre-enable phase itself because as per hw team * recommendation, port should be enabled befor plane & pipe */ intel_dsi_enable(encoder); }
static void intel_dsi_enable(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; u32 temp; DRM_DEBUG_KMS("\n"); temp = I915_READ(MIPI_DEVICE_READY(pipe)); if ((temp & DEVICE_READY) == 0) { temp &= ~ULPS_STATE_MASK; I915_WRITE(MIPI_DEVICE_READY(pipe), temp | DEVICE_READY); } else if (temp & ULPS_STATE_MASK) { temp &= ~ULPS_STATE_MASK; I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_EXIT); /* * We need to ensure that there is a minimum of 1 ms time * available before clearing the UPLS exit state. */ msleep(2); I915_WRITE(MIPI_DEVICE_READY(pipe), temp); } if (is_cmd_mode(intel_dsi)) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); if (is_vid_mode(intel_dsi)) { msleep(20); /* XXX */ dpi_send_cmd(intel_dsi, TURN_ON); msleep(100); /* assert ip_tg_enable signal */ temp = I915_READ(MIPI_PORT_CTRL(pipe)); I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); }
void intel_dsi_port_disable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; if (intel_dsi->dual_link) { I915_WRITE_BITS(MIPI_PORT_CTRL(0), 0, DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(0)); I915_WRITE_BITS(MIPI_PORT_CTRL(1), 0, DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(1)); } else { I915_WRITE_BITS(MIPI_PORT_CTRL(pipe), 0, DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } usleep_range(2000, 2500); }
static void intel_dsi_post_disable(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); u32 val; DRM_DEBUG_KMS("\n"); intel_dsi_disable(encoder); intel_dsi_clear_device_ready(encoder); val = I915_READ(DSPCLK_GATE_D); val &= ~DPOUNIT_CLOCK_GATE_DISABLE; I915_WRITE(DSPCLK_GATE_D, val); if (intel_dsi->dev.dev_ops->disable_panel_power) intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); msleep(intel_dsi->panel_off_delay); msleep(intel_dsi->panel_pwr_cycle_delay); }
static void intel_dsi_pre_enable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; bool is_dsi; u32 temp; DRM_DEBUG_KMS("\n"); is_dsi = intel_pipe_has_type(encoder->base.crtc, INTEL_OUTPUT_DSI); intel_enable_dsi_pll(intel_dsi); printk("====>DLP3430 debug 2.20.\n"); if (is_cmd_mode(intel_dsi)) { /* XXX: Implement me */ I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); } else { intel_dsi->hs = 1; dpi_send_cmd(intel_dsi, TURN_ON); usleep_range(1000, 1500); if (intel_dsi->dev.dev_ops->enable) intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); temp = I915_READ(MIPI_PORT_CTRL(pipe)); temp = temp | intel_dsi->port_bits; if (is_dsi && intel_crtc->config.dither) temp |= DITHERING_ENABLE; I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); usleep_range(2000, 2500); } }
static int bxt_compute_dsi_pll(struct intel_encoder *encoder, struct intel_crtc_state *config) { struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); u8 dsi_ratio; u32 dsi_clk; dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, intel_dsi->lane_count); /* * From clock diagram, to get PLL ratio divider, divide double of DSI * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to * round 'up' the result */ dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ); if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN || dsi_ratio > BXT_DSI_PLL_RATIO_MAX) { DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n"); return -ECHRNG; } /* * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x * Spec says both have to be programmed, even if one is not getting * used. Configure MIPI_CLOCK_CTL dividers in modeset */ config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2; /* As per recommendation from hardware team, * Prog PVD ratio =1 if dsi ratio <= 50 */ if (dsi_ratio <= 50) config->dsi_pll.ctrl |= BXT_DSI_PLL_PVD_RATIO_1; return 0; }
static void intel_dsi_disable(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); DRM_DEBUG_KMS("\n"); intel_panel_disable_backlight(dev); if (intel_dsi->backlight_off_delay >= 20) msleep(intel_dsi->backlight_off_delay); else usleep_range(intel_dsi->backlight_off_delay * 1000, (intel_dsi->backlight_off_delay * 1000) + 500); if (is_cmd_mode(intel_dsi)) { /* XXX Impementation TBD */ } else { /* Send Shutdown command to the panel in LP mode */ intel_dsi->hs = 0; dpi_send_cmd(intel_dsi, SHUTDOWN); usleep_range(1000, 1500); } }
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); }
u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); u32 dsi_clock, pclk; u32 pll_ctl, pll_div; u32 m = 0, p = 0, n; int refclk = IS_CHERRYVIEW(dev_priv) ? 100000 : 25000; int i; DRM_DEBUG_KMS("\n"); mutex_lock(&dev_priv->sb_lock); pll_ctl = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL); pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER); mutex_unlock(&dev_priv->sb_lock); config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK; config->dsi_pll.div = pll_div; /* mask out other bits and extract the P1 divisor */ pll_ctl &= DSI_PLL_P1_POST_DIV_MASK; pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2); /* N1 divisor */ n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT; n = 1 << n; /* register has log2(N1) */ /* mask out the other bits and extract the M1 divisor */ pll_div &= DSI_PLL_M1_DIV_MASK; pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT; while (pll_ctl) { pll_ctl = pll_ctl >> 1; p++; } p--; if (!p) { DRM_ERROR("wrong P1 divisor\n"); return 0; } for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) { if (lfsr_converts[i] == pll_div) break; } if (i == ARRAY_SIZE(lfsr_converts)) { DRM_ERROR("wrong m_seed programmed\n"); return 0; } m = i + 62; dsi_clock = (m * refclk) / (p * n); /* pixel_format and pipe_bpp should agree */ assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp); pclk = DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, pipe_bpp); return pclk; }