static bool dpu_hw_setup_clk_force_ctrl(struct dpu_hw_mdp *mdp, enum dpu_clk_ctrl_type clk_ctrl, bool enable) { struct dpu_hw_blk_reg_map *c; u32 reg_off, bit_off; u32 reg_val, new_val; bool clk_forced_on; if (!mdp) return false; c = &mdp->hw; if (clk_ctrl <= DPU_CLK_CTRL_NONE || clk_ctrl >= DPU_CLK_CTRL_MAX) return false; reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off; bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off; reg_val = DPU_REG_READ(c, reg_off); if (enable) new_val = reg_val | BIT(bit_off); else new_val = reg_val & ~BIT(bit_off); DPU_REG_WRITE(c, reg_off, new_val); clk_forced_on = !(reg_val & BIT(bit_off)); return clk_forced_on; }
static void dpu_hw_intf_enable_timing_engine( struct dpu_hw_intf *intf, u8 enable) { struct dpu_hw_blk_reg_map *c = &intf->hw; /* Note: Display interface select is handled in top block hw layer */ DPU_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0); }
static void dpu_hw_intf_audio_select(struct dpu_hw_mdp *mdp) { struct dpu_hw_blk_reg_map *c; if (!mdp) return; c = &mdp->hw; DPU_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1); }
static void dpu_hw_intf_setup_prg_fetch( struct dpu_hw_intf *intf, const struct intf_prog_fetch *fetch) { struct dpu_hw_blk_reg_map *c = &intf->hw; int fetch_enable; /* * Fetch should always be outside the active lines. If the fetching * is programmed within active region, hardware behavior is unknown. */ fetch_enable = DPU_REG_READ(c, INTF_CONFIG); if (fetch->enable) { fetch_enable |= BIT(31); DPU_REG_WRITE(c, INTF_PROG_FETCH_START, fetch->fetch_start); } else { fetch_enable &= ~BIT(31); } DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable); }
static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, struct split_pipe_cfg *cfg) { struct dpu_hw_blk_reg_map *c; u32 upper_pipe = 0; u32 lower_pipe = 0; if (!mdp || !cfg) return; c = &mdp->hw; if (cfg->en) { if (cfg->mode == INTF_MODE_CMD) { lower_pipe = FLD_SPLIT_DISPLAY_CMD; /* interface controlling sw trigger */ if (cfg->intf == INTF_2) lower_pipe |= FLD_INTF_1_SW_TRG_MUX; else lower_pipe |= FLD_INTF_2_SW_TRG_MUX; upper_pipe = lower_pipe; } else { if (cfg->intf == INTF_2) { lower_pipe = FLD_INTF_1_SW_TRG_MUX; upper_pipe = FLD_INTF_2_SW_TRG_MUX; } else { lower_pipe = FLD_INTF_2_SW_TRG_MUX; upper_pipe = FLD_INTF_1_SW_TRG_MUX; } } } DPU_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0); DPU_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe); DPU_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe); DPU_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1); }
static void dpu_hw_reset_ubwc(struct dpu_hw_mdp *mdp, struct dpu_mdss_cfg *m) { struct dpu_hw_blk_reg_map c; if (!mdp || !m) return; if (!IS_UBWC_20_SUPPORTED(m->caps->ubwc_version)) return; /* force blk offset to zero to access beginning of register region */ c = mdp->hw; c.blk_off = 0x0; DPU_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static); }
static void dpu_hw_setup_cdm_output(struct dpu_hw_mdp *mdp, struct cdm_output_cfg *cfg) { struct dpu_hw_blk_reg_map *c; u32 out_ctl = 0; if (!mdp || !cfg) return; c = &mdp->hw; if (cfg->intf_en) out_ctl |= BIT(19); DPU_REG_WRITE(c, MDP_OUT_CTL_0, out_ctl); }
static void dpu_hw_setup_vsync_source(struct dpu_hw_mdp *mdp, struct dpu_vsync_source_cfg *cfg) { struct dpu_hw_blk_reg_map *c; u32 reg, wd_load_value, wd_ctl, wd_ctl2, i; static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18}; if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber))) return; c = &mdp->hw; reg = DPU_REG_READ(c, MDP_VSYNC_SEL); for (i = 0; i < cfg->pp_count; i++) { int pp_idx = cfg->ppnumber[i] - PINGPONG_0; if (pp_idx >= ARRAY_SIZE(pp_offset)) continue; reg &= ~(0xf << pp_offset[pp_idx]); reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx]; } DPU_REG_WRITE(c, MDP_VSYNC_SEL, reg); if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 && cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_0) { switch (cfg->vsync_source) { case DPU_VSYNC_SOURCE_WD_TIMER_4: wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_4_CTL; wd_ctl2 = MDP_WD_TIMER_4_CTL2; break; case DPU_VSYNC_SOURCE_WD_TIMER_3: wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_3_CTL; wd_ctl2 = MDP_WD_TIMER_3_CTL2; break; case DPU_VSYNC_SOURCE_WD_TIMER_2: wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_2_CTL; wd_ctl2 = MDP_WD_TIMER_2_CTL2; break; case DPU_VSYNC_SOURCE_WD_TIMER_1: wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_1_CTL; wd_ctl2 = MDP_WD_TIMER_1_CTL2; break; case DPU_VSYNC_SOURCE_WD_TIMER_0: default: wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE; wd_ctl = MDP_WD_TIMER_0_CTL; wd_ctl2 = MDP_WD_TIMER_0_CTL2; break; } DPU_REG_WRITE(c, wd_load_value, CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); DPU_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */ reg = DPU_REG_READ(c, wd_ctl2); reg |= BIT(8); /* enable heartbeat timer */ reg |= BIT(0); /* enable WD timer */ DPU_REG_WRITE(c, wd_ctl2, reg); /* make sure that timers are enabled/disabled for vsync state */ wmb(); } }
static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, const struct intf_timing_params *p, const struct dpu_format *fmt) { struct dpu_hw_blk_reg_map *c = &ctx->hw; u32 hsync_period, vsync_period; u32 display_v_start, display_v_end; u32 hsync_start_x, hsync_end_x; u32 active_h_start, active_h_end; u32 active_v_start, active_v_end; u32 active_hctl, display_hctl, hsync_ctl; u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity; u32 panel_format; u32 intf_cfg; /* read interface_cfg */ intf_cfg = DPU_REG_READ(c, INTF_CONFIG); hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + p->h_front_porch; vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + p->v_front_porch; display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * hsync_period) + p->hsync_skew; display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + p->hsync_skew - 1; if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP) { display_v_start += p->hsync_pulse_width + p->h_back_porch; display_v_end -= p->h_front_porch; } hsync_start_x = p->h_back_porch + p->hsync_pulse_width; hsync_end_x = hsync_period - p->h_front_porch - 1; if (p->width != p->xres) { active_h_start = hsync_start_x; active_h_end = active_h_start + p->xres - 1; } else { active_h_start = 0; active_h_end = 0; } if (p->height != p->yres) { active_v_start = display_v_start; active_v_end = active_v_start + (p->yres * hsync_period) - 1; } else { active_v_start = 0; active_v_end = 0; } if (active_h_end) { active_hctl = (active_h_end << 16) | active_h_start; intf_cfg |= BIT(29); /* ACTIVE_H_ENABLE */ } else { active_hctl = 0; } if (active_v_end) intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */ hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; display_hctl = (hsync_end_x << 16) | hsync_start_x; den_polarity = 0; if (ctx->cap->type == INTF_HDMI) { hsync_polarity = p->yres >= 720 ? 0 : 1; vsync_polarity = p->yres >= 720 ? 0 : 1; } else { hsync_polarity = 0; vsync_polarity = 0; } polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ (vsync_polarity << 1) | /* VSYNC Polarity */ (hsync_polarity << 0); /* HSYNC Polarity */ if (!DPU_FORMAT_IS_YUV(fmt)) panel_format = (fmt->bits[C0_G_Y] | (fmt->bits[C1_B_Cb] << 2) | (fmt->bits[C2_R_Cr] << 4) | (0x21 << 8)); else /* Interface treats all the pixel data in RGB888 format */ panel_format = (COLOR_8BIT | (COLOR_8BIT << 2) | (COLOR_8BIT << 4) | (0x21 << 8)); DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl); DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0, p->vsync_pulse_width * hsync_period); DPU_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl); DPU_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start); DPU_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end); DPU_REG_WRITE(c, INTF_ACTIVE_HCTL, active_hctl); DPU_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start); DPU_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end); DPU_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr); DPU_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr); DPU_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew); DPU_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl); DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3); DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg); DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); }