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