Loading msm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_qdss.o \ sde_dsc_helper.o \ sde_vdc_helper.o \ sde/sde_hw_rc.o \ msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o \ Loading msm/sde/sde_color_processing.c +185 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ static void dspp_ad_install_property(struct drm_crtc *crtc); static void dspp_ltm_install_property(struct drm_crtc *crtc); static void dspp_rc_install_property(struct drm_crtc *crtc); static void dspp_vlut_install_property(struct drm_crtc *crtc); static void dspp_gamut_install_property(struct drm_crtc *crtc); Loading Loading @@ -112,6 +114,7 @@ do { \ func[SDE_DSPP_IGC] = dspp_igc_install_property; \ func[SDE_DSPP_HIST] = dspp_hist_install_property; \ func[SDE_DSPP_DITHER] = dspp_dither_install_property; \ func[SDE_DSPP_RC] = dspp_rc_install_property; \ } while (0) typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc); Loading Loading @@ -160,6 +163,7 @@ enum sde_cp_crtc_features { SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3, SDE_CP_CRTC_DSPP_LTM_VLUT, SDE_CP_CRTC_DSPP_SB, SDE_CP_CRTC_DSPP_RC_MASK, SDE_CP_CRTC_DSPP_MAX, /* DSPP features end */ Loading @@ -172,11 +176,15 @@ enum sde_cp_crtc_features { }; enum sde_cp_crtc_pu_features { SDE_CP_CRTC_DSPP_RC_PU, SDE_CP_CRTC_MAX_PU_FEATURES, }; static enum sde_cp_crtc_pu_features sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES]; sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES] = { [SDE_CP_CRTC_DSPP_RC_PU] = (enum sde_cp_crtc_pu_features) SDE_CP_CRTC_DSPP_RC_MASK, }; static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc); Loading Loading @@ -672,10 +680,122 @@ static int set_ltm_hist_crtl_feature(struct sde_hw_dspp *hw_dspp, return ret; } static int check_rc_mask_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments"); return -EINVAL; } if (!hw_dspp->ops.validate_rc_mask) { DRM_ERROR("invalid rc ops"); return -EINVAL; } ret = hw_dspp->ops.validate_rc_mask(hw_dspp, hw_cfg); if (ret) DRM_ERROR("failed to validate rc mask %d", ret); return ret; } static int set_rc_mask_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if (!hw_dspp->ops.setup_rc_mask || !hw_dspp->ops.setup_rc_data) { DRM_ERROR("invalid rc ops\n"); return -EINVAL; } DRM_DEBUG_DRIVER("dspp %d setup mask for rc instance %u\n", hw_dspp->idx, hw_dspp->cap->sblk->rc.idx); ret = hw_dspp->ops.setup_rc_mask(hw_dspp, hw_cfg); if (ret) { DRM_ERROR("failed to setup rc mask, ret %d\n", ret); goto exit; } /* rc data should be programmed once if dspp are in multi-pipe mode */ if (hw_dspp->cap->sblk->rc.idx % hw_cfg->num_of_mixers == 0) { ret = hw_dspp->ops.setup_rc_data(hw_dspp, hw_cfg); if (ret) { DRM_ERROR("failed to setup rc data, ret %d\n", ret); goto exit; } } exit: return ret; } static int set_rc_pu_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if (!hw_dspp->ops.setup_rc_pu_roi) { DRM_ERROR("invalid rc ops\n"); return -EINVAL; } DRM_DEBUG_DRIVER("dspp %d setup pu roi for rc instance %u\n", hw_dspp->idx, hw_dspp->cap->sblk->rc.idx); ret = hw_dspp->ops.setup_rc_pu_roi(hw_dspp, hw_cfg); if (ret < 0) DRM_ERROR("failed to setup rc pu roi, ret %d\n", ret); return ret; } static int check_rc_pu_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if (!hw_dspp->ops.validate_rc_pu_roi) { SDE_ERROR("invalid rc ops"); return -EINVAL; } ret = hw_dspp->ops.validate_rc_pu_roi(hw_dspp, hw_cfg); if (ret) SDE_ERROR("failed to validate rc pu roi, ret %d", ret); return ret; } feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; #define setup_check_crtc_feature_wrappers(wrappers) \ memset(wrappers, 0, sizeof(wrappers)) do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = check_rc_mask_feature; \ } while (0) feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; #define setup_set_crtc_feature_wrappers(wrappers) \ Loading Loading @@ -718,15 +838,22 @@ do { \ wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = set_ltm_queue_buf_feature; \ wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = set_ltm_queue_buf_feature; \ wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \ wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = set_rc_mask_feature; \ } while (0) feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES]; #define setup_set_crtc_pu_feature_wrappers(wrappers) \ memset(wrappers, 0, sizeof(wrappers)) do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_RC_PU] = set_rc_pu_feature; \ } while (0) feature_wrapper check_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES]; #define setup_check_crtc_pu_feature_wrappers(wrappers) \ memset(wrappers, 0, sizeof(wrappers)) do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_RC_PU] = check_rc_pu_feature; \ } while (0) #define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \ do { \ Loading Loading @@ -1372,6 +1499,7 @@ static const int dspp_feature_to_sub_blk_tbl[SDE_CP_CRTC_MAX_FEATURES] = { [SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = SDE_DSPP_LTM, [SDE_CP_CRTC_DSPP_LTM_VLUT] = SDE_DSPP_LTM, [SDE_CP_CRTC_DSPP_SB] = SDE_DSPP_SB, [SDE_CP_CRTC_DSPP_RC_MASK] = SDE_DSPP_RC, [SDE_CP_CRTC_DSPP_MAX] = SDE_DSPP_MAX, [SDE_CP_CRTC_LM_GC] = SDE_DSPP_MAX, }; Loading Loading @@ -2391,6 +2519,36 @@ static void dspp_ltm_install_property(struct drm_crtc *crtc) } } static void dspp_rc_install_property(struct drm_crtc *crtc) { char feature_name[256]; struct sde_kms *kms = NULL; struct sde_mdss_cfg *catalog = NULL; u32 version; if (!crtc) { DRM_ERROR("invalid arguments"); return; } kms = get_kms(crtc); catalog = kms->catalog; version = catalog->dspp[0].sblk->rc.version >> 16; switch (version) { case 1: snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", "SDE_DSPP_RC_MASK_V", version); sde_cp_crtc_install_blob_property(crtc, feature_name, SDE_CP_CRTC_DSPP_RC_MASK, sizeof(struct drm_msm_rc_mask_cfg)); break; default: DRM_ERROR("version %d not supported\n", version); break; } } static void lm_gc_install_property(struct drm_crtc *crtc) { char feature_name[256]; Loading Loading @@ -3775,3 +3933,26 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, { return 0; } void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm) { struct sde_cp_node *prop_node = NULL, *n = NULL; struct sde_crtc *crtc; if (!crtc_drm) { DRM_ERROR("invalid crtc handle"); return; } crtc = to_sde_crtc(crtc_drm); mutex_lock(&crtc->crtc_cp_lock); list_for_each_entry_safe(prop_node, n, &crtc->active_list, active_list) { if (prop_node->feature == SDE_CP_CRTC_DSPP_LTM_INIT || prop_node->feature == SDE_CP_CRTC_DSPP_LTM_VLUT) { list_del_init(&prop_node->active_list); list_add_tail(&prop_node->dirty_list, &crtc->dirty_list); } } mutex_unlock(&crtc->crtc_cp_lock); } msm/sde/sde_color_processing.h +6 −0 Original line number Diff line number Diff line Loading @@ -199,4 +199,10 @@ int sde_cp_ltm_wb_pb_interrupt(struct drm_crtc *crtc_drm, bool en, */ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *hist_irq); /** * sde_cp_mode_switch_prop_dirty: API marks mode dependent features as dirty * @crtc_drm: Pointer to crtc. */ void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm); #endif /*_SDE_COLOR_PROCESSING_H */ msm/sde/sde_crtc.c +9 −0 Original line number Diff line number Diff line Loading @@ -429,6 +429,7 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, { SDE_DEBUG("\n"); sde_cp_mode_switch_prop_dirty(crtc); if ((msm_is_mode_seamless(adjusted_mode) || (msm_is_mode_seamless_vrr(adjusted_mode) || msm_is_mode_seamless_dyn_clk(adjusted_mode))) && Loading Loading @@ -755,6 +756,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, } sde_kms_rect_merge_rectangles(&sde_conn_state->rois, &conn_roi); SDE_DEBUG("conn_roi x:%u, y:%u, w:%u, h:%u\n", conn_roi.x, conn_roi.y, conn_roi.w, conn_roi.h); SDE_EVT32_VERBOSE(DRMID(crtc), DRMID(conn), conn_roi.x, conn_roi.y, conn_roi.w, conn_roi.h); Loading Loading @@ -5003,8 +5007,13 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, sde_crtc_install_dest_scale_properties(sde_crtc, catalog, info); if (catalog->dspp_count && catalog->rc_count) sde_kms_info_add_keyint(info, "rc_mem_size", catalog->dspp[0].sblk->rc.mem_total_size); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info, info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO); Loading msm/sde/sde_hw_catalog.c +202 −179 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ /* each entry will have register address and bit offset in that register */ #define MAX_BIT_OFFSET 2 /* max table size for dts property lists, increase if tables grow larger */ #define MAX_SDE_DT_TABLE_SIZE 64 /* default line width for sspp, mixer, ds (input), wb */ #define DEFAULT_SDE_LINE_WIDTH 2048 Loading Loading @@ -380,6 +383,14 @@ enum { LTM_PROP_MAX, }; enum { RC_OFF, RC_LEN, RC_VERSION, RC_MEM_TOTAL_SIZE, RC_PROP_MAX, }; enum { MIXER_OFF, MIXER_LEN, Loading Loading @@ -475,6 +486,20 @@ struct sde_prop_value { u32 bit_value[MAX_SDE_HW_BLK][MAX_BIT_OFFSET]; }; /** * struct sde_dt_props - stores dts properties read from a sde_prop_type table * @exists: Array of bools indicating if the given prop name was present * @counts: Count of the number of valid values for the property * @values: Array storing the count[i] property values * * Must use the sde_[get|put]_dt_props APIs to allocate/free this object. */ struct sde_dt_props { bool exists[MAX_SDE_DT_TABLE_SIZE]; int counts[MAX_SDE_DT_TABLE_SIZE]; struct sde_prop_value *values; }; /************************************************************* * dts property list *************************************************************/ Loading Loading @@ -682,6 +707,13 @@ static struct sde_prop_type ltm_prop[] = { {LTM_VERSION, "qcom,sde-dspp-ltm-version", false, PROP_TYPE_U32}, }; static struct sde_prop_type rc_prop[] = { {RC_OFF, "qcom,sde-dspp-rc-off", false, PROP_TYPE_U32_ARRAY}, {RC_LEN, "qcom,sde-dspp-rc-size", false, PROP_TYPE_U32}, {RC_VERSION, "qcom,sde-dspp-rc-version", false, PROP_TYPE_U32}, {RC_MEM_TOTAL_SIZE, "qcom,sde-dspp-rc-mem-size", false, PROP_TYPE_U32}, }; static struct sde_prop_type ds_top_prop[] = { {DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32}, {DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32}, Loading Loading @@ -912,6 +944,8 @@ static int _validate_dt_entry(struct device_node *np, case PROP_TYPE_U32: rc = of_property_read_u32(np, sde_prop[i].prop_name, &val); if (!rc) prop_count[i] = 1; break; case PROP_TYPE_U32_ARRAY: prop_count[i] = of_property_count_u32_elems(np, Loading @@ -935,6 +969,14 @@ static int _validate_dt_entry(struct device_node *np, if (!snp) rc = -EINVAL; break; case PROP_TYPE_BOOL: /** * No special handling for bool properties here. * They will always exist, with value indicating * if the given key is present or not. */ prop_count[i] = 1; break; default: SDE_DEBUG("invalid property type:%d\n", sde_prop[i].type); Loading Loading @@ -1091,6 +1133,50 @@ static int _read_dt_entry(struct device_node *np, return rc; } static struct sde_dt_props *sde_get_dt_props(struct device_node *np, size_t prop_max, struct sde_prop_type *sde_prop, u32 prop_size, u32 *off_count) { struct sde_dt_props *props; int rc = -ENOMEM; props = kzalloc(sizeof(*props), GFP_KERNEL); if (!props) return ERR_PTR(rc); props->values = kcalloc(prop_max, sizeof(*props->values), GFP_KERNEL); if (!props->values) goto free_props; rc = _validate_dt_entry(np, sde_prop, prop_size, props->counts, off_count); if (rc) goto free_vals; rc = _read_dt_entry(np, sde_prop, prop_size, props->counts, props->exists, props->values); if (rc) goto free_vals; return props; free_vals: kfree(props->values); free_props: kfree(props); return ERR_PTR(rc); } static void sde_put_dt_props(struct sde_dt_props *props) { if (!props) return; kfree(props->values); kfree(props); } static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg, enum sde_intr_hwblk_type blk_type, u32 instance, u32 offset) { Loading Loading @@ -1709,43 +1795,29 @@ static int sde_sspp_parse_dt(struct device_node *np, static int sde_ctl_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[HW_PROP_MAX], i; bool prop_exists[HW_PROP_MAX]; struct sde_prop_value *prop_value = NULL; int i; struct sde_dt_props *props; struct sde_ctl_cfg *ctl; u32 off_count; if (!sde_cfg) { SDE_ERROR("invalid argument input param\n"); rc = -EINVAL; goto end; } prop_value = kzalloc(HW_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; goto end; return -EINVAL; } rc = _validate_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count, &off_count); if (rc) goto end; props = sde_get_dt_props(np, HW_PROP_MAX, ctl_prop, ARRAY_SIZE(ctl_prop), &off_count); if (IS_ERR_OR_NULL(props)) return PTR_ERR(props); sde_cfg->ctl_count = off_count; rc = _read_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count, prop_exists, prop_value); if (rc) goto end; for (i = 0; i < off_count; i++) { const char *disp_pref = NULL; ctl = sde_cfg->ctl + i; ctl->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i); ctl->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0); ctl->base = PROP_VALUE_ACCESS(props->values, HW_OFF, i); ctl->len = PROP_VALUE_ACCESS(props->values, HW_LEN, 0); ctl->id = CTL_0 + i; snprintf(ctl->name, SDE_HW_BLK_NAME_LEN, "ctl_%u", ctl->id - CTL_0); Loading @@ -1766,9 +1838,9 @@ static int sde_ctl_parse_dt(struct device_node *np, SDE_HW_MAJOR(SDE_HW_VER_700)) set_bit(SDE_CTL_UNIFIED_DSPP_FLUSH, &ctl->features); } end: kfree(prop_value); return rc; sde_put_dt_props(props); return 0; } void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, Loading Loading @@ -1840,14 +1912,7 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, static int sde_mixer_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[MIXER_PROP_MAX], i, j; int blocks_prop_count[MIXER_BLOCKS_PROP_MAX]; int blend_prop_count[MIXER_BLEND_PROP_MAX]; bool prop_exists[MIXER_PROP_MAX]; bool blocks_prop_exists[MIXER_BLOCKS_PROP_MAX]; bool blend_prop_exists[MIXER_BLEND_PROP_MAX]; struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL; struct sde_prop_value *blend_prop_value = NULL; int rc = 0, i, j; u32 off_count, blend_off_count, max_blendstages, lm_pair_mask; struct sde_lm_cfg *mixer; struct sde_lm_sub_blks *sblk; Loading @@ -1855,30 +1920,18 @@ static int sde_mixer_parse_dt(struct device_node *np, u32 pp_idx, dspp_idx, ds_idx; u32 mixer_base; struct device_node *snp = NULL; struct sde_dt_props *props, *blend_props, *blocks_props = NULL; if (!sde_cfg) { SDE_ERROR("invalid argument input param\n"); rc = -EINVAL; goto end; return -EINVAL; } max_blendstages = sde_cfg->max_mixer_blendstages; prop_value = kcalloc(MIXER_PROP_MAX, sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; goto end; } rc = _validate_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), prop_count, &off_count); if (rc) goto end; rc = _read_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), prop_count, prop_exists, prop_value); if (rc) goto end; props = sde_get_dt_props(np, MIXER_PROP_MAX, mixer_prop, ARRAY_SIZE(mixer_prop), &off_count); if (IS_ERR_OR_NULL(props)) return PTR_ERR(props); pp_count = sde_cfg->pingpong_count; dspp_count = sde_cfg->dspp_count; Loading @@ -1887,47 +1940,30 @@ static int sde_mixer_parse_dt(struct device_node *np, /* get mixer feature dt properties if they exist */ snp = of_get_child_by_name(np, mixer_prop[MIXER_BLOCKS].prop_name); if (snp) { blocks_prop_value = kzalloc(MIXER_BLOCKS_PROP_MAX * MAX_SDE_HW_BLK * sizeof(struct sde_prop_value), GFP_KERNEL); if (!blocks_prop_value) { rc = -ENOMEM; goto end; blocks_props = sde_get_dt_props(snp, MIXER_PROP_MAX, mixer_blocks_prop, ARRAY_SIZE(mixer_blocks_prop), NULL); if (IS_ERR_OR_NULL(blocks_props)) { rc = PTR_ERR(blocks_props); goto put_props; } rc = _validate_dt_entry(snp, mixer_blocks_prop, ARRAY_SIZE(mixer_blocks_prop), blocks_prop_count, NULL); if (rc) goto end; rc = _read_dt_entry(snp, mixer_blocks_prop, ARRAY_SIZE(mixer_blocks_prop), blocks_prop_count, blocks_prop_exists, blocks_prop_value); } /* get the blend_op register offsets */ blend_prop_value = kzalloc(MIXER_BLEND_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!blend_prop_value) { rc = -ENOMEM; goto end; } rc = _validate_dt_entry(np, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), blend_prop_count, blend_props = sde_get_dt_props(np, MIXER_BLEND_PROP_MAX, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), &blend_off_count); if (rc) goto end; rc = _read_dt_entry(np, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), blend_prop_count, blend_prop_exists, blend_prop_value); if (rc) goto end; if (IS_ERR_OR_NULL(blend_props)) { rc = PTR_ERR(blend_props); goto put_blocks; } for (i = 0, mixer_count = 0, pp_idx = 0, dspp_idx = 0, ds_idx = 0; i < off_count; i++) { const char *disp_pref = NULL; const char *cwb_pref = NULL; mixer_base = PROP_VALUE_ACCESS(prop_value, MIXER_OFF, i); mixer_base = PROP_VALUE_ACCESS(props->values, MIXER_OFF, i); if (!mixer_base) continue; Loading @@ -1942,15 +1978,15 @@ static int sde_mixer_parse_dt(struct device_node *np, mixer->sblk = sblk; mixer->base = mixer_base; mixer->len = PROP_VALUE_ACCESS(prop_value, MIXER_LEN, 0); mixer->len = PROP_VALUE_ACCESS(props->values, MIXER_LEN, 0); mixer->id = LM_0 + i; snprintf(mixer->name, SDE_HW_BLK_NAME_LEN, "lm_%u", mixer->id - LM_0); if (!prop_exists[MIXER_LEN]) if (!props->exists[MIXER_LEN]) mixer->len = DEFAULT_SDE_HW_BLOCK_LEN; lm_pair_mask = PROP_VALUE_ACCESS(prop_value, lm_pair_mask = PROP_VALUE_ACCESS(props->values, MIXER_PAIR_MASK, i); if (lm_pair_mask) mixer->lm_pair_mask = 1 << lm_pair_mask; Loading @@ -1960,7 +1996,7 @@ static int sde_mixer_parse_dt(struct device_node *np, for (j = 0; j < blend_off_count; j++) sblk->blendstage_base[j] = PROP_VALUE_ACCESS(blend_prop_value, PROP_VALUE_ACCESS(blend_props->values, MIXER_BLEND_OP_OFF, j); if (sde_cfg->has_src_split) Loading Loading @@ -1995,11 +2031,11 @@ static int sde_mixer_parse_dt(struct device_node *np, mixer_count++; sblk->gc.id = SDE_MIXER_GC; if (blocks_prop_value && blocks_prop_exists[MIXER_GC_PROP]) { sblk->gc.base = PROP_VALUE_ACCESS(blocks_prop_value, if (blocks_props && blocks_props->exists[MIXER_GC_PROP]) { sblk->gc.base = PROP_VALUE_ACCESS(blocks_props->values, MIXER_GC_PROP, 0); sblk->gc.version = PROP_VALUE_ACCESS(blocks_prop_value, MIXER_GC_PROP, 1); sblk->gc.version = PROP_VALUE_ACCESS( blocks_props->values, MIXER_GC_PROP, 1); sblk->gc.len = 0; set_bit(SDE_MIXER_GC, &mixer->features); } Loading @@ -2007,9 +2043,11 @@ static int sde_mixer_parse_dt(struct device_node *np, sde_cfg->mixer_count = mixer_count; end: kfree(prop_value); kfree(blocks_prop_value); kfree(blend_prop_value); sde_put_dt_props(blend_props); put_blocks: sde_put_dt_props(blocks_props); put_props: sde_put_dt_props(props); return rc; } Loading Loading @@ -2455,102 +2493,66 @@ static int sde_dspp_top_parse_dt(struct device_node *np, static int sde_dspp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[DSPP_PROP_MAX], i; int ad_prop_count[AD_PROP_MAX]; int ltm_prop_count[LTM_PROP_MAX]; bool prop_exists[DSPP_PROP_MAX], ad_prop_exists[AD_PROP_MAX]; bool ltm_prop_exists[LTM_PROP_MAX]; bool blocks_prop_exists[DSPP_BLOCKS_PROP_MAX]; struct sde_prop_value *ad_prop_value = NULL, *ltm_prop_value = NULL; int blocks_prop_count[DSPP_BLOCKS_PROP_MAX]; struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL; u32 off_count, ad_off_count, ltm_off_count; int rc = 0, i; u32 off_count, ad_off_count, ltm_off_count, rc_off_count; struct sde_dt_props *props, *ad_props, *ltm_props, *rc_props; struct sde_dt_props *blocks_props = NULL; struct sde_dspp_cfg *dspp; struct sde_dspp_sub_blks *sblk; struct device_node *snp = NULL; if (!sde_cfg) { SDE_ERROR("invalid argument\n"); rc = -EINVAL; goto end; return -EINVAL; } prop_value = kzalloc(DSPP_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; goto end; } rc = _validate_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), prop_count, &off_count); if (rc) goto end; props = sde_get_dt_props(np, DSPP_PROP_MAX, dspp_prop, ARRAY_SIZE(dspp_prop), &off_count); if (IS_ERR_OR_NULL(props)) return PTR_ERR(props); sde_cfg->dspp_count = off_count; rc = _read_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), prop_count, prop_exists, prop_value); if (rc) goto end; /* Parse AD dtsi entries */ ad_prop_value = kcalloc(AD_PROP_MAX, sizeof(struct sde_prop_value), GFP_KERNEL); if (!ad_prop_value) { rc = -ENOMEM; goto end; ad_props = sde_get_dt_props(np, AD_PROP_MAX, ad_prop, ARRAY_SIZE(ad_prop), &ad_off_count); if (IS_ERR_OR_NULL(ad_props)) { rc = PTR_ERR(ad_props); goto put_props; } rc = _validate_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), ad_prop_count, &ad_off_count); if (rc) goto end; rc = _read_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), ad_prop_count, ad_prop_exists, ad_prop_value); if (rc) goto end; /* Parse LTM dtsi entries */ ltm_prop_value = kcalloc(LTM_PROP_MAX, sizeof(struct sde_prop_value), GFP_KERNEL); if (!ltm_prop_value) { rc = -ENOMEM; goto end; ltm_props = sde_get_dt_props(np, LTM_PROP_MAX, ltm_prop, ARRAY_SIZE(ltm_prop), <m_off_count); if (IS_ERR_OR_NULL(ltm_props)) { rc = PTR_ERR(ltm_props); goto put_ad_props; } /* Parse RC dtsi entries */ rc_props = sde_get_dt_props(np, RC_PROP_MAX, rc_prop, ARRAY_SIZE(rc_prop), &rc_off_count); if (IS_ERR_OR_NULL(rc_props)) { rc = PTR_ERR(rc_props); goto put_ltm_props; } rc = _validate_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), ltm_prop_count, <m_off_count); if (rc) goto end; rc = _read_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), ltm_prop_count, ltm_prop_exists, ltm_prop_value); if (rc) goto end; /* get DSPP feature dt properties if they exist */ snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name); if (snp) { blocks_prop_value = kzalloc(DSPP_BLOCKS_PROP_MAX * MAX_SDE_HW_BLK * sizeof(struct sde_prop_value), GFP_KERNEL); if (!blocks_prop_value) { rc = -ENOMEM; goto end; blocks_props = sde_get_dt_props(snp, DSPP_BLOCKS_PROP_MAX, dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop), NULL); if (IS_ERR_OR_NULL(blocks_props)) { rc = PTR_ERR(blocks_props); goto put_rc_props; } rc = _validate_dt_entry(snp, dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, NULL); if (rc) goto end; rc = _read_dt_entry(snp, dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, blocks_prop_exists, blocks_prop_value); if (rc) goto end; } for (i = 0; i < off_count; i++) { dspp = sde_cfg->dspp + i; dspp->base = PROP_VALUE_ACCESS(prop_value, DSPP_OFF, i); dspp->len = PROP_VALUE_ACCESS(prop_value, DSPP_SIZE, 0); dspp->base = PROP_VALUE_ACCESS(props->values, DSPP_OFF, i); dspp->len = PROP_VALUE_ACCESS(props->values, DSPP_SIZE, 0); dspp->id = DSPP_0 + i; snprintf(dspp->name, SDE_HW_BLK_NAME_LEN, "dspp_%u", dspp->id - DSPP_0); Loading @@ -2563,17 +2565,18 @@ static int sde_dspp_parse_dt(struct device_node *np, } dspp->sblk = sblk; if (blocks_prop_value) if (blocks_props) _sde_dspp_setup_blocks(sde_cfg, dspp, sblk, blocks_prop_exists, blocks_prop_value); blocks_props->exists, blocks_props->values); sblk->ad.id = SDE_DSPP_AD; sde_cfg->ad_count = ad_off_count; if (ad_prop_value && (i < ad_off_count) && ad_prop_exists[AD_OFF]) { sblk->ad.base = PROP_VALUE_ACCESS(ad_prop_value, if (ad_props && (i < ad_off_count) && ad_props->exists[AD_OFF]) { sblk->ad.base = PROP_VALUE_ACCESS(ad_props->values, AD_OFF, i); sblk->ad.version = PROP_VALUE_ACCESS(ad_prop_value, sblk->ad.version = PROP_VALUE_ACCESS(ad_props->values, AD_VERSION, 0); set_bit(SDE_DSPP_AD, &dspp->features); rc = _add_to_irq_offset_list(sde_cfg, Loading @@ -2585,11 +2588,11 @@ static int sde_dspp_parse_dt(struct device_node *np, sblk->ltm.id = SDE_DSPP_LTM; sde_cfg->ltm_count = ltm_off_count; if (ltm_prop_value && (i < ltm_off_count) && ltm_prop_exists[LTM_OFF]) { sblk->ltm.base = PROP_VALUE_ACCESS(ltm_prop_value, if (ltm_props && (i < ltm_off_count) && ltm_props->exists[LTM_OFF]) { sblk->ltm.base = PROP_VALUE_ACCESS(ltm_props->values, LTM_OFF, i); sblk->ltm.version = PROP_VALUE_ACCESS(ltm_prop_value, sblk->ltm.version = PROP_VALUE_ACCESS(ltm_props->values, LTM_VERSION, 0); set_bit(SDE_DSPP_LTM, &dspp->features); rc = _add_to_irq_offset_list(sde_cfg, Loading @@ -2599,13 +2602,34 @@ static int sde_dspp_parse_dt(struct device_node *np, goto end; } sblk->rc.id = SDE_DSPP_RC; sde_cfg->rc_count = rc_off_count; if (rc_props && (i < rc_off_count) && rc_props->exists[RC_OFF]) { sblk->rc.base = PROP_VALUE_ACCESS(rc_props->values, RC_OFF, i); sblk->rc.len = PROP_VALUE_ACCESS(rc_props->values, RC_LEN, 0); sblk->rc.version = PROP_VALUE_ACCESS(rc_props->values, RC_VERSION, 0); sblk->rc.mem_total_size = PROP_VALUE_ACCESS( rc_props->values, RC_MEM_TOTAL_SIZE, 0); sblk->rc.idx = i; set_bit(SDE_DSPP_RC, &dspp->features); } } end: kfree(prop_value); kfree(ad_prop_value); kfree(ltm_prop_value); kfree(blocks_prop_value); sde_put_dt_props(blocks_props); put_rc_props: sde_put_dt_props(rc_props); put_ltm_props: sde_put_dt_props(ltm_props); put_ad_props: sde_put_dt_props(ad_props); put_props: sde_put_dt_props(props); return rc; } Loading Loading @@ -2713,7 +2737,6 @@ static int sde_ds_parse_dt(struct device_node *np, set_bit(SDE_SSPP_SCALER_QSEED3, &ds->features); else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3LITE) set_bit(SDE_SSPP_SCALER_QSEED3LITE, &ds->features); } end: Loading Loading
msm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_qdss.o \ sde_dsc_helper.o \ sde_vdc_helper.o \ sde/sde_hw_rc.o \ msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o \ Loading
msm/sde/sde_color_processing.c +185 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ static void dspp_ad_install_property(struct drm_crtc *crtc); static void dspp_ltm_install_property(struct drm_crtc *crtc); static void dspp_rc_install_property(struct drm_crtc *crtc); static void dspp_vlut_install_property(struct drm_crtc *crtc); static void dspp_gamut_install_property(struct drm_crtc *crtc); Loading Loading @@ -112,6 +114,7 @@ do { \ func[SDE_DSPP_IGC] = dspp_igc_install_property; \ func[SDE_DSPP_HIST] = dspp_hist_install_property; \ func[SDE_DSPP_DITHER] = dspp_dither_install_property; \ func[SDE_DSPP_RC] = dspp_rc_install_property; \ } while (0) typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc); Loading Loading @@ -160,6 +163,7 @@ enum sde_cp_crtc_features { SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3, SDE_CP_CRTC_DSPP_LTM_VLUT, SDE_CP_CRTC_DSPP_SB, SDE_CP_CRTC_DSPP_RC_MASK, SDE_CP_CRTC_DSPP_MAX, /* DSPP features end */ Loading @@ -172,11 +176,15 @@ enum sde_cp_crtc_features { }; enum sde_cp_crtc_pu_features { SDE_CP_CRTC_DSPP_RC_PU, SDE_CP_CRTC_MAX_PU_FEATURES, }; static enum sde_cp_crtc_pu_features sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES]; sde_cp_crtc_pu_to_feature[SDE_CP_CRTC_MAX_PU_FEATURES] = { [SDE_CP_CRTC_DSPP_RC_PU] = (enum sde_cp_crtc_pu_features) SDE_CP_CRTC_DSPP_RC_MASK, }; static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc); Loading Loading @@ -672,10 +680,122 @@ static int set_ltm_hist_crtl_feature(struct sde_hw_dspp *hw_dspp, return ret; } static int check_rc_mask_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments"); return -EINVAL; } if (!hw_dspp->ops.validate_rc_mask) { DRM_ERROR("invalid rc ops"); return -EINVAL; } ret = hw_dspp->ops.validate_rc_mask(hw_dspp, hw_cfg); if (ret) DRM_ERROR("failed to validate rc mask %d", ret); return ret; } static int set_rc_mask_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if (!hw_dspp->ops.setup_rc_mask || !hw_dspp->ops.setup_rc_data) { DRM_ERROR("invalid rc ops\n"); return -EINVAL; } DRM_DEBUG_DRIVER("dspp %d setup mask for rc instance %u\n", hw_dspp->idx, hw_dspp->cap->sblk->rc.idx); ret = hw_dspp->ops.setup_rc_mask(hw_dspp, hw_cfg); if (ret) { DRM_ERROR("failed to setup rc mask, ret %d\n", ret); goto exit; } /* rc data should be programmed once if dspp are in multi-pipe mode */ if (hw_dspp->cap->sblk->rc.idx % hw_cfg->num_of_mixers == 0) { ret = hw_dspp->ops.setup_rc_data(hw_dspp, hw_cfg); if (ret) { DRM_ERROR("failed to setup rc data, ret %d\n", ret); goto exit; } } exit: return ret; } static int set_rc_pu_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if (!hw_dspp->ops.setup_rc_pu_roi) { DRM_ERROR("invalid rc ops\n"); return -EINVAL; } DRM_DEBUG_DRIVER("dspp %d setup pu roi for rc instance %u\n", hw_dspp->idx, hw_dspp->cap->sblk->rc.idx); ret = hw_dspp->ops.setup_rc_pu_roi(hw_dspp, hw_cfg); if (ret < 0) DRM_ERROR("failed to setup rc pu roi, ret %d\n", ret); return ret; } static int check_rc_pu_feature(struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg, struct sde_crtc *sde_crtc) { int ret = 0; if (!hw_dspp || !hw_cfg || !sde_crtc) { DRM_ERROR("invalid arguments\n"); return -EINVAL; } if (!hw_dspp->ops.validate_rc_pu_roi) { SDE_ERROR("invalid rc ops"); return -EINVAL; } ret = hw_dspp->ops.validate_rc_pu_roi(hw_dspp, hw_cfg); if (ret) SDE_ERROR("failed to validate rc pu roi, ret %d", ret); return ret; } feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; #define setup_check_crtc_feature_wrappers(wrappers) \ memset(wrappers, 0, sizeof(wrappers)) do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = check_rc_mask_feature; \ } while (0) feature_wrapper set_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; #define setup_set_crtc_feature_wrappers(wrappers) \ Loading Loading @@ -718,15 +838,22 @@ do { \ wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = set_ltm_queue_buf_feature; \ wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = set_ltm_queue_buf_feature; \ wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \ wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = set_rc_mask_feature; \ } while (0) feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES]; #define setup_set_crtc_pu_feature_wrappers(wrappers) \ memset(wrappers, 0, sizeof(wrappers)) do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_RC_PU] = set_rc_pu_feature; \ } while (0) feature_wrapper check_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES]; #define setup_check_crtc_pu_feature_wrappers(wrappers) \ memset(wrappers, 0, sizeof(wrappers)) do { \ memset(wrappers, 0, sizeof(wrappers)); \ wrappers[SDE_CP_CRTC_DSPP_RC_PU] = check_rc_pu_feature; \ } while (0) #define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \ do { \ Loading Loading @@ -1372,6 +1499,7 @@ static const int dspp_feature_to_sub_blk_tbl[SDE_CP_CRTC_MAX_FEATURES] = { [SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = SDE_DSPP_LTM, [SDE_CP_CRTC_DSPP_LTM_VLUT] = SDE_DSPP_LTM, [SDE_CP_CRTC_DSPP_SB] = SDE_DSPP_SB, [SDE_CP_CRTC_DSPP_RC_MASK] = SDE_DSPP_RC, [SDE_CP_CRTC_DSPP_MAX] = SDE_DSPP_MAX, [SDE_CP_CRTC_LM_GC] = SDE_DSPP_MAX, }; Loading Loading @@ -2391,6 +2519,36 @@ static void dspp_ltm_install_property(struct drm_crtc *crtc) } } static void dspp_rc_install_property(struct drm_crtc *crtc) { char feature_name[256]; struct sde_kms *kms = NULL; struct sde_mdss_cfg *catalog = NULL; u32 version; if (!crtc) { DRM_ERROR("invalid arguments"); return; } kms = get_kms(crtc); catalog = kms->catalog; version = catalog->dspp[0].sblk->rc.version >> 16; switch (version) { case 1: snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", "SDE_DSPP_RC_MASK_V", version); sde_cp_crtc_install_blob_property(crtc, feature_name, SDE_CP_CRTC_DSPP_RC_MASK, sizeof(struct drm_msm_rc_mask_cfg)); break; default: DRM_ERROR("version %d not supported\n", version); break; } } static void lm_gc_install_property(struct drm_crtc *crtc) { char feature_name[256]; Loading Loading @@ -3775,3 +3933,26 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, { return 0; } void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm) { struct sde_cp_node *prop_node = NULL, *n = NULL; struct sde_crtc *crtc; if (!crtc_drm) { DRM_ERROR("invalid crtc handle"); return; } crtc = to_sde_crtc(crtc_drm); mutex_lock(&crtc->crtc_cp_lock); list_for_each_entry_safe(prop_node, n, &crtc->active_list, active_list) { if (prop_node->feature == SDE_CP_CRTC_DSPP_LTM_INIT || prop_node->feature == SDE_CP_CRTC_DSPP_LTM_VLUT) { list_del_init(&prop_node->active_list); list_add_tail(&prop_node->dirty_list, &crtc->dirty_list); } } mutex_unlock(&crtc->crtc_cp_lock); }
msm/sde/sde_color_processing.h +6 −0 Original line number Diff line number Diff line Loading @@ -199,4 +199,10 @@ int sde_cp_ltm_wb_pb_interrupt(struct drm_crtc *crtc_drm, bool en, */ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *hist_irq); /** * sde_cp_mode_switch_prop_dirty: API marks mode dependent features as dirty * @crtc_drm: Pointer to crtc. */ void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm); #endif /*_SDE_COLOR_PROCESSING_H */
msm/sde/sde_crtc.c +9 −0 Original line number Diff line number Diff line Loading @@ -429,6 +429,7 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, { SDE_DEBUG("\n"); sde_cp_mode_switch_prop_dirty(crtc); if ((msm_is_mode_seamless(adjusted_mode) || (msm_is_mode_seamless_vrr(adjusted_mode) || msm_is_mode_seamless_dyn_clk(adjusted_mode))) && Loading Loading @@ -755,6 +756,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, } sde_kms_rect_merge_rectangles(&sde_conn_state->rois, &conn_roi); SDE_DEBUG("conn_roi x:%u, y:%u, w:%u, h:%u\n", conn_roi.x, conn_roi.y, conn_roi.w, conn_roi.h); SDE_EVT32_VERBOSE(DRMID(crtc), DRMID(conn), conn_roi.x, conn_roi.y, conn_roi.w, conn_roi.h); Loading Loading @@ -5003,8 +5007,13 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, sde_crtc_install_dest_scale_properties(sde_crtc, catalog, info); if (catalog->dspp_count && catalog->rc_count) sde_kms_info_add_keyint(info, "rc_mem_size", catalog->dspp[0].sblk->rc.mem_total_size); msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info, info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO); Loading
msm/sde/sde_hw_catalog.c +202 −179 Original line number Diff line number Diff line Loading @@ -32,6 +32,9 @@ /* each entry will have register address and bit offset in that register */ #define MAX_BIT_OFFSET 2 /* max table size for dts property lists, increase if tables grow larger */ #define MAX_SDE_DT_TABLE_SIZE 64 /* default line width for sspp, mixer, ds (input), wb */ #define DEFAULT_SDE_LINE_WIDTH 2048 Loading Loading @@ -380,6 +383,14 @@ enum { LTM_PROP_MAX, }; enum { RC_OFF, RC_LEN, RC_VERSION, RC_MEM_TOTAL_SIZE, RC_PROP_MAX, }; enum { MIXER_OFF, MIXER_LEN, Loading Loading @@ -475,6 +486,20 @@ struct sde_prop_value { u32 bit_value[MAX_SDE_HW_BLK][MAX_BIT_OFFSET]; }; /** * struct sde_dt_props - stores dts properties read from a sde_prop_type table * @exists: Array of bools indicating if the given prop name was present * @counts: Count of the number of valid values for the property * @values: Array storing the count[i] property values * * Must use the sde_[get|put]_dt_props APIs to allocate/free this object. */ struct sde_dt_props { bool exists[MAX_SDE_DT_TABLE_SIZE]; int counts[MAX_SDE_DT_TABLE_SIZE]; struct sde_prop_value *values; }; /************************************************************* * dts property list *************************************************************/ Loading Loading @@ -682,6 +707,13 @@ static struct sde_prop_type ltm_prop[] = { {LTM_VERSION, "qcom,sde-dspp-ltm-version", false, PROP_TYPE_U32}, }; static struct sde_prop_type rc_prop[] = { {RC_OFF, "qcom,sde-dspp-rc-off", false, PROP_TYPE_U32_ARRAY}, {RC_LEN, "qcom,sde-dspp-rc-size", false, PROP_TYPE_U32}, {RC_VERSION, "qcom,sde-dspp-rc-version", false, PROP_TYPE_U32}, {RC_MEM_TOTAL_SIZE, "qcom,sde-dspp-rc-mem-size", false, PROP_TYPE_U32}, }; static struct sde_prop_type ds_top_prop[] = { {DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32}, {DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32}, Loading Loading @@ -912,6 +944,8 @@ static int _validate_dt_entry(struct device_node *np, case PROP_TYPE_U32: rc = of_property_read_u32(np, sde_prop[i].prop_name, &val); if (!rc) prop_count[i] = 1; break; case PROP_TYPE_U32_ARRAY: prop_count[i] = of_property_count_u32_elems(np, Loading @@ -935,6 +969,14 @@ static int _validate_dt_entry(struct device_node *np, if (!snp) rc = -EINVAL; break; case PROP_TYPE_BOOL: /** * No special handling for bool properties here. * They will always exist, with value indicating * if the given key is present or not. */ prop_count[i] = 1; break; default: SDE_DEBUG("invalid property type:%d\n", sde_prop[i].type); Loading Loading @@ -1091,6 +1133,50 @@ static int _read_dt_entry(struct device_node *np, return rc; } static struct sde_dt_props *sde_get_dt_props(struct device_node *np, size_t prop_max, struct sde_prop_type *sde_prop, u32 prop_size, u32 *off_count) { struct sde_dt_props *props; int rc = -ENOMEM; props = kzalloc(sizeof(*props), GFP_KERNEL); if (!props) return ERR_PTR(rc); props->values = kcalloc(prop_max, sizeof(*props->values), GFP_KERNEL); if (!props->values) goto free_props; rc = _validate_dt_entry(np, sde_prop, prop_size, props->counts, off_count); if (rc) goto free_vals; rc = _read_dt_entry(np, sde_prop, prop_size, props->counts, props->exists, props->values); if (rc) goto free_vals; return props; free_vals: kfree(props->values); free_props: kfree(props); return ERR_PTR(rc); } static void sde_put_dt_props(struct sde_dt_props *props) { if (!props) return; kfree(props->values); kfree(props); } static int _add_to_irq_offset_list(struct sde_mdss_cfg *sde_cfg, enum sde_intr_hwblk_type blk_type, u32 instance, u32 offset) { Loading Loading @@ -1709,43 +1795,29 @@ static int sde_sspp_parse_dt(struct device_node *np, static int sde_ctl_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[HW_PROP_MAX], i; bool prop_exists[HW_PROP_MAX]; struct sde_prop_value *prop_value = NULL; int i; struct sde_dt_props *props; struct sde_ctl_cfg *ctl; u32 off_count; if (!sde_cfg) { SDE_ERROR("invalid argument input param\n"); rc = -EINVAL; goto end; } prop_value = kzalloc(HW_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; goto end; return -EINVAL; } rc = _validate_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count, &off_count); if (rc) goto end; props = sde_get_dt_props(np, HW_PROP_MAX, ctl_prop, ARRAY_SIZE(ctl_prop), &off_count); if (IS_ERR_OR_NULL(props)) return PTR_ERR(props); sde_cfg->ctl_count = off_count; rc = _read_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count, prop_exists, prop_value); if (rc) goto end; for (i = 0; i < off_count; i++) { const char *disp_pref = NULL; ctl = sde_cfg->ctl + i; ctl->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i); ctl->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0); ctl->base = PROP_VALUE_ACCESS(props->values, HW_OFF, i); ctl->len = PROP_VALUE_ACCESS(props->values, HW_LEN, 0); ctl->id = CTL_0 + i; snprintf(ctl->name, SDE_HW_BLK_NAME_LEN, "ctl_%u", ctl->id - CTL_0); Loading @@ -1766,9 +1838,9 @@ static int sde_ctl_parse_dt(struct device_node *np, SDE_HW_MAJOR(SDE_HW_VER_700)) set_bit(SDE_CTL_UNIFIED_DSPP_FLUSH, &ctl->features); } end: kfree(prop_value); return rc; sde_put_dt_props(props); return 0; } void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, Loading Loading @@ -1840,14 +1912,7 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, static int sde_mixer_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[MIXER_PROP_MAX], i, j; int blocks_prop_count[MIXER_BLOCKS_PROP_MAX]; int blend_prop_count[MIXER_BLEND_PROP_MAX]; bool prop_exists[MIXER_PROP_MAX]; bool blocks_prop_exists[MIXER_BLOCKS_PROP_MAX]; bool blend_prop_exists[MIXER_BLEND_PROP_MAX]; struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL; struct sde_prop_value *blend_prop_value = NULL; int rc = 0, i, j; u32 off_count, blend_off_count, max_blendstages, lm_pair_mask; struct sde_lm_cfg *mixer; struct sde_lm_sub_blks *sblk; Loading @@ -1855,30 +1920,18 @@ static int sde_mixer_parse_dt(struct device_node *np, u32 pp_idx, dspp_idx, ds_idx; u32 mixer_base; struct device_node *snp = NULL; struct sde_dt_props *props, *blend_props, *blocks_props = NULL; if (!sde_cfg) { SDE_ERROR("invalid argument input param\n"); rc = -EINVAL; goto end; return -EINVAL; } max_blendstages = sde_cfg->max_mixer_blendstages; prop_value = kcalloc(MIXER_PROP_MAX, sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; goto end; } rc = _validate_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), prop_count, &off_count); if (rc) goto end; rc = _read_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), prop_count, prop_exists, prop_value); if (rc) goto end; props = sde_get_dt_props(np, MIXER_PROP_MAX, mixer_prop, ARRAY_SIZE(mixer_prop), &off_count); if (IS_ERR_OR_NULL(props)) return PTR_ERR(props); pp_count = sde_cfg->pingpong_count; dspp_count = sde_cfg->dspp_count; Loading @@ -1887,47 +1940,30 @@ static int sde_mixer_parse_dt(struct device_node *np, /* get mixer feature dt properties if they exist */ snp = of_get_child_by_name(np, mixer_prop[MIXER_BLOCKS].prop_name); if (snp) { blocks_prop_value = kzalloc(MIXER_BLOCKS_PROP_MAX * MAX_SDE_HW_BLK * sizeof(struct sde_prop_value), GFP_KERNEL); if (!blocks_prop_value) { rc = -ENOMEM; goto end; blocks_props = sde_get_dt_props(snp, MIXER_PROP_MAX, mixer_blocks_prop, ARRAY_SIZE(mixer_blocks_prop), NULL); if (IS_ERR_OR_NULL(blocks_props)) { rc = PTR_ERR(blocks_props); goto put_props; } rc = _validate_dt_entry(snp, mixer_blocks_prop, ARRAY_SIZE(mixer_blocks_prop), blocks_prop_count, NULL); if (rc) goto end; rc = _read_dt_entry(snp, mixer_blocks_prop, ARRAY_SIZE(mixer_blocks_prop), blocks_prop_count, blocks_prop_exists, blocks_prop_value); } /* get the blend_op register offsets */ blend_prop_value = kzalloc(MIXER_BLEND_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!blend_prop_value) { rc = -ENOMEM; goto end; } rc = _validate_dt_entry(np, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), blend_prop_count, blend_props = sde_get_dt_props(np, MIXER_BLEND_PROP_MAX, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), &blend_off_count); if (rc) goto end; rc = _read_dt_entry(np, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), blend_prop_count, blend_prop_exists, blend_prop_value); if (rc) goto end; if (IS_ERR_OR_NULL(blend_props)) { rc = PTR_ERR(blend_props); goto put_blocks; } for (i = 0, mixer_count = 0, pp_idx = 0, dspp_idx = 0, ds_idx = 0; i < off_count; i++) { const char *disp_pref = NULL; const char *cwb_pref = NULL; mixer_base = PROP_VALUE_ACCESS(prop_value, MIXER_OFF, i); mixer_base = PROP_VALUE_ACCESS(props->values, MIXER_OFF, i); if (!mixer_base) continue; Loading @@ -1942,15 +1978,15 @@ static int sde_mixer_parse_dt(struct device_node *np, mixer->sblk = sblk; mixer->base = mixer_base; mixer->len = PROP_VALUE_ACCESS(prop_value, MIXER_LEN, 0); mixer->len = PROP_VALUE_ACCESS(props->values, MIXER_LEN, 0); mixer->id = LM_0 + i; snprintf(mixer->name, SDE_HW_BLK_NAME_LEN, "lm_%u", mixer->id - LM_0); if (!prop_exists[MIXER_LEN]) if (!props->exists[MIXER_LEN]) mixer->len = DEFAULT_SDE_HW_BLOCK_LEN; lm_pair_mask = PROP_VALUE_ACCESS(prop_value, lm_pair_mask = PROP_VALUE_ACCESS(props->values, MIXER_PAIR_MASK, i); if (lm_pair_mask) mixer->lm_pair_mask = 1 << lm_pair_mask; Loading @@ -1960,7 +1996,7 @@ static int sde_mixer_parse_dt(struct device_node *np, for (j = 0; j < blend_off_count; j++) sblk->blendstage_base[j] = PROP_VALUE_ACCESS(blend_prop_value, PROP_VALUE_ACCESS(blend_props->values, MIXER_BLEND_OP_OFF, j); if (sde_cfg->has_src_split) Loading Loading @@ -1995,11 +2031,11 @@ static int sde_mixer_parse_dt(struct device_node *np, mixer_count++; sblk->gc.id = SDE_MIXER_GC; if (blocks_prop_value && blocks_prop_exists[MIXER_GC_PROP]) { sblk->gc.base = PROP_VALUE_ACCESS(blocks_prop_value, if (blocks_props && blocks_props->exists[MIXER_GC_PROP]) { sblk->gc.base = PROP_VALUE_ACCESS(blocks_props->values, MIXER_GC_PROP, 0); sblk->gc.version = PROP_VALUE_ACCESS(blocks_prop_value, MIXER_GC_PROP, 1); sblk->gc.version = PROP_VALUE_ACCESS( blocks_props->values, MIXER_GC_PROP, 1); sblk->gc.len = 0; set_bit(SDE_MIXER_GC, &mixer->features); } Loading @@ -2007,9 +2043,11 @@ static int sde_mixer_parse_dt(struct device_node *np, sde_cfg->mixer_count = mixer_count; end: kfree(prop_value); kfree(blocks_prop_value); kfree(blend_prop_value); sde_put_dt_props(blend_props); put_blocks: sde_put_dt_props(blocks_props); put_props: sde_put_dt_props(props); return rc; } Loading Loading @@ -2455,102 +2493,66 @@ static int sde_dspp_top_parse_dt(struct device_node *np, static int sde_dspp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { int rc, prop_count[DSPP_PROP_MAX], i; int ad_prop_count[AD_PROP_MAX]; int ltm_prop_count[LTM_PROP_MAX]; bool prop_exists[DSPP_PROP_MAX], ad_prop_exists[AD_PROP_MAX]; bool ltm_prop_exists[LTM_PROP_MAX]; bool blocks_prop_exists[DSPP_BLOCKS_PROP_MAX]; struct sde_prop_value *ad_prop_value = NULL, *ltm_prop_value = NULL; int blocks_prop_count[DSPP_BLOCKS_PROP_MAX]; struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL; u32 off_count, ad_off_count, ltm_off_count; int rc = 0, i; u32 off_count, ad_off_count, ltm_off_count, rc_off_count; struct sde_dt_props *props, *ad_props, *ltm_props, *rc_props; struct sde_dt_props *blocks_props = NULL; struct sde_dspp_cfg *dspp; struct sde_dspp_sub_blks *sblk; struct device_node *snp = NULL; if (!sde_cfg) { SDE_ERROR("invalid argument\n"); rc = -EINVAL; goto end; return -EINVAL; } prop_value = kzalloc(DSPP_PROP_MAX * sizeof(struct sde_prop_value), GFP_KERNEL); if (!prop_value) { rc = -ENOMEM; goto end; } rc = _validate_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), prop_count, &off_count); if (rc) goto end; props = sde_get_dt_props(np, DSPP_PROP_MAX, dspp_prop, ARRAY_SIZE(dspp_prop), &off_count); if (IS_ERR_OR_NULL(props)) return PTR_ERR(props); sde_cfg->dspp_count = off_count; rc = _read_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), prop_count, prop_exists, prop_value); if (rc) goto end; /* Parse AD dtsi entries */ ad_prop_value = kcalloc(AD_PROP_MAX, sizeof(struct sde_prop_value), GFP_KERNEL); if (!ad_prop_value) { rc = -ENOMEM; goto end; ad_props = sde_get_dt_props(np, AD_PROP_MAX, ad_prop, ARRAY_SIZE(ad_prop), &ad_off_count); if (IS_ERR_OR_NULL(ad_props)) { rc = PTR_ERR(ad_props); goto put_props; } rc = _validate_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), ad_prop_count, &ad_off_count); if (rc) goto end; rc = _read_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), ad_prop_count, ad_prop_exists, ad_prop_value); if (rc) goto end; /* Parse LTM dtsi entries */ ltm_prop_value = kcalloc(LTM_PROP_MAX, sizeof(struct sde_prop_value), GFP_KERNEL); if (!ltm_prop_value) { rc = -ENOMEM; goto end; ltm_props = sde_get_dt_props(np, LTM_PROP_MAX, ltm_prop, ARRAY_SIZE(ltm_prop), <m_off_count); if (IS_ERR_OR_NULL(ltm_props)) { rc = PTR_ERR(ltm_props); goto put_ad_props; } /* Parse RC dtsi entries */ rc_props = sde_get_dt_props(np, RC_PROP_MAX, rc_prop, ARRAY_SIZE(rc_prop), &rc_off_count); if (IS_ERR_OR_NULL(rc_props)) { rc = PTR_ERR(rc_props); goto put_ltm_props; } rc = _validate_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), ltm_prop_count, <m_off_count); if (rc) goto end; rc = _read_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), ltm_prop_count, ltm_prop_exists, ltm_prop_value); if (rc) goto end; /* get DSPP feature dt properties if they exist */ snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name); if (snp) { blocks_prop_value = kzalloc(DSPP_BLOCKS_PROP_MAX * MAX_SDE_HW_BLK * sizeof(struct sde_prop_value), GFP_KERNEL); if (!blocks_prop_value) { rc = -ENOMEM; goto end; blocks_props = sde_get_dt_props(snp, DSPP_BLOCKS_PROP_MAX, dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop), NULL); if (IS_ERR_OR_NULL(blocks_props)) { rc = PTR_ERR(blocks_props); goto put_rc_props; } rc = _validate_dt_entry(snp, dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, NULL); if (rc) goto end; rc = _read_dt_entry(snp, dspp_blocks_prop, ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, blocks_prop_exists, blocks_prop_value); if (rc) goto end; } for (i = 0; i < off_count; i++) { dspp = sde_cfg->dspp + i; dspp->base = PROP_VALUE_ACCESS(prop_value, DSPP_OFF, i); dspp->len = PROP_VALUE_ACCESS(prop_value, DSPP_SIZE, 0); dspp->base = PROP_VALUE_ACCESS(props->values, DSPP_OFF, i); dspp->len = PROP_VALUE_ACCESS(props->values, DSPP_SIZE, 0); dspp->id = DSPP_0 + i; snprintf(dspp->name, SDE_HW_BLK_NAME_LEN, "dspp_%u", dspp->id - DSPP_0); Loading @@ -2563,17 +2565,18 @@ static int sde_dspp_parse_dt(struct device_node *np, } dspp->sblk = sblk; if (blocks_prop_value) if (blocks_props) _sde_dspp_setup_blocks(sde_cfg, dspp, sblk, blocks_prop_exists, blocks_prop_value); blocks_props->exists, blocks_props->values); sblk->ad.id = SDE_DSPP_AD; sde_cfg->ad_count = ad_off_count; if (ad_prop_value && (i < ad_off_count) && ad_prop_exists[AD_OFF]) { sblk->ad.base = PROP_VALUE_ACCESS(ad_prop_value, if (ad_props && (i < ad_off_count) && ad_props->exists[AD_OFF]) { sblk->ad.base = PROP_VALUE_ACCESS(ad_props->values, AD_OFF, i); sblk->ad.version = PROP_VALUE_ACCESS(ad_prop_value, sblk->ad.version = PROP_VALUE_ACCESS(ad_props->values, AD_VERSION, 0); set_bit(SDE_DSPP_AD, &dspp->features); rc = _add_to_irq_offset_list(sde_cfg, Loading @@ -2585,11 +2588,11 @@ static int sde_dspp_parse_dt(struct device_node *np, sblk->ltm.id = SDE_DSPP_LTM; sde_cfg->ltm_count = ltm_off_count; if (ltm_prop_value && (i < ltm_off_count) && ltm_prop_exists[LTM_OFF]) { sblk->ltm.base = PROP_VALUE_ACCESS(ltm_prop_value, if (ltm_props && (i < ltm_off_count) && ltm_props->exists[LTM_OFF]) { sblk->ltm.base = PROP_VALUE_ACCESS(ltm_props->values, LTM_OFF, i); sblk->ltm.version = PROP_VALUE_ACCESS(ltm_prop_value, sblk->ltm.version = PROP_VALUE_ACCESS(ltm_props->values, LTM_VERSION, 0); set_bit(SDE_DSPP_LTM, &dspp->features); rc = _add_to_irq_offset_list(sde_cfg, Loading @@ -2599,13 +2602,34 @@ static int sde_dspp_parse_dt(struct device_node *np, goto end; } sblk->rc.id = SDE_DSPP_RC; sde_cfg->rc_count = rc_off_count; if (rc_props && (i < rc_off_count) && rc_props->exists[RC_OFF]) { sblk->rc.base = PROP_VALUE_ACCESS(rc_props->values, RC_OFF, i); sblk->rc.len = PROP_VALUE_ACCESS(rc_props->values, RC_LEN, 0); sblk->rc.version = PROP_VALUE_ACCESS(rc_props->values, RC_VERSION, 0); sblk->rc.mem_total_size = PROP_VALUE_ACCESS( rc_props->values, RC_MEM_TOTAL_SIZE, 0); sblk->rc.idx = i; set_bit(SDE_DSPP_RC, &dspp->features); } } end: kfree(prop_value); kfree(ad_prop_value); kfree(ltm_prop_value); kfree(blocks_prop_value); sde_put_dt_props(blocks_props); put_rc_props: sde_put_dt_props(rc_props); put_ltm_props: sde_put_dt_props(ltm_props); put_ad_props: sde_put_dt_props(ad_props); put_props: sde_put_dt_props(props); return rc; } Loading Loading @@ -2713,7 +2737,6 @@ static int sde_ds_parse_dt(struct device_node *np, set_bit(SDE_SSPP_SCALER_QSEED3, &ds->features); else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3LITE) set_bit(SDE_SSPP_SCALER_QSEED3LITE, &ds->features); } end: Loading