Loading drivers/gpu/drm/msm/sde/sde_crtc.c +201 −197 Original line number Diff line number Diff line Loading @@ -607,18 +607,6 @@ static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) return; } /** * sde_crtc_destroy_dest_scaler - free memory allocated for scaler lut * @sde_crtc: Pointer to sde crtc */ static void _sde_crtc_destroy_dest_scaler(struct sde_crtc *sde_crtc) { if (!sde_crtc) return; kfree(sde_crtc->scl3_lut_cfg); } static void sde_crtc_destroy(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); Loading @@ -632,7 +620,6 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) drm_property_unreference_blob(sde_crtc->blob_info); msm_property_destroy(&sde_crtc->property_info); sde_cp_crtc_destroy_properties(crtc); _sde_crtc_destroy_dest_scaler(sde_crtc); sde_fence_deinit(&sde_crtc->output_fence); _sde_crtc_deinit_events(sde_crtc); Loading Loading @@ -1812,16 +1799,11 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, size_t len = 0; int ret = 0; if (!sde_crtc || !cstate || !sde_crtc->scl3_lut_cfg) { if (!sde_crtc || !cstate) { SDE_ERROR("invalid args\n"); return -EINVAL; } if (sde_crtc->scl3_lut_cfg->is_configured) { SDE_DEBUG("%s: lut already configured\n", sde_crtc->name); return 0; } lut_data = msm_property_get_blob(&sde_crtc->property_info, &cstate->property_state, &len, lut_idx); if (!lut_data || !len) { Loading @@ -1831,7 +1813,7 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, len = 0; } cfg = sde_crtc->scl3_lut_cfg; cfg = &cstate->scl3_lut_cfg; switch (lut_idx) { case CRTC_PROP_DEST_SCALER_LUT_ED: Loading @@ -1848,12 +1830,15 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, break; default: ret = -EINVAL; SDE_ERROR("invalid LUT index = %d", lut_idx); SDE_ERROR("%s:invalid LUT idx(%d)\n", sde_crtc->name, lut_idx); SDE_EVT32(DRMID(&sde_crtc->base), lut_idx, SDE_EVTLOG_ERROR); break; } cfg->is_configured = cfg->dir_lut && cfg->cir_lut && cfg->sep_lut; SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), ret, lut_idx, len, cfg->is_configured); return ret; } Loading Loading @@ -1994,6 +1979,44 @@ int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit) return ret; } static int _sde_validate_hw_resources(struct sde_crtc *sde_crtc) { int i; /** * Check if sufficient hw resources are * available as per target caps & topology */ if (!sde_crtc) { SDE_ERROR("invalid argument\n"); return -EINVAL; } if (!sde_crtc->num_mixers || sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("%s: invalid number mixers: %d\n", sde_crtc->name, sde_crtc->num_mixers); SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers, SDE_EVTLOG_ERROR); return -EINVAL; } for (i = 0; i < sde_crtc->num_mixers; i++) { if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ctl || !sde_crtc->mixers[i].hw_ds) { SDE_ERROR("%s:insufficient resources for mixer(%d)\n", sde_crtc->name, i); SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers, i, sde_crtc->mixers[i].hw_lm, sde_crtc->mixers[i].hw_ctl, sde_crtc->mixers[i].hw_ds, SDE_EVTLOG_ERROR); return -EINVAL; } } return 0; } /** * _sde_crtc_dest_scaler_setup - Set up dest scaler block * @crtc: Pointer to drm crtc Loading @@ -2010,6 +2033,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) u32 flush_mask = 0, op_mode = 0; u32 lm_idx = 0, num_mixers = 0; int i, count = 0; bool ds_dirty = false; if (!crtc) return; Loading @@ -2018,29 +2042,40 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) cstate = to_sde_crtc_state(crtc->state); kms = _sde_crtc_get_kms(crtc); num_mixers = sde_crtc->num_mixers; count = cstate->num_ds; SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32(DRMID(crtc), num_mixers, count, cstate->ds_dirty, sde_crtc->ds_reconfig, cstate->num_ds_enabled); if (!cstate->ds_dirty) { /** * destination scaler configuration will be done either * or on set property or on power collapse (idle/suspend) */ ds_dirty = (cstate->ds_dirty || sde_crtc->ds_reconfig); if (sde_crtc->ds_reconfig) { SDE_DEBUG("reconfigure dest scaler block\n"); sde_crtc->ds_reconfig = false; } if (!ds_dirty) { SDE_DEBUG("no change in settings, skip commit\n"); } else if (!kms || !kms->catalog) { SDE_ERROR("invalid parameters\n"); SDE_ERROR("crtc%d:invalid parameters\n", crtc->base.id); } else if (!kms->catalog->mdp[0].has_dest_scaler) { SDE_DEBUG("dest scaler feature not supported\n"); } else if (num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("invalid number mixers: %d\n", num_mixers); } else if (!sde_crtc->scl3_lut_cfg->is_configured) { SDE_DEBUG("no LUT data available\n"); } else if (_sde_validate_hw_resources(sde_crtc)) { //do nothing } else if (!cstate->scl3_lut_cfg.is_configured) { SDE_ERROR("crtc%d:no LUT data available\n", crtc->base.id); } else { count = cstate->num_ds_enabled ? cstate->num_ds : num_mixers; for (i = 0; i < count; i++) { cfg = &cstate->ds_cfg[i]; if (!cfg->flags) continue; lm_idx = cfg->ndx; lm_idx = cfg->idx; hw_lm = sde_crtc->mixers[lm_idx].hw_lm; hw_ctl = sde_crtc->mixers[lm_idx].hw_ctl; hw_ds = sde_crtc->mixers[lm_idx].hw_ds; Loading @@ -2054,7 +2089,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) CRTC_DUAL_MIXERS) ? SDE_DS_OP_MODE_DUAL : 0; hw_ds->ops.setup_opmode(hw_ds, op_mode); SDE_EVT32(DRMID(crtc), op_mode); SDE_EVT32_VERBOSE(DRMID(crtc), op_mode); } /* Setup scaler */ Loading @@ -2063,23 +2098,15 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) SDE_DRM_DESTSCALER_ENHANCER_UPDATE)) { if (hw_ds->ops.setup_scaler) hw_ds->ops.setup_scaler(hw_ds, cfg->scl3_cfg, sde_crtc->scl3_lut_cfg); &cfg->scl3_cfg, &cstate->scl3_lut_cfg); /** * Clear the flags as the block doesn't have to * be programmed in each commit if no updates */ cfg->flags &= ~SDE_DRM_DESTSCALER_SCALE_UPDATE; cfg->flags &= ~SDE_DRM_DESTSCALER_ENHANCER_UPDATE; } /* * Dest scaler shares the flush bit of the LM in control */ if (cfg->set_lm_flush && hw_lm && hw_ctl && hw_ctl->ops.get_bitmask_mixer) { if (hw_ctl->ops.get_bitmask_mixer) { flush_mask = hw_ctl->ops.get_bitmask_mixer( hw_ctl, hw_lm->idx); SDE_DEBUG("Set lm[%d] flush = %d", Loading @@ -2087,9 +2114,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask); } cfg->set_lm_flush = false; } cstate->ds_dirty = false; } } Loading Loading @@ -2560,28 +2585,6 @@ static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate, } } /** * _sde_crtc_dest_scaler_init - allocate memory for scaler lut * @sde_crtc : Pointer to sde crtc * @catalog : Pointer to mdss catalog info */ static void _sde_crtc_dest_scaler_init(struct sde_crtc *sde_crtc, struct sde_mdss_cfg *catalog) { if (!sde_crtc || !catalog) return; if (!catalog->mdp[0].has_dest_scaler) { SDE_DEBUG("dest scaler feature not supported\n"); return; } sde_crtc->scl3_lut_cfg = kzalloc(sizeof(struct sde_hw_scaler3_lut_cfg), GFP_KERNEL); if (!sde_crtc->scl3_lut_cfg) SDE_ERROR("failed to create scale LUT for dest scaler"); } /** * _sde_crtc_set_dest_scaler - copy dest scaler settings from userspace * @sde_crtc : Pointer to sde crtc Loading @@ -2596,7 +2599,7 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, struct sde_drm_dest_scaler_cfg *ds_cfg_usr; struct sde_drm_scaler_v2 scaler_v2; void __user *scaler_v2_usr; int i, count, ret = 0; int i, count; if (!sde_crtc || !cstate) { SDE_ERROR("invalid sde_crtc/state\n"); Loading @@ -2605,15 +2608,14 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, SDE_DEBUG("crtc %s\n", sde_crtc->name); cstate->num_ds = 0; cstate->ds_dirty = false; if (!usr_ptr) { SDE_DEBUG("ds data removed\n"); return 0; } if (copy_from_user(&ds_data, usr_ptr, sizeof(ds_data))) { SDE_ERROR("failed to copy dest scaler data from user\n"); SDE_ERROR("%s:failed to copy dest scaler data from user\n", sde_crtc->name); return -EINVAL; } Loading @@ -2623,11 +2625,10 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, return 0; } if (!sde_crtc->num_mixers || count > sde_crtc->num_mixers || (count && (count != sde_crtc->num_mixers) && !(ds_data.ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { SDE_ERROR("invalid config:num ds(%d), mixers(%d),flags(%d)\n", count, sde_crtc->num_mixers, ds_data.ds_cfg[0].flags); if (count > SDE_MAX_DS_COUNT) { SDE_ERROR("%s: invalid config: num_ds(%d) max(%d)\n", sde_crtc->name, count, SDE_MAX_DS_COUNT); SDE_EVT32(DRMID(&sde_crtc->base), count, SDE_EVTLOG_ERROR); return -EINVAL; } Loading @@ -2635,48 +2636,34 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, for (i = 0; i < count; i++) { ds_cfg_usr = &ds_data.ds_cfg[i]; cstate->ds_cfg[i].ndx = ds_cfg_usr->index; cstate->ds_cfg[i].idx = ds_cfg_usr->index; cstate->ds_cfg[i].flags = ds_cfg_usr->flags; cstate->ds_cfg[i].lm_width = ds_cfg_usr->lm_width; cstate->ds_cfg[i].lm_height = ds_cfg_usr->lm_height; cstate->ds_cfg[i].scl3_cfg = NULL; memset(&scaler_v2, 0, sizeof(scaler_v2)); if (ds_cfg_usr->scaler_cfg) { scaler_v2_usr = (void __user *)((uintptr_t)ds_cfg_usr->scaler_cfg); memset(&scaler_v2, 0, sizeof(scaler_v2)); cstate->ds_cfg[i].scl3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg), GFP_KERNEL); if (!cstate->ds_cfg[i].scl3_cfg) { ret = -ENOMEM; goto err; } if (copy_from_user(&scaler_v2, scaler_v2_usr, sizeof(scaler_v2))) { SDE_ERROR("scale data:copy from user failed\n"); ret = -EINVAL; goto err; SDE_ERROR("%s:scaler: copy from user failed\n", sde_crtc->name); return -EINVAL; } } sde_set_scaler_v2(cstate->ds_cfg[i].scl3_cfg, &scaler_v2); sde_set_scaler_v2(&cstate->ds_cfg[i].scl3_cfg, &scaler_v2); SDE_DEBUG("en(%d)dir(%d)de(%d) src(%dx%d) dst(%dx%d)\n", scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); } scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); SDE_DEBUG("ds cfg[%d]-ndx(%d) flags(%d) lm(%dx%d)\n", i, ds_cfg_usr->index, ds_cfg_usr->flags, Loading @@ -2688,13 +2675,9 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, cstate->num_ds = count; cstate->ds_dirty = true; return 0; err: for (; i >= 0; i--) kfree(cstate->ds_cfg[i].scl3_cfg); SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), count, cstate->ds_dirty); return ret; return 0; } /** Loading @@ -2712,7 +2695,7 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, struct sde_hw_ds *hw_ds; struct sde_hw_ds_cfg *cfg; u32 i, ret = 0, lm_idx; u32 num_ds_enable = 0; u32 num_ds_enable = 0, hdisplay = 0; u32 max_in_width = 0, max_out_width = 0; u32 prev_lm_width = 0, prev_lm_height = 0; Loading @@ -2726,13 +2709,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, SDE_DEBUG("crtc%d\n", crtc->base.id); if (!cstate->ds_dirty && !cstate->num_ds_enabled) { if (!cstate->ds_dirty) { SDE_DEBUG("dest scaler property not set, skip validation\n"); return 0; } if (!kms || !kms->catalog) { SDE_ERROR("invalid parameters\n"); SDE_ERROR("crtc%d: invalid parameters\n", crtc->base.id); return -EINVAL; } Loading @@ -2742,40 +2725,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, } if (!sde_crtc->num_mixers) { SDE_ERROR("mixers not allocated\n"); return -EINVAL; } /** * Check if sufficient hw resources are * available as per target caps & topology */ if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("invalid config: mixers(%d) max(%d)\n", sde_crtc->num_mixers, CRTC_DUAL_MIXERS); ret = -EINVAL; goto err; SDE_DEBUG("mixers not allocated\n"); return 0; } for (i = 0; i < sde_crtc->num_mixers; i++) { if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ds) { SDE_ERROR("insufficient HW resources allocated\n"); ret = -EINVAL; ret = _sde_validate_hw_resources(sde_crtc); if (ret) goto err; } } /** * Check if DS needs to be enabled or disabled * In case of enable, validate the data */ if (!cstate->ds_dirty || !cstate->num_ds || !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) { SDE_DEBUG("disable dest scaler,dirty(%d)num(%d)flags(%d)\n", cstate->ds_dirty, cstate->num_ds, cstate->ds_cfg[0].flags); goto disable; } /** * No of dest scalers shouldn't exceed hw ds block count and Loading @@ -2785,17 +2741,30 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, if (cstate->num_ds > kms->catalog->ds_count || ((cstate->num_ds != sde_crtc->num_mixers) && !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { SDE_ERROR("invalid cfg: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n", cstate->num_ds, kms->catalog->ds_count, SDE_ERROR("crtc%d: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n", crtc->base.id, cstate->num_ds, kms->catalog->ds_count, cstate->ds_cfg[0].flags); ret = -EINVAL; goto err; } /** * Check if DS needs to be enabled or disabled * In case of enable, validate the data */ if (!(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) { SDE_DEBUG("disable dest scaler, num(%d) flags(%d)\n", cstate->num_ds, cstate->ds_cfg[0].flags); goto disable; } /* Display resolution */ hdisplay = mode->hdisplay/sde_crtc->num_mixers; /* Validate the DS data */ for (i = 0; i < cstate->num_ds; i++) { cfg = &cstate->ds_cfg[i]; lm_idx = cfg->ndx; lm_idx = cfg->idx; /** * Validate against topology Loading @@ -2804,8 +2773,10 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, */ if (lm_idx >= sde_crtc->num_mixers || (i != lm_idx && !(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { SDE_ERROR("invalid user data(%d):idx(%d), flags(%d)\n", i, lm_idx, cfg->flags); SDE_ERROR("crtc%d: ds_cfg id(%d):idx(%d), flags(%d)\n", crtc->base.id, i, lm_idx, cfg->flags); SDE_EVT32(DRMID(crtc), i, lm_idx, cfg->flags, SDE_EVTLOG_ERROR); ret = -EINVAL; goto err; } Loading @@ -2824,14 +2795,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, } /* Check LM width and height */ if (cfg->lm_width > (mode->hdisplay/sde_crtc->num_mixers) || cfg->lm_height > mode->vdisplay || !cfg->lm_width || !cfg->lm_height) { SDE_ERROR("invalid lm size[%d,%d] display [%d,%d]\n", cfg->lm_width, cfg->lm_height, mode->hdisplay/sde_crtc->num_mixers, mode->vdisplay); if (cfg->lm_width > hdisplay || cfg->lm_height > mode->vdisplay || !cfg->lm_width || !cfg->lm_height) { SDE_ERROR("crtc%d: lm size[%d,%d] display [%d,%d]\n", crtc->base.id, cfg->lm_width, cfg->lm_height, hdisplay, mode->vdisplay); SDE_EVT32(DRMID(crtc), cfg->lm_width, cfg->lm_height, hdisplay, mode->vdisplay, SDE_EVTLOG_ERROR); ret = -E2BIG; goto err; } Loading @@ -2842,9 +2812,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, } else { if (cfg->lm_width != prev_lm_width || cfg->lm_height != prev_lm_height) { SDE_ERROR("lm size:left[%d,%d], right[%d %d]\n", cfg->lm_width, cfg->lm_height, prev_lm_width, prev_lm_height); SDE_ERROR("crtc%d:lm left[%d,%d]right[%d %d]\n", crtc->base.id, cfg->lm_width, cfg->lm_height, prev_lm_width, prev_lm_height); SDE_EVT32(DRMID(crtc), cfg->lm_width, cfg->lm_height, prev_lm_width, prev_lm_height, SDE_EVTLOG_ERROR); ret = -EINVAL; goto err; } Loading @@ -2853,22 +2827,40 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, /* Check scaler data */ if (cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE || cfg->flags & SDE_DRM_DESTSCALER_ENHANCER_UPDATE) { if (!cfg->scl3_cfg) { ret = -EINVAL; SDE_ERROR("null scale data\n"); goto err; } if (cfg->scl3_cfg->src_width[0] > max_in_width || cfg->scl3_cfg->dst_width > max_out_width || !cfg->scl3_cfg->src_width[0] || !cfg->scl3_cfg->dst_width) { SDE_ERROR("scale width(%d %d) for ds-%d:\n", cfg->scl3_cfg->src_width[0], cfg->scl3_cfg->dst_width, /** * Scaler src and dst width shouldn't exceed the maximum * width limitation. Also, if there is no partial update * dst width and height must match display resolution. */ if (cfg->scl3_cfg.src_width[0] > max_in_width || cfg->scl3_cfg.dst_width > max_out_width || !cfg->scl3_cfg.src_width[0] || !cfg->scl3_cfg.dst_width || (!(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE) && (cfg->scl3_cfg.dst_width != hdisplay || cfg->scl3_cfg.dst_height != mode->vdisplay))) { SDE_ERROR("crtc%d: ", crtc->base.id); SDE_ERROR("src_w(%d) dst(%dx%d) display(%dx%d)", cfg->scl3_cfg.src_width[0], cfg->scl3_cfg.dst_width, cfg->scl3_cfg.dst_height, hdisplay, mode->vdisplay); SDE_ERROR("num_mixers(%d) flags(%d) ds-%d:\n", sde_crtc->num_mixers, cfg->flags, hw_ds->idx - DS_0); SDE_ERROR("scale_en = %d, DE_en =%d\n", cfg->scl3_cfg->enable, cfg->scl3_cfg->de.enable); cfg->scl3_cfg.enable, cfg->scl3_cfg.de.enable); SDE_EVT32(DRMID(crtc), cfg->scl3_cfg.enable, cfg->scl3_cfg.de.enable, cfg->flags, max_in_width, max_out_width, cfg->scl3_cfg.src_width[0], cfg->scl3_cfg.dst_width, cfg->scl3_cfg.dst_height, hdisplay, mode->vdisplay, sde_crtc->num_mixers, SDE_EVTLOG_ERROR); cfg->flags &= ~SDE_DRM_DESTSCALER_SCALE_UPDATE; Loading @@ -2883,36 +2875,34 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE) num_ds_enable++; /** * Validation successful, indicator for flush to be issued */ cfg->set_lm_flush = true; SDE_DEBUG("ds[%d]: flags = 0x%X\n", SDE_DEBUG("ds[%d]: flags[0x%X]\n", hw_ds->idx - DS_0, cfg->flags); SDE_EVT32_VERBOSE(DRMID(crtc), hw_ds->idx - DS_0, cfg->flags); } disable: SDE_DEBUG("dest scaler enable status, old = %d, new = %d", SDE_DEBUG("dest scaler status : %d -> %d\n", cstate->num_ds_enabled, num_ds_enable); SDE_EVT32(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable, cstate->ds_dirty); SDE_EVT32_VERBOSE(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable, cstate->num_ds, cstate->ds_dirty); if (cstate->num_ds_enabled != num_ds_enable) { /* Disabling destination scaler */ if (!num_ds_enable) { for (i = 0; i < sde_crtc->num_mixers; i++) { for (i = 0; i < cstate->num_ds; i++) { cfg = &cstate->ds_cfg[i]; cfg->ndx = i; cfg->idx = i; /* Update scaler settings in disable case */ cfg->flags = SDE_DRM_DESTSCALER_SCALE_UPDATE; cfg->scl3_cfg->enable = 0; cfg->scl3_cfg->de.enable = 0; cfg->set_lm_flush = true; cfg->scl3_cfg.enable = 0; cfg->scl3_cfg.de.enable = 0; } } cstate->num_ds_enabled = num_ds_enable; cstate->ds_dirty = true; } else { if (!cstate->num_ds_enabled) cstate->ds_dirty = false; } return 0; Loading Loading @@ -3879,6 +3869,9 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) old_cstate, cstate, &cstate->property_state, cstate->property_values); /* clear destination scaler dirty bit */ cstate->ds_dirty = false; /* duplicate base helper */ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); Loading Loading @@ -3945,6 +3938,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) { struct drm_crtc *crtc = arg; struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; struct drm_plane *plane; struct drm_encoder *encoder; struct sde_crtc_mixer *m; Loading @@ -3958,6 +3952,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) return; } sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(crtc->state); mutex_lock(&sde_crtc->crtc_lock); Loading Loading @@ -4046,6 +4041,14 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_plane_set_revalidate(plane, true); sde_cp_crtc_suspend(crtc); /** * destination scaler if enabled should be reconfigured * in the next frame update */ if (cstate->num_ds_enabled) sde_crtc->ds_reconfig = true; break; default: SDE_DEBUG("event:%d not handled\n", event_type); Loading Loading @@ -4091,6 +4094,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc) msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); /* destination scaler if enabled should be reconfigured on resume */ if (cstate->num_ds_enabled) sde_crtc->ds_reconfig = true; /* wait for frame_event_done completion */ if (_sde_crtc_wait_for_frame_done(crtc)) SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", Loading Loading @@ -5742,9 +5749,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_crtc_install_properties(crtc, kms->catalog); /* Init dest scaler */ _sde_crtc_dest_scaler_init(sde_crtc, kms->catalog); /* Install color processing properties */ sde_cp_crtc_init(crtc); sde_cp_crtc_install_properties(crtc); Loading drivers/gpu/drm/msm/sde/sde_crtc.h +4 −2 Original line number Diff line number Diff line Loading @@ -188,6 +188,7 @@ struct sde_crtc_event { * @enabled : whether the SDE CRTC is currently enabled. updated in the * commit-thread, not state-swap time which is earlier, so * safe to make decisions on during VBLANK on/off work * @ds_reconfig : force reconfiguration of the destination scaler block * @feature_list : list of color processing features supported on a crtc * @active_list : list of color processing features are active * @dirty_list : list of color processing features are dirty Loading Loading @@ -215,7 +216,6 @@ struct sde_crtc_event { * @cur_perf : current performance committed to clock/bandwidth driver * @rp_lock : serialization lock for resource pool * @rp_head : list of active resource pool * @scl3_cfg_lut : qseed3 lut config */ struct sde_crtc { struct drm_crtc base; Loading @@ -226,7 +226,6 @@ struct sde_crtc { u32 num_mixers; bool mixers_swapped; struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS]; struct sde_hw_scaler3_lut_cfg *scl3_lut_cfg; struct drm_pending_vblank_event *event; u32 vsync_count; Loading @@ -248,6 +247,7 @@ struct sde_crtc { bool suspend; bool enabled; bool ds_reconfig; struct list_head feature_list; struct list_head active_list; struct list_head dirty_list; Loading Loading @@ -374,6 +374,7 @@ struct sde_crtc_respool { * @num_ds_enabled: Number of destination scalers enabled * @ds_dirty: Boolean to indicate if dirty or not * @ds_cfg: Destination scaler config * @scl3_lut_cfg: QSEED3 lut config * @new_perf: new performance state being requested * @sbuf_cfg: stream buffer configuration * @sbuf_prefill_line: number of line for inline rotator prefetch Loading Loading @@ -403,6 +404,7 @@ struct sde_crtc_state { uint32_t num_ds_enabled; bool ds_dirty; struct sde_hw_ds_cfg ds_cfg[SDE_MAX_DS_COUNT]; struct sde_hw_scaler3_lut_cfg scl3_lut_cfg; struct sde_core_perf_params new_perf; struct sde_ctl_sbuf_cfg sbuf_cfg; Loading drivers/gpu/drm/msm/sde/sde_hw_ds.h +4 −6 Original line number Diff line number Diff line Loading @@ -27,20 +27,18 @@ struct sde_hw_ds; #define SDE_DS_OP_MODE_DUAL BIT(16) /* struct sde_hw_ds_cfg - destination scaler config * @ndx : DS selection index * @idx : DS selection index * @flags : Flag to switch between mode for DS * @lm_width : Layer mixer width configuration * @lm_heigh : Layer mixer height configuration * @set_lm_flush : LM flush bit * @scl3_cfg : Pointer to sde_hw_scaler3_cfg. * @scl3_cfg : Configuration data for scaler */ struct sde_hw_ds_cfg { u32 ndx; u32 idx; int flags; u32 lm_width; u32 lm_height; bool set_lm_flush; struct sde_hw_scaler3_cfg *scl3_cfg; struct sde_hw_scaler3_cfg scl3_cfg; }; /** Loading Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +201 −197 Original line number Diff line number Diff line Loading @@ -607,18 +607,6 @@ static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) return; } /** * sde_crtc_destroy_dest_scaler - free memory allocated for scaler lut * @sde_crtc: Pointer to sde crtc */ static void _sde_crtc_destroy_dest_scaler(struct sde_crtc *sde_crtc) { if (!sde_crtc) return; kfree(sde_crtc->scl3_lut_cfg); } static void sde_crtc_destroy(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); Loading @@ -632,7 +620,6 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) drm_property_unreference_blob(sde_crtc->blob_info); msm_property_destroy(&sde_crtc->property_info); sde_cp_crtc_destroy_properties(crtc); _sde_crtc_destroy_dest_scaler(sde_crtc); sde_fence_deinit(&sde_crtc->output_fence); _sde_crtc_deinit_events(sde_crtc); Loading Loading @@ -1812,16 +1799,11 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, size_t len = 0; int ret = 0; if (!sde_crtc || !cstate || !sde_crtc->scl3_lut_cfg) { if (!sde_crtc || !cstate) { SDE_ERROR("invalid args\n"); return -EINVAL; } if (sde_crtc->scl3_lut_cfg->is_configured) { SDE_DEBUG("%s: lut already configured\n", sde_crtc->name); return 0; } lut_data = msm_property_get_blob(&sde_crtc->property_info, &cstate->property_state, &len, lut_idx); if (!lut_data || !len) { Loading @@ -1831,7 +1813,7 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, len = 0; } cfg = sde_crtc->scl3_lut_cfg; cfg = &cstate->scl3_lut_cfg; switch (lut_idx) { case CRTC_PROP_DEST_SCALER_LUT_ED: Loading @@ -1848,12 +1830,15 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, break; default: ret = -EINVAL; SDE_ERROR("invalid LUT index = %d", lut_idx); SDE_ERROR("%s:invalid LUT idx(%d)\n", sde_crtc->name, lut_idx); SDE_EVT32(DRMID(&sde_crtc->base), lut_idx, SDE_EVTLOG_ERROR); break; } cfg->is_configured = cfg->dir_lut && cfg->cir_lut && cfg->sep_lut; SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), ret, lut_idx, len, cfg->is_configured); return ret; } Loading Loading @@ -1994,6 +1979,44 @@ int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit) return ret; } static int _sde_validate_hw_resources(struct sde_crtc *sde_crtc) { int i; /** * Check if sufficient hw resources are * available as per target caps & topology */ if (!sde_crtc) { SDE_ERROR("invalid argument\n"); return -EINVAL; } if (!sde_crtc->num_mixers || sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("%s: invalid number mixers: %d\n", sde_crtc->name, sde_crtc->num_mixers); SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers, SDE_EVTLOG_ERROR); return -EINVAL; } for (i = 0; i < sde_crtc->num_mixers; i++) { if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ctl || !sde_crtc->mixers[i].hw_ds) { SDE_ERROR("%s:insufficient resources for mixer(%d)\n", sde_crtc->name, i); SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers, i, sde_crtc->mixers[i].hw_lm, sde_crtc->mixers[i].hw_ctl, sde_crtc->mixers[i].hw_ds, SDE_EVTLOG_ERROR); return -EINVAL; } } return 0; } /** * _sde_crtc_dest_scaler_setup - Set up dest scaler block * @crtc: Pointer to drm crtc Loading @@ -2010,6 +2033,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) u32 flush_mask = 0, op_mode = 0; u32 lm_idx = 0, num_mixers = 0; int i, count = 0; bool ds_dirty = false; if (!crtc) return; Loading @@ -2018,29 +2042,40 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) cstate = to_sde_crtc_state(crtc->state); kms = _sde_crtc_get_kms(crtc); num_mixers = sde_crtc->num_mixers; count = cstate->num_ds; SDE_DEBUG("crtc%d\n", crtc->base.id); SDE_EVT32(DRMID(crtc), num_mixers, count, cstate->ds_dirty, sde_crtc->ds_reconfig, cstate->num_ds_enabled); if (!cstate->ds_dirty) { /** * destination scaler configuration will be done either * or on set property or on power collapse (idle/suspend) */ ds_dirty = (cstate->ds_dirty || sde_crtc->ds_reconfig); if (sde_crtc->ds_reconfig) { SDE_DEBUG("reconfigure dest scaler block\n"); sde_crtc->ds_reconfig = false; } if (!ds_dirty) { SDE_DEBUG("no change in settings, skip commit\n"); } else if (!kms || !kms->catalog) { SDE_ERROR("invalid parameters\n"); SDE_ERROR("crtc%d:invalid parameters\n", crtc->base.id); } else if (!kms->catalog->mdp[0].has_dest_scaler) { SDE_DEBUG("dest scaler feature not supported\n"); } else if (num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("invalid number mixers: %d\n", num_mixers); } else if (!sde_crtc->scl3_lut_cfg->is_configured) { SDE_DEBUG("no LUT data available\n"); } else if (_sde_validate_hw_resources(sde_crtc)) { //do nothing } else if (!cstate->scl3_lut_cfg.is_configured) { SDE_ERROR("crtc%d:no LUT data available\n", crtc->base.id); } else { count = cstate->num_ds_enabled ? cstate->num_ds : num_mixers; for (i = 0; i < count; i++) { cfg = &cstate->ds_cfg[i]; if (!cfg->flags) continue; lm_idx = cfg->ndx; lm_idx = cfg->idx; hw_lm = sde_crtc->mixers[lm_idx].hw_lm; hw_ctl = sde_crtc->mixers[lm_idx].hw_ctl; hw_ds = sde_crtc->mixers[lm_idx].hw_ds; Loading @@ -2054,7 +2089,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) CRTC_DUAL_MIXERS) ? SDE_DS_OP_MODE_DUAL : 0; hw_ds->ops.setup_opmode(hw_ds, op_mode); SDE_EVT32(DRMID(crtc), op_mode); SDE_EVT32_VERBOSE(DRMID(crtc), op_mode); } /* Setup scaler */ Loading @@ -2063,23 +2098,15 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) SDE_DRM_DESTSCALER_ENHANCER_UPDATE)) { if (hw_ds->ops.setup_scaler) hw_ds->ops.setup_scaler(hw_ds, cfg->scl3_cfg, sde_crtc->scl3_lut_cfg); &cfg->scl3_cfg, &cstate->scl3_lut_cfg); /** * Clear the flags as the block doesn't have to * be programmed in each commit if no updates */ cfg->flags &= ~SDE_DRM_DESTSCALER_SCALE_UPDATE; cfg->flags &= ~SDE_DRM_DESTSCALER_ENHANCER_UPDATE; } /* * Dest scaler shares the flush bit of the LM in control */ if (cfg->set_lm_flush && hw_lm && hw_ctl && hw_ctl->ops.get_bitmask_mixer) { if (hw_ctl->ops.get_bitmask_mixer) { flush_mask = hw_ctl->ops.get_bitmask_mixer( hw_ctl, hw_lm->idx); SDE_DEBUG("Set lm[%d] flush = %d", Loading @@ -2087,9 +2114,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask); } cfg->set_lm_flush = false; } cstate->ds_dirty = false; } } Loading Loading @@ -2560,28 +2585,6 @@ static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate, } } /** * _sde_crtc_dest_scaler_init - allocate memory for scaler lut * @sde_crtc : Pointer to sde crtc * @catalog : Pointer to mdss catalog info */ static void _sde_crtc_dest_scaler_init(struct sde_crtc *sde_crtc, struct sde_mdss_cfg *catalog) { if (!sde_crtc || !catalog) return; if (!catalog->mdp[0].has_dest_scaler) { SDE_DEBUG("dest scaler feature not supported\n"); return; } sde_crtc->scl3_lut_cfg = kzalloc(sizeof(struct sde_hw_scaler3_lut_cfg), GFP_KERNEL); if (!sde_crtc->scl3_lut_cfg) SDE_ERROR("failed to create scale LUT for dest scaler"); } /** * _sde_crtc_set_dest_scaler - copy dest scaler settings from userspace * @sde_crtc : Pointer to sde crtc Loading @@ -2596,7 +2599,7 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, struct sde_drm_dest_scaler_cfg *ds_cfg_usr; struct sde_drm_scaler_v2 scaler_v2; void __user *scaler_v2_usr; int i, count, ret = 0; int i, count; if (!sde_crtc || !cstate) { SDE_ERROR("invalid sde_crtc/state\n"); Loading @@ -2605,15 +2608,14 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, SDE_DEBUG("crtc %s\n", sde_crtc->name); cstate->num_ds = 0; cstate->ds_dirty = false; if (!usr_ptr) { SDE_DEBUG("ds data removed\n"); return 0; } if (copy_from_user(&ds_data, usr_ptr, sizeof(ds_data))) { SDE_ERROR("failed to copy dest scaler data from user\n"); SDE_ERROR("%s:failed to copy dest scaler data from user\n", sde_crtc->name); return -EINVAL; } Loading @@ -2623,11 +2625,10 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, return 0; } if (!sde_crtc->num_mixers || count > sde_crtc->num_mixers || (count && (count != sde_crtc->num_mixers) && !(ds_data.ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { SDE_ERROR("invalid config:num ds(%d), mixers(%d),flags(%d)\n", count, sde_crtc->num_mixers, ds_data.ds_cfg[0].flags); if (count > SDE_MAX_DS_COUNT) { SDE_ERROR("%s: invalid config: num_ds(%d) max(%d)\n", sde_crtc->name, count, SDE_MAX_DS_COUNT); SDE_EVT32(DRMID(&sde_crtc->base), count, SDE_EVTLOG_ERROR); return -EINVAL; } Loading @@ -2635,48 +2636,34 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, for (i = 0; i < count; i++) { ds_cfg_usr = &ds_data.ds_cfg[i]; cstate->ds_cfg[i].ndx = ds_cfg_usr->index; cstate->ds_cfg[i].idx = ds_cfg_usr->index; cstate->ds_cfg[i].flags = ds_cfg_usr->flags; cstate->ds_cfg[i].lm_width = ds_cfg_usr->lm_width; cstate->ds_cfg[i].lm_height = ds_cfg_usr->lm_height; cstate->ds_cfg[i].scl3_cfg = NULL; memset(&scaler_v2, 0, sizeof(scaler_v2)); if (ds_cfg_usr->scaler_cfg) { scaler_v2_usr = (void __user *)((uintptr_t)ds_cfg_usr->scaler_cfg); memset(&scaler_v2, 0, sizeof(scaler_v2)); cstate->ds_cfg[i].scl3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg), GFP_KERNEL); if (!cstate->ds_cfg[i].scl3_cfg) { ret = -ENOMEM; goto err; } if (copy_from_user(&scaler_v2, scaler_v2_usr, sizeof(scaler_v2))) { SDE_ERROR("scale data:copy from user failed\n"); ret = -EINVAL; goto err; SDE_ERROR("%s:scaler: copy from user failed\n", sde_crtc->name); return -EINVAL; } } sde_set_scaler_v2(cstate->ds_cfg[i].scl3_cfg, &scaler_v2); sde_set_scaler_v2(&cstate->ds_cfg[i].scl3_cfg, &scaler_v2); SDE_DEBUG("en(%d)dir(%d)de(%d) src(%dx%d) dst(%dx%d)\n", scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); } scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, scaler_v2.src_width[0], scaler_v2.src_height[0], scaler_v2.dst_width, scaler_v2.dst_height); SDE_DEBUG("ds cfg[%d]-ndx(%d) flags(%d) lm(%dx%d)\n", i, ds_cfg_usr->index, ds_cfg_usr->flags, Loading @@ -2688,13 +2675,9 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, cstate->num_ds = count; cstate->ds_dirty = true; return 0; err: for (; i >= 0; i--) kfree(cstate->ds_cfg[i].scl3_cfg); SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), count, cstate->ds_dirty); return ret; return 0; } /** Loading @@ -2712,7 +2695,7 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, struct sde_hw_ds *hw_ds; struct sde_hw_ds_cfg *cfg; u32 i, ret = 0, lm_idx; u32 num_ds_enable = 0; u32 num_ds_enable = 0, hdisplay = 0; u32 max_in_width = 0, max_out_width = 0; u32 prev_lm_width = 0, prev_lm_height = 0; Loading @@ -2726,13 +2709,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, SDE_DEBUG("crtc%d\n", crtc->base.id); if (!cstate->ds_dirty && !cstate->num_ds_enabled) { if (!cstate->ds_dirty) { SDE_DEBUG("dest scaler property not set, skip validation\n"); return 0; } if (!kms || !kms->catalog) { SDE_ERROR("invalid parameters\n"); SDE_ERROR("crtc%d: invalid parameters\n", crtc->base.id); return -EINVAL; } Loading @@ -2742,40 +2725,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, } if (!sde_crtc->num_mixers) { SDE_ERROR("mixers not allocated\n"); return -EINVAL; } /** * Check if sufficient hw resources are * available as per target caps & topology */ if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("invalid config: mixers(%d) max(%d)\n", sde_crtc->num_mixers, CRTC_DUAL_MIXERS); ret = -EINVAL; goto err; SDE_DEBUG("mixers not allocated\n"); return 0; } for (i = 0; i < sde_crtc->num_mixers; i++) { if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ds) { SDE_ERROR("insufficient HW resources allocated\n"); ret = -EINVAL; ret = _sde_validate_hw_resources(sde_crtc); if (ret) goto err; } } /** * Check if DS needs to be enabled or disabled * In case of enable, validate the data */ if (!cstate->ds_dirty || !cstate->num_ds || !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) { SDE_DEBUG("disable dest scaler,dirty(%d)num(%d)flags(%d)\n", cstate->ds_dirty, cstate->num_ds, cstate->ds_cfg[0].flags); goto disable; } /** * No of dest scalers shouldn't exceed hw ds block count and Loading @@ -2785,17 +2741,30 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, if (cstate->num_ds > kms->catalog->ds_count || ((cstate->num_ds != sde_crtc->num_mixers) && !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { SDE_ERROR("invalid cfg: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n", cstate->num_ds, kms->catalog->ds_count, SDE_ERROR("crtc%d: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n", crtc->base.id, cstate->num_ds, kms->catalog->ds_count, cstate->ds_cfg[0].flags); ret = -EINVAL; goto err; } /** * Check if DS needs to be enabled or disabled * In case of enable, validate the data */ if (!(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) { SDE_DEBUG("disable dest scaler, num(%d) flags(%d)\n", cstate->num_ds, cstate->ds_cfg[0].flags); goto disable; } /* Display resolution */ hdisplay = mode->hdisplay/sde_crtc->num_mixers; /* Validate the DS data */ for (i = 0; i < cstate->num_ds; i++) { cfg = &cstate->ds_cfg[i]; lm_idx = cfg->ndx; lm_idx = cfg->idx; /** * Validate against topology Loading @@ -2804,8 +2773,10 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, */ if (lm_idx >= sde_crtc->num_mixers || (i != lm_idx && !(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { SDE_ERROR("invalid user data(%d):idx(%d), flags(%d)\n", i, lm_idx, cfg->flags); SDE_ERROR("crtc%d: ds_cfg id(%d):idx(%d), flags(%d)\n", crtc->base.id, i, lm_idx, cfg->flags); SDE_EVT32(DRMID(crtc), i, lm_idx, cfg->flags, SDE_EVTLOG_ERROR); ret = -EINVAL; goto err; } Loading @@ -2824,14 +2795,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, } /* Check LM width and height */ if (cfg->lm_width > (mode->hdisplay/sde_crtc->num_mixers) || cfg->lm_height > mode->vdisplay || !cfg->lm_width || !cfg->lm_height) { SDE_ERROR("invalid lm size[%d,%d] display [%d,%d]\n", cfg->lm_width, cfg->lm_height, mode->hdisplay/sde_crtc->num_mixers, mode->vdisplay); if (cfg->lm_width > hdisplay || cfg->lm_height > mode->vdisplay || !cfg->lm_width || !cfg->lm_height) { SDE_ERROR("crtc%d: lm size[%d,%d] display [%d,%d]\n", crtc->base.id, cfg->lm_width, cfg->lm_height, hdisplay, mode->vdisplay); SDE_EVT32(DRMID(crtc), cfg->lm_width, cfg->lm_height, hdisplay, mode->vdisplay, SDE_EVTLOG_ERROR); ret = -E2BIG; goto err; } Loading @@ -2842,9 +2812,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, } else { if (cfg->lm_width != prev_lm_width || cfg->lm_height != prev_lm_height) { SDE_ERROR("lm size:left[%d,%d], right[%d %d]\n", cfg->lm_width, cfg->lm_height, prev_lm_width, prev_lm_height); SDE_ERROR("crtc%d:lm left[%d,%d]right[%d %d]\n", crtc->base.id, cfg->lm_width, cfg->lm_height, prev_lm_width, prev_lm_height); SDE_EVT32(DRMID(crtc), cfg->lm_width, cfg->lm_height, prev_lm_width, prev_lm_height, SDE_EVTLOG_ERROR); ret = -EINVAL; goto err; } Loading @@ -2853,22 +2827,40 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, /* Check scaler data */ if (cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE || cfg->flags & SDE_DRM_DESTSCALER_ENHANCER_UPDATE) { if (!cfg->scl3_cfg) { ret = -EINVAL; SDE_ERROR("null scale data\n"); goto err; } if (cfg->scl3_cfg->src_width[0] > max_in_width || cfg->scl3_cfg->dst_width > max_out_width || !cfg->scl3_cfg->src_width[0] || !cfg->scl3_cfg->dst_width) { SDE_ERROR("scale width(%d %d) for ds-%d:\n", cfg->scl3_cfg->src_width[0], cfg->scl3_cfg->dst_width, /** * Scaler src and dst width shouldn't exceed the maximum * width limitation. Also, if there is no partial update * dst width and height must match display resolution. */ if (cfg->scl3_cfg.src_width[0] > max_in_width || cfg->scl3_cfg.dst_width > max_out_width || !cfg->scl3_cfg.src_width[0] || !cfg->scl3_cfg.dst_width || (!(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE) && (cfg->scl3_cfg.dst_width != hdisplay || cfg->scl3_cfg.dst_height != mode->vdisplay))) { SDE_ERROR("crtc%d: ", crtc->base.id); SDE_ERROR("src_w(%d) dst(%dx%d) display(%dx%d)", cfg->scl3_cfg.src_width[0], cfg->scl3_cfg.dst_width, cfg->scl3_cfg.dst_height, hdisplay, mode->vdisplay); SDE_ERROR("num_mixers(%d) flags(%d) ds-%d:\n", sde_crtc->num_mixers, cfg->flags, hw_ds->idx - DS_0); SDE_ERROR("scale_en = %d, DE_en =%d\n", cfg->scl3_cfg->enable, cfg->scl3_cfg->de.enable); cfg->scl3_cfg.enable, cfg->scl3_cfg.de.enable); SDE_EVT32(DRMID(crtc), cfg->scl3_cfg.enable, cfg->scl3_cfg.de.enable, cfg->flags, max_in_width, max_out_width, cfg->scl3_cfg.src_width[0], cfg->scl3_cfg.dst_width, cfg->scl3_cfg.dst_height, hdisplay, mode->vdisplay, sde_crtc->num_mixers, SDE_EVTLOG_ERROR); cfg->flags &= ~SDE_DRM_DESTSCALER_SCALE_UPDATE; Loading @@ -2883,36 +2875,34 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE) num_ds_enable++; /** * Validation successful, indicator for flush to be issued */ cfg->set_lm_flush = true; SDE_DEBUG("ds[%d]: flags = 0x%X\n", SDE_DEBUG("ds[%d]: flags[0x%X]\n", hw_ds->idx - DS_0, cfg->flags); SDE_EVT32_VERBOSE(DRMID(crtc), hw_ds->idx - DS_0, cfg->flags); } disable: SDE_DEBUG("dest scaler enable status, old = %d, new = %d", SDE_DEBUG("dest scaler status : %d -> %d\n", cstate->num_ds_enabled, num_ds_enable); SDE_EVT32(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable, cstate->ds_dirty); SDE_EVT32_VERBOSE(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable, cstate->num_ds, cstate->ds_dirty); if (cstate->num_ds_enabled != num_ds_enable) { /* Disabling destination scaler */ if (!num_ds_enable) { for (i = 0; i < sde_crtc->num_mixers; i++) { for (i = 0; i < cstate->num_ds; i++) { cfg = &cstate->ds_cfg[i]; cfg->ndx = i; cfg->idx = i; /* Update scaler settings in disable case */ cfg->flags = SDE_DRM_DESTSCALER_SCALE_UPDATE; cfg->scl3_cfg->enable = 0; cfg->scl3_cfg->de.enable = 0; cfg->set_lm_flush = true; cfg->scl3_cfg.enable = 0; cfg->scl3_cfg.de.enable = 0; } } cstate->num_ds_enabled = num_ds_enable; cstate->ds_dirty = true; } else { if (!cstate->num_ds_enabled) cstate->ds_dirty = false; } return 0; Loading Loading @@ -3879,6 +3869,9 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) old_cstate, cstate, &cstate->property_state, cstate->property_values); /* clear destination scaler dirty bit */ cstate->ds_dirty = false; /* duplicate base helper */ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); Loading Loading @@ -3945,6 +3938,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) { struct drm_crtc *crtc = arg; struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; struct drm_plane *plane; struct drm_encoder *encoder; struct sde_crtc_mixer *m; Loading @@ -3958,6 +3952,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) return; } sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(crtc->state); mutex_lock(&sde_crtc->crtc_lock); Loading Loading @@ -4046,6 +4041,14 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_plane_set_revalidate(plane, true); sde_cp_crtc_suspend(crtc); /** * destination scaler if enabled should be reconfigured * in the next frame update */ if (cstate->num_ds_enabled) sde_crtc->ds_reconfig = true; break; default: SDE_DEBUG("event:%d not handled\n", event_type); Loading Loading @@ -4091,6 +4094,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc) msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); /* destination scaler if enabled should be reconfigured on resume */ if (cstate->num_ds_enabled) sde_crtc->ds_reconfig = true; /* wait for frame_event_done completion */ if (_sde_crtc_wait_for_frame_done(crtc)) SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", Loading Loading @@ -5742,9 +5749,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) sde_crtc_install_properties(crtc, kms->catalog); /* Init dest scaler */ _sde_crtc_dest_scaler_init(sde_crtc, kms->catalog); /* Install color processing properties */ sde_cp_crtc_init(crtc); sde_cp_crtc_install_properties(crtc); Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +4 −2 Original line number Diff line number Diff line Loading @@ -188,6 +188,7 @@ struct sde_crtc_event { * @enabled : whether the SDE CRTC is currently enabled. updated in the * commit-thread, not state-swap time which is earlier, so * safe to make decisions on during VBLANK on/off work * @ds_reconfig : force reconfiguration of the destination scaler block * @feature_list : list of color processing features supported on a crtc * @active_list : list of color processing features are active * @dirty_list : list of color processing features are dirty Loading Loading @@ -215,7 +216,6 @@ struct sde_crtc_event { * @cur_perf : current performance committed to clock/bandwidth driver * @rp_lock : serialization lock for resource pool * @rp_head : list of active resource pool * @scl3_cfg_lut : qseed3 lut config */ struct sde_crtc { struct drm_crtc base; Loading @@ -226,7 +226,6 @@ struct sde_crtc { u32 num_mixers; bool mixers_swapped; struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS]; struct sde_hw_scaler3_lut_cfg *scl3_lut_cfg; struct drm_pending_vblank_event *event; u32 vsync_count; Loading @@ -248,6 +247,7 @@ struct sde_crtc { bool suspend; bool enabled; bool ds_reconfig; struct list_head feature_list; struct list_head active_list; struct list_head dirty_list; Loading Loading @@ -374,6 +374,7 @@ struct sde_crtc_respool { * @num_ds_enabled: Number of destination scalers enabled * @ds_dirty: Boolean to indicate if dirty or not * @ds_cfg: Destination scaler config * @scl3_lut_cfg: QSEED3 lut config * @new_perf: new performance state being requested * @sbuf_cfg: stream buffer configuration * @sbuf_prefill_line: number of line for inline rotator prefetch Loading Loading @@ -403,6 +404,7 @@ struct sde_crtc_state { uint32_t num_ds_enabled; bool ds_dirty; struct sde_hw_ds_cfg ds_cfg[SDE_MAX_DS_COUNT]; struct sde_hw_scaler3_lut_cfg scl3_lut_cfg; struct sde_core_perf_params new_perf; struct sde_ctl_sbuf_cfg sbuf_cfg; Loading
drivers/gpu/drm/msm/sde/sde_hw_ds.h +4 −6 Original line number Diff line number Diff line Loading @@ -27,20 +27,18 @@ struct sde_hw_ds; #define SDE_DS_OP_MODE_DUAL BIT(16) /* struct sde_hw_ds_cfg - destination scaler config * @ndx : DS selection index * @idx : DS selection index * @flags : Flag to switch between mode for DS * @lm_width : Layer mixer width configuration * @lm_heigh : Layer mixer height configuration * @set_lm_flush : LM flush bit * @scl3_cfg : Pointer to sde_hw_scaler3_cfg. * @scl3_cfg : Configuration data for scaler */ struct sde_hw_ds_cfg { u32 ndx; u32 idx; int flags; u32 lm_width; u32 lm_height; bool set_lm_flush; struct sde_hw_scaler3_cfg *scl3_cfg; struct sde_hw_scaler3_cfg scl3_cfg; }; /** Loading