339 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.3 */4 5#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__6 7#include <linux/debugfs.h>8#include <linux/delay.h>9 10#include "dpu_vbif.h"11#include "dpu_hw_vbif.h"12#include "dpu_trace.h"13 14static struct dpu_hw_vbif *dpu_get_vbif(struct dpu_kms *dpu_kms, enum dpu_vbif vbif_idx)15{16 if (vbif_idx < ARRAY_SIZE(dpu_kms->hw_vbif))17 return dpu_kms->hw_vbif[vbif_idx];18 19 return NULL;20}21 22static const char *dpu_vbif_name(enum dpu_vbif idx)23{24 switch (idx) {25 case VBIF_RT:26 return "VBIF_RT";27 case VBIF_NRT:28 return "VBIF_NRT";29 default:30 return "??";31 }32}33 34/**35 * _dpu_vbif_wait_for_xin_halt - wait for the xin to halt36 * @vbif: Pointer to hardware vbif driver37 * @xin_id: Client interface identifier38 * @return: 0 if success; error code otherwise39 */40static int _dpu_vbif_wait_for_xin_halt(struct dpu_hw_vbif *vbif, u32 xin_id)41{42 ktime_t timeout;43 bool status;44 int rc;45 46 if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) {47 DPU_ERROR("invalid arguments vbif %d\n", vbif != NULL);48 return -EINVAL;49 }50 51 timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout);52 for (;;) {53 status = vbif->ops.get_halt_ctrl(vbif, xin_id);54 if (status)55 break;56 if (ktime_compare_safe(ktime_get(), timeout) > 0) {57 status = vbif->ops.get_halt_ctrl(vbif, xin_id);58 break;59 }60 usleep_range(501, 1000);61 }62 63 if (!status) {64 rc = -ETIMEDOUT;65 DPU_ERROR("%s client %d not halting. TIMEDOUT.\n",66 dpu_vbif_name(vbif->idx), xin_id);67 } else {68 rc = 0;69 DRM_DEBUG_ATOMIC("%s client %d is halted\n",70 dpu_vbif_name(vbif->idx), xin_id);71 }72 73 return rc;74}75 76/**77 * _dpu_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters78 * @vbif: Pointer to hardware vbif driver79 * @ot_lim: Pointer to OT limit to be modified80 * @params: Pointer to usecase parameters81 */82static void _dpu_vbif_apply_dynamic_ot_limit(struct dpu_hw_vbif *vbif,83 u32 *ot_lim, struct dpu_vbif_set_ot_params *params)84{85 u64 pps;86 const struct dpu_vbif_dynamic_ot_tbl *tbl;87 u32 i;88 89 if (!vbif || !(vbif->cap->features & BIT(DPU_VBIF_QOS_OTLIM)))90 return;91 92 /* Dynamic OT setting done only for WFD */93 if (!params->is_wfd)94 return;95 96 pps = params->frame_rate;97 pps *= params->width;98 pps *= params->height;99 100 tbl = params->rd ? &vbif->cap->dynamic_ot_rd_tbl :101 &vbif->cap->dynamic_ot_wr_tbl;102 103 for (i = 0; i < tbl->count; i++) {104 if (pps <= tbl->cfg[i].pps) {105 *ot_lim = tbl->cfg[i].ot_limit;106 break;107 }108 }109 110 DRM_DEBUG_ATOMIC("%s xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n",111 dpu_vbif_name(vbif->idx), params->xin_id,112 params->width, params->height, params->frame_rate,113 pps, *ot_lim);114}115 116/**117 * _dpu_vbif_get_ot_limit - get OT based on usecase & configuration parameters118 * @vbif: Pointer to hardware vbif driver119 * @params: Pointer to usecase parameters120 * @return: OT limit121 */122static u32 _dpu_vbif_get_ot_limit(struct dpu_hw_vbif *vbif,123 struct dpu_vbif_set_ot_params *params)124{125 u32 ot_lim = 0;126 u32 val;127 128 if (!vbif || !vbif->cap) {129 DPU_ERROR("invalid arguments vbif %d\n", vbif != NULL);130 return -EINVAL;131 }132 133 if (vbif->cap->default_ot_wr_limit && !params->rd)134 ot_lim = vbif->cap->default_ot_wr_limit;135 else if (vbif->cap->default_ot_rd_limit && params->rd)136 ot_lim = vbif->cap->default_ot_rd_limit;137 138 /*139 * If default ot is not set from dt/catalog,140 * then do not configure it.141 */142 if (ot_lim == 0)143 goto exit;144 145 /* Modify the limits if the target and the use case requires it */146 _dpu_vbif_apply_dynamic_ot_limit(vbif, &ot_lim, params);147 148 if (vbif && vbif->ops.get_limit_conf) {149 val = vbif->ops.get_limit_conf(vbif,150 params->xin_id, params->rd);151 if (val == ot_lim)152 ot_lim = 0;153 }154 155exit:156 DRM_DEBUG_ATOMIC("%s xin:%d ot_lim:%d\n",157 dpu_vbif_name(vbif->idx), params->xin_id, ot_lim);158 return ot_lim;159}160 161/**162 * dpu_vbif_set_ot_limit - set OT based on usecase & configuration parameters163 * @dpu_kms: DPU handler164 * @params: Pointer to usecase parameters165 *166 * Note this function would block waiting for bus halt.167 */168void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms,169 struct dpu_vbif_set_ot_params *params)170{171 struct dpu_hw_vbif *vbif;172 u32 ot_lim;173 int ret;174 175 vbif = dpu_get_vbif(dpu_kms, params->vbif_idx);176 if (!vbif) {177 DRM_DEBUG_ATOMIC("invalid arguments vbif %d\n", vbif != NULL);178 return;179 }180 181 if (!vbif->ops.set_limit_conf || !vbif->ops.set_halt_ctrl)182 return;183 184 /* set write_gather_en for all write clients */185 if (vbif->ops.set_write_gather_en && !params->rd)186 vbif->ops.set_write_gather_en(vbif, params->xin_id);187 188 ot_lim = _dpu_vbif_get_ot_limit(vbif, params) & 0xFF;189 190 if (ot_lim == 0)191 return;192 193 trace_dpu_perf_set_ot(params->num, params->xin_id, ot_lim,194 params->vbif_idx);195 196 vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim);197 198 vbif->ops.set_halt_ctrl(vbif, params->xin_id, true);199 200 ret = _dpu_vbif_wait_for_xin_halt(vbif, params->xin_id);201 if (ret)202 trace_dpu_vbif_wait_xin_halt_fail(vbif->idx, params->xin_id);203 204 vbif->ops.set_halt_ctrl(vbif, params->xin_id, false);205}206 207void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms,208 struct dpu_vbif_set_qos_params *params)209{210 struct dpu_hw_vbif *vbif;211 const struct dpu_vbif_qos_tbl *qos_tbl;212 int i;213 214 if (!params) {215 DPU_ERROR("invalid arguments\n");216 return;217 }218 219 vbif = dpu_get_vbif(dpu_kms, params->vbif_idx);220 221 if (!vbif || !vbif->cap) {222 DPU_ERROR("invalid vbif %d\n", params->vbif_idx);223 return;224 }225 226 if (!vbif->ops.set_qos_remap) {227 DRM_DEBUG_ATOMIC("qos remap not supported\n");228 return;229 }230 231 qos_tbl = params->is_rt ? &vbif->cap->qos_rt_tbl :232 &vbif->cap->qos_nrt_tbl;233 234 if (!qos_tbl->npriority_lvl || !qos_tbl->priority_lvl) {235 DRM_DEBUG_ATOMIC("qos tbl not defined\n");236 return;237 }238 239 for (i = 0; i < qos_tbl->npriority_lvl; i++) {240 DRM_DEBUG_ATOMIC("%s xin:%d lvl:%d/%d\n",241 dpu_vbif_name(params->vbif_idx), params->xin_id, i,242 qos_tbl->priority_lvl[i]);243 vbif->ops.set_qos_remap(vbif, params->xin_id, i,244 qos_tbl->priority_lvl[i]);245 }246}247 248void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms)249{250 struct dpu_hw_vbif *vbif;251 u32 i, pnd, src;252 253 for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {254 vbif = dpu_kms->hw_vbif[i];255 if (vbif && vbif->ops.clear_errors) {256 vbif->ops.clear_errors(vbif, &pnd, &src);257 if (pnd || src) {258 DRM_DEBUG_KMS("%s: pnd 0x%X, src 0x%X\n",259 dpu_vbif_name(vbif->idx), pnd, src);260 }261 }262 }263}264 265void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms)266{267 struct dpu_hw_vbif *vbif;268 int i, j;269 270 for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) {271 vbif = dpu_kms->hw_vbif[i];272 if (vbif && vbif->cap && vbif->ops.set_mem_type) {273 for (j = 0; j < vbif->cap->memtype_count; j++)274 vbif->ops.set_mem_type(275 vbif, j, vbif->cap->memtype[j]);276 }277 }278}279 280#ifdef CONFIG_DEBUG_FS281 282void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root)283{284 char vbif_name[32];285 struct dentry *entry, *debugfs_vbif;286 int i, j;287 288 entry = debugfs_create_dir("vbif", debugfs_root);289 290 for (i = 0; i < dpu_kms->catalog->vbif_count; i++) {291 const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i];292 293 snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id);294 295 debugfs_vbif = debugfs_create_dir(vbif_name, entry);296 297 debugfs_create_u32("features", 0600, debugfs_vbif,298 (u32 *)&vbif->features);299 300 debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif,301 (u32 *)&vbif->xin_halt_timeout);302 303 debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif,304 (u32 *)&vbif->default_ot_rd_limit);305 306 debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif,307 (u32 *)&vbif->default_ot_wr_limit);308 309 for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) {310 const struct dpu_vbif_dynamic_ot_cfg *cfg =311 &vbif->dynamic_ot_rd_tbl.cfg[j];312 313 snprintf(vbif_name, sizeof(vbif_name),314 "dynamic_ot_rd_%d_pps", j);315 debugfs_create_u64(vbif_name, 0400, debugfs_vbif,316 (u64 *)&cfg->pps);317 snprintf(vbif_name, sizeof(vbif_name),318 "dynamic_ot_rd_%d_ot_limit", j);319 debugfs_create_u32(vbif_name, 0400, debugfs_vbif,320 (u32 *)&cfg->ot_limit);321 }322 323 for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) {324 const struct dpu_vbif_dynamic_ot_cfg *cfg =325 &vbif->dynamic_ot_wr_tbl.cfg[j];326 327 snprintf(vbif_name, sizeof(vbif_name),328 "dynamic_ot_wr_%d_pps", j);329 debugfs_create_u64(vbif_name, 0400, debugfs_vbif,330 (u64 *)&cfg->pps);331 snprintf(vbif_name, sizeof(vbif_name),332 "dynamic_ot_wr_%d_ot_limit", j);333 debugfs_create_u32(vbif_name, 0400, debugfs_vbif,334 (u32 *)&cfg->ot_limit);335 }336 }337}338#endif339